自动计算opencv中Canny操作的低和高阈值

在openCV中,canny操作符的低和高阈值是强制性的:

cvCanny(input,output,thresh1,thresh2) 

在Matlab中,可以自动计算这些选项:

 edge(input,'canny') 

我已经研究了Matlab的边缘代码,这实际上不是直接计算这些自动。

您是否知道canny操作符的任何实现以及opencv的自动阈值计算?

谢谢

当我寻找一种自动计算Canny阈值的方法时,我偶然发现了这个答案。

希望这有助于任何人来寻找一个很好的方法来确定自动阈值Canny的algorithm…


如果您的图像由不同的前景和背景组成,那么前景对象的边缘可以使用以下方法提取:

  1. 用下面的方法计算Otsu的阈值:

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

    我们不需要_img 。 我们只对otsu_thresh_val感兴趣,但不幸的是,目前在OpenCV中没有方法可以只计算阈值。

  2. 使用大津的门槛值作为较高的门槛和一半的相同的门槛下限的坎尼的algorithm。

     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 ); 

有关这方面的更多信息可以在这篇文章中find:Otsu方法在Canny算子中的应用研究 。 大津的实现的解释可以在这里find。

您可以使用input灰度图像的平均值,并使用标准偏差定义下限和上限。 您可以在这里获得更详细的解释和opencv代码: http : //www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/

另外,还有代码可以自动完成这个,把它放在OpenCV构build中。 我在OpenCV用户邮件列表中find它,所以没有保证。 🙂

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

我已经查看了Matlab Canny边缘检测的源代码,并设法使用OpenCV 3在Java中编写它。

 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; } 

文件path是保存输出图像的地方。 input图像应该是一个U8数据types的灰度图像。 基本原理是通过亮度排除nonEdgeRate(60%)像素作为非边缘像素。 使用直方图对亮度进行sorting,并设置较高的阈值,使其下面有60%的像素。 下阈值是通过将上阈值乘以阈值(0.6)来设定的。

请注意,在我的具体使用情况下,double nonEdgeRate = 0.6和double thresholdRate = 0.6是自己调整的。 在matlab中,原始值分别是0.7和0.4。

看看这个链接: http : //www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/

他们使用基本的统计数据来实现类似的解决scheme,以确定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 

对于同样的问题,我有另一种方法。 该解决scheme还涉及select用于边缘检测的最佳阈值。

  • 首先计算灰度图像的中位数
  • 根据灰度图像的中值select两个值(低和高阈值)。

下面的伪代码显示了它是如何完成的:

 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)) 

修正这些阈值作为Canny边缘检测function的参数。

示意图 :如果您在统计中观察到高斯曲线,则在分布中考虑曲线两边0.33之间的值。 这些点以外的任何值被假定为exception值。 由于图像被认为是数据,所以这里也假设这个概念。

正如Luca Del Tongo所build议的那样,您可以从灰色图像中计算阈值,例如使用OpenCV的Java。

 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);