image processing - morfologia - Cálculo automático de umbrales bajos y altos para la operación Canny en opencv
opencv canny edge (7)
Además, hay un código disponible para hacer esto automáticamente, al poner esto en la compilación de OpenCV. Lo encontré en la lista de correo de los usuarios de OpenCV, por lo que no hay garantías. :)
Discusión: http://opencv-users.1802565.n2.nabble.com/Automatic-thresholding-in-cvCanny-td5871024.html GitHub (código): https://gist.github.com/756833
En openCV, los umbrales bajo y alto para el operador de canny son obligatorios:
cvCanny(input,output,thresh1,thresh2)
En Matlab, hay una opción para calcular esos automáticamente:
edge(input,''canny'')
He buscado el código de Matlab para edge, y esto realmente no es sencillo para calcular esos automáticamente.
¿Conoce alguna implementación del operador de canny junto con el cálculo de umbral automático para opencv?
Gracias
Como ha sugerido Luca Del Tongo, puede calcular los umbrales a partir de la imagen gris, por ejemplo, en 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);
Echa un vistazo a este enlace: http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/
Implementan una solución similar usando estadísticas básicas para determinar el umbral bajo y alto para la detección de bordes de 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
Me encontré con esta respuesta mientras buscaba una forma de calcular automáticamente los valores umbral de Canny.
Espero que esto ayude a cualquiera que busque un buen método para determinar los valores de umbral automáticos para el algoritmo de Canny ...
Si su imagen consiste en primer plano y fondo distintos, entonces el borde del objeto en primer plano se puede usar de la siguiente forma:
Calcule el umbral de Otsu usando:
double otsu_thresh_val = cv::threshold( orig_img, _img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU );
No necesitamos el
_img
. Estamos interesados enotsu_thresh_val
pero, lamentablemente, actualmente no hay ningún método en OpenCV que le permita calcular solo el valor de umbral.Utilice el valor umbral de Otsu como umbral más alto y la mitad de lo mismo que el umbral inferior para el algoritmo de 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 );
Se puede encontrar más información relacionada con esto en este documento: El estudio sobre una aplicación del método Otsu en Canny Operator . Una explicación de la implementación de Otsu se puede encontrar here .
Puede usar el valor medio de su imagen de entrada en escala de grises y definir los umbrales más bajos y más altos usando la desviación estándar. Puede obtener una explicación más detallada y el código de OpenCV aquí: http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/
Revisé el código fuente de la detección de bordes de Matlab Canny y pude escribirlo en 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<Mat> matList = new ArrayList<Mat>();
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;
}
La ruta de archivo es el lugar para contener las imágenes de salida. Y la imagen de entrada debe ser una imagen en escala de grises con el tipo de datos U8. El principio básico es descartar píxeles no bordes (60%) como píxeles que no sean bordes por el brillo. Se usa un histograma para ordenar el brillo y el umbral superior se establecerá de modo que haya un 60% de píxeles debajo de él. El umbral inferior se establece multiplicando el umbral superior por el thresholdRate (0.6).
Tenga en cuenta que el double nonEdgeRate = 0.6 y el doble thresholdRate = 0.6 lo sintonizo yo mismo en mi caso de uso específico. Los valores originales son 0.7 y 0.4 por separado en matlab.
Tengo otro enfoque para el mismo problema. Esta solución también implica la selección de umbrales óptimos para la detección de bordes.
- Primero calcule la mediana de la imagen de la escala de grises.
- Elija dos valores (umbrales inferior y superior) basados en el valor mediano de la imagen de escala de grises.
El siguiente pseudo-código muestra cómo se hace:
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))
Corrija estos umbrales como parámetros en la función de detección de bordes astutos.
Ilustración : si observa una curva gaussiana en las estadísticas, los valores entre 0.33 de ambos lados de la curva se consideran en la distribución. Se supone que cualquier valor fuera de estos puntos es atípico. Dado que las imágenes se consideran datos, este concepto se asume también aquí.