一、引入
Canny边缘检测器可以说是OpenCV中的一个重要工具,它可以自己通过调节阈值对图像边缘进行检测与滤波,具有低错误率与良好的定位。
二、原理
-
过滤掉任何噪音。高斯滤波器用于此目的。
可能使用的高斯内核示例如下所示:
-
找到图像的强度梯度。为此,我们遵循类似索贝尔的程序:
-
使用一对卷积面罩(在
和
方向:
-
找到梯度强度和方向:
方向四舍五入为四个可能的角度之一(即0,45,90或135)
-
-
应用非最大抑制。这将删除不被视为边缘一部分的像素。因此,仅保留细线(候选边缘)。
-
迟滞:最后一步。Canny确实使用了两个阈值(上限和下限):
- 如果像素梯度高于上阈值,则将像素接受为边缘
- 如果像素梯度值低于下阈值,则拒绝它。
- 如果像素梯度在两个阈值之间,则仅当它连接到高于上阈值的像素时才接受。
Canny建议上限:较低的比例在2:1和3:1之间。
三、代码
-
创建一些所需的变量:
Mat src, src_gray; Mat dst, detected_edges; int edgeThresh = 1; int lowThreshold; int const max_lowThreshold = 100; int ratio = 3; int kernel_size = 3; char* window_name = "Edge Map";
请注意以下事项: a.我们建立一个3:1的低:高阈值比率(可变*比率*) b.我们将内核大小设置为:math:`3`(对于canny函数内部执行的sobel操作) c.我们为以下阈值设置了一个最大值:math:`100`。
-
加载源图像:
/// Load an image src = imread( argv[1] ); if( !src.data ) { return -1; }
-
创建一个src相同类型和大小的矩阵(将是dst)
dst.create( src.size(), src.type() );
-
将图像转换为灰度(使用函数cvtColor:
cvtColor( src, src_gray, CV_BGR2GRAY );
-
创建一个窗口以显示结果
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
-
创建一个跟踪栏,供用户输入Canny探测器的下限:
createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
请注意以下事项:
- 由Trackbar控制的变量是lowThreshold,其限制为max_lowThreshold(我们之前设置为100)
- 每次Trackbar注册一个动作时,都会调用回调函数CannyThreshold。
-
让我们一步一步检查CannyThreshold函数:
-
首先,我们使用内核大小为3的过滤器模糊图像:
blur( src_gray, detected_edges, Size(3,3) );
-
其次,我们应用OpenCV函数Canny:
Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
参数在哪里:
- detected_edges:源图像,灰度
- detected_edges:探测器的输出(可以与输入相同)
- lowThreshold:用户移动Trackbar输入的值
- highThreshold:在程序中设置为下限阈值的三倍(遵循Canny的建议)
- kernel_size:我们将它定义为3(内部使用的Sobel内核的大小)
-
-
我们用零填充dst图像(意味着图像是完全黑色的)。
dst = Scalar::all(0);
-
最后,我们将使用函数copyTo仅映射图像中标识为边的区域(在黑色背景上)。
src.copyTo( dst, detected_edges);
CopyTo从复制的src图像到DST。但是,它只会复制具有非零值的位置的像素。由于Canny探测器的输出是黑色背景上的边缘轮廓,因此得到的dst在所有区域中都是黑色的,但是检测到的边缘。
-
我们显示结果:
imshow( window_name, dst );