Calcolo automatico di soglie basse e alte per l’operazione Canny in modalità opencv

In openCV, le soglie bassa e alta per l’operatore abile sono obbligatorie:

cvCanny(input,output,thresh1,thresh2) 

In Matlab, c’è un’opzione per calcolarli automaticamente:

 edge(input,'canny') 

Ho esaminato il codice di Matlab per edge, e questo non è davvero semplice per calcolarli automaticamente.

Sei a conoscenza di qualsiasi implementazione dell’operatore abile insieme al calcolo automatico della soglia per opencv?

Grazie

Mi sono imbattuto in questa risposta mentre stavo cercando un modo per calcolare automaticamente i valori di soglia di Canny.

Spero che questo aiuti chiunque sia in cerca di un buon metodo per determinare i valori di soglia automatici per l’algoritmo di Canny …


Se l’immagine è composta da un piano e uno sfondo distinti, il bordo dell’object in primo piano può essere estratto come segue:

  1. Calcola la soglia di Otsu usando:

     double otsu_thresh_val = cv::threshold( orig_img, _img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU ); 

    Non abbiamo bisogno del _img . Siamo interessati solo a otsu_thresh_val ma sfortunatamente, attualmente non esiste alcun metodo in OpenCV che ti permetta di calcolare solo il valore di soglia.

  2. Usa il valore di soglia di Otsu come soglia superiore e metà dello stesso della soglia inferiore per l’algoritmo di Canny.

     double high_thresh_val = otsu_thresh_val, lower_thresh_val = otsu_thresh_val * 0.5; cv::Canny( orig_img, cannyOP, lower_thresh_val, high_thresh_val ); 

Ulteriori informazioni relative a questo possono essere trovate in questo documento: Lo studio su un’applicazione del metodo Otsu in Canny Operator . Una spiegazione dell’attuazione di Otsu può essere trovata qui .

È ansible utilizzare il valore medio dell’immagine in scala di grigi di input e definire le soglie inferiore e superiore utilizzando la deviazione standard. Puoi avere una spiegazione più dettagliata e codice di OpenCV qui: http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/

Inoltre, c’è un codice disponibile per farlo automaticamente, inserendolo nella build di OpenCV. L’ho trovato nella mailing list degli utenti OpenCV, quindi non ci sono garanzie. 🙂

Discussione: http://opencv-users.1802565.n2.nabble.com/Automatic-thresholding-in-cvCanny-td5871024.html GitHub (codice): https://gist.github.com/756833

Ho esaminato il codice sorgente del rilevamento dei bordi di Matlab Canny e sono riuscito a scriverlo in Java con OpenCV 3.

 private static Mat getpartialedge(Mat image){ double nonEdgeRate = 0.6; double thresholdRate = 0.6; double w = image.cols(); double h = image.rows(); int bins = 256; Mat sobel = new Mat(); Mat sobelx = new Mat(); Mat sobely = new Mat(); Mat sobelxabs = new Mat(); Mat sobelyabs = new Mat(); Size gsz = new Size(5, 5); if(false) { Imgproc.Canny(image, sobel, 41, 71); }else { //Imgproc.GaussianBlur(graycopy,graycopy, gsz, 2); //Imgproc.dilate(image, image, kernel8); Imgproc.GaussianBlur(image, image, gsz, 2); int apertureSize = 3; Imgproc.Sobel(image, sobelx, CvType.CV_16S, 1, 0, apertureSize, 1, 0); Core.convertScaleAbs(sobelx, sobelxabs); Imgproc.Sobel(image, sobely, CvType.CV_16S, 0, 1, apertureSize, 1, 0); Core.convertScaleAbs(sobely, sobelyabs); Core.addWeighted(sobelxabs, 1, sobelyabs, 1, 0, sobel); sobel.convertTo(sobel, CvType.CV_8U); Mat equalized = new Mat(); Imgproc.equalizeHist(sobel, equalized); Imgcodecs.imwrite(filePath + "aftersobel(eq).png", equalized); Imgcodecs.imwrite(filePath + "aftersobel.png", sobel); Mat hist = new Mat(); List matList = new ArrayList(); matList.add(sobel); Imgproc.calcHist(matList, new MatOfInt(0), new Mat(), hist, new MatOfInt(bins), new MatOfFloat(0f, 256f)); float accu = 0; float t = (float) (nonEdgeRate * w * h); float bon = 0; float[] accutemp = new float[bins]; for (int i = 0; i < bins; i++) { float tf[] = new float[1]; hist.get(i, 0, tf); accu = accu + tf[0]; accutemp[i] = accu; if (accu > t) { bon = (float) i; break; } } Imgproc.threshold(sobel, sobel, bon, 255, Imgproc.THRESH_BINARY); double ut = bon; double lt = thresholdRate * bon; Imgproc.Canny(image, sobel, lt, ut); //Imgproc.dilate(sobel, sobel, kernel2); } return sobel; } 

Il percorso file è il posto in cui tenere le immagini di output. E l’immagine di input dovrebbe essere un’immagine in scala di grigi con il tipo di dati U8. Il principio di base è quello di escludere il pixel nonEdgeRate (60%) come pixel non edge dalla luminosità. Viene utilizzato un istogramma per ordinare la luminosità e la soglia superiore verrà impostata in modo che ci siano 60% di pixel al di sotto di essa. La soglia inferiore viene impostata moltiplicando la soglia superiore per la sogliaRate (0.6).

Nota che double nonEdgeRate = 0.6 e double thresholdRate = 0.6 sono sintonizzati da me stesso nel mio caso d’uso specifico. I valori originali sono 0,7 e 0,4 separatamente in MATLAB.

Dai un’occhiata a questo link: http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/

Implementano una soluzione simile utilizzando le statistiche di base per determinare la soglia bassa e alta per il rilevamento del bordo Canny.

 def auto_canny(image, sigma=0.33): # compute the median of the single channel pixel intensities v = np.median(image) # apply automatic Canny edge detection using the computed median lower = int(max(0, (1.0 - sigma) * v)) upper = int(min(255, (1.0 + sigma) * v)) edged = cv2.Canny(image, lower, upper) # return the edged image return edged 

Ho un altro approccio allo stesso problema. Questa soluzione comporta anche la selezione di soglie ottimali per il rilevamento dei bordi.

  • Calcola prima la mediana dell’immagine in scala di grigi.
  • Scegli due valori (soglie inferiore e superiore) in base al valore medio dell’immagine in scala di grigi.

Il seguente pseudo-codice mostra come è stato fatto:

 v = np.median(gray_img) sigma = 0.33 #---- apply optimal Canny edge detection using the computed median---- lower_thresh = int(max(0, (1.0 - sigma) * v)) upper_thresh = int(min(255, (1.0 + sigma) * v)) 

Correggere queste soglie come parametri nella funzione di rilevamento dei bordi canny.

Illustrazione : se si osserva una curva gaussiana in statistica, i valori compresi tra 0,33 e entrambi i lati della curva vengono considerati nella distribuzione. Si presume che qualsiasi valore al di fuori di questi punti sia anomalo. Poiché le immagini sono considerate dati, anche qui si assume questo concetto.

Come suggerito da Luca Del Tongo, puoi calcolare le soglie dall’immagine grigia, ad es. In Java usando OpenCV …

 MatOfDouble mu = new MatOfDouble(); MatOfDouble stddev = new MatOfDouble(); Core.meanStdDev(greyMat, mu, stddev); threshold1 = mu.get(0, 0)[0]; threshold2 = stddev.get(0, 0)[0]; Imgproc.Canny(greyMat, outputMat, threshold1, threshold2);