2012-06-29 14 views
11

Sto scrivendo un'app per Android in OpenCV per rilevare i BLOB. Un compito è quello di sormontare l'immagine per differenziare gli oggetti in primo piano dallo sfondo (vedi immagine).Come ottenere il valore di soglia dall'istogramma?

Funziona correttamente finché l'immagine è nota e posso passare manualmente un valore di soglia a threshold() - in questa immagine specifica, 200. Ma assumendo che l'immagine non sia nota con la sola conoscenza che sarebbe uno sfondo scuro scuro e oggetti in primo piano più chiari come posso calcolare dinamicamente il valore di soglia?

Mi sono imbattuto nell'istogramma in cui è possibile calcolare la distribuzione dell'intensità dell'immagine in scala di grigi. Ma non sono riuscito a trovare un metodo per analizzare l'istogramma e scegliere il valore in cui si trova l'oggetto di interesse (più leggero). Questo è; Voglio differenziare i picchi di sfondo chiaramente scuri dai picchi più chiari in primo piano - in questo caso sopra i 200, ma in un altro caso si potrebbe dire, 100 se gli oggetti sono grigiosi.

enter image description here

+4

C'è un sacco di metodi per questo. Forse il Metodo di Otsu potrebbe funzionare per te. Se non è ancora un buon punto di partenza, IMHO. http://en.wikipedia.org/wiki/Otsu%27s_Method – Florian

+0

Puoi caricare un'immagine in cui 100 soglia è buona? Perché sull'immagine sopra la soglia 50 è anche accettabile ... – ArtemStorozhuk

risposta

9

Se tutte le immagini sono così o possono essere portate a questo stile, credo che cv2.THRESHOLD_OTSU, ovvero l'algoritmo di sottotitolatura di otsu, sia un buon scatto.

Ecco un campione utilizzando pitone terminale di comando:

>>> import cv2 
>>> import numpy as np 
>>> img2 = cv2.imread('D:\Abid_Rahman_K\work_space\sofeggs.jpg',0) 

>>> ret,thresh = cv2.threshold(img2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) 

>>> ret 
122.0 

ret è il valore di soglia che viene calcolata automaticamente. Passiamo semplicemente a "0" come valore di soglia per questo.

Ho ottenuto 124 in GIMP (che è paragonabile al risultato ottenuto). E rimuove anche il rumore. Vedere risultato qui sotto:

enter image description here

6

Se si dice che lo sfondo è scuro (nero) e il primo piano è più leggero, allora vi consiglio di utilizzare la YUV color space (o qualsiasi altro YXX come YCrCb, ecc), perché il primo componente di tali spazi colore è luminanza (o fulmineo).

light channel

Così, dopo il canale Y viene estratto (tramite la funzione extractChennel) dobbiamo analizzare l'istogramma di questo canale (immagine):

histogram

V. primo (a sinistra) gobba? Rappresenta le aree scure (lo sfondo nella tua situazione) sull'immagine. Quindi il nostro scopo ora è quello di trovare un segmento (in ascissa, è la parte rossa nell'immagine) che contiene questa gobba. Ovviamente il punto di sinistra di questo segmento è zero. Il punto giusto è il primo punto in cui:

  • il (locale) massimo di istogramma è dalla sinistra del punto
  • il valore di istogramma è inferiore a qualche piccolo epsilon (è possibile impostarlo su 10)

Ho disegnato una linea verticale verde per mostrare la posizione del punto destro del segmento in questo istogramma.

E questo è tutto! Questo punto giusto del segmento è la soglia necessaria. Ecco il risultato (epsilon è 10 e il calcolato soglia di è 50):

result

penso che non è un problema per voi di eliminare il rumore nell'immagine sopra.

0

Quello che segue è un'implementazione C++ di risposta di Abid che funziona con OpenCV 3.x:

// Convert the source image to a 1 channel grayscale: 
Mat gray; 
cvtColor(src, gray, CV_BGR2GRAY); 
// Apply the threshold function with the CV_THRESH_OTSU setting as well 
// You can skip having it return the value, but I include it for showing the 
// results from OTSU 
double thresholdValue = threshold(gray, gray, 0, 255, CV_THRESH_BINARY+CV_THRESH_OTSU); 
// Present the threshold value 
printf("Threshold value: %f\n", thresholdValue); 

L'esecuzione di questo contro l'immagine originale, ottengo il seguente: enter image description here

OpenCV ha calcolato un valore di soglia di 122, vicino al valore Abid trovato nella sua risposta.

solo per verificare, ho modificato l'immagine originale come si vede qui:

enter image description here

e prodotto il seguente, con un nuovo valore di soglia di 178:

enter image description here

Problemi correlati