目标
- 使用OpenCV函数cv :: Canny来实现Canny Edge Detector。
理论
该Canny边缘检测是由约翰·F·坎尼在1986年也知道很多的开发最佳的检测,坎尼算法旨在满足三个主要标准:
- 低错误率:意味着只有现有边缘的良好检测。
- 良好的定位:检测到的边缘像素与实际边缘像素之间的距离必须最小化。
- 最小响应:每个边缘只有一个检测器响应。
步骤
- 滤除任何噪音。高斯滤波器用于此目的。可能使用的的高斯内核的示例如下所示:size=5
- 找到图像的强度梯度。为此,我们遵循类似于Sobel的程序:
应用一对卷积面罩 (在 x 和 y directions:
查找梯度强度和方向:
方向四舍五入为四个可能的角度之一(即0,45,90或135)
- 应用非最大抑制。这将删除不被认为是边缘的一部分的像素。因此,只有细线(候选边)将保留。
- 滞后:最后一步。Canny确实使用两个阈值(上限和下限):
- 如果像素梯度高于上限阈值,则像素被接受为边缘
- 如果像素梯度值低于较低阈值,则会被拒绝。
- 如果像素梯度在两个阈值之间,那么只有当它连接到高于上限阈值的像素时才被接受。
Canny推荐上限:2:1和3:1之间的较低比例。
- 有关更多详细信息,您可以随时咨询您最喜爱的Computer Vision书籍。
Code
- 这个程序是做什么的?
- 要求用户输入数值以设置我们的Canny Edge Detector的下限(通过Trackbar)。
- 应用Canny Detector并生成一个蒙版(亮线表示黑色背景上的边缘)。
- 应用在原始图像上获得的蒙版,并将其显示在窗口中。
- 代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
Mat src, gray_src, dst;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("C:/usr/opencv-test/Testpictures/sight.jpg");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*) {
Mat edge_output;
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
Canny(gray_src, edge_output, t1_value, t1_value * 3, 3, false);//false表用L1,即G(s) = |G(x)|+|G(y)|
dst.create(src.size(), src.type());
src.copyTo(dst, edge_output);
// (edge_output, edge_output);
imshow(OUTPUT_TITLE, edge_output);
}
说明
请注意以下事项:
- 我们建立一个较低的上限阈值3:1(与可变比率)的比率。
- 我们设置内核大小为(Sobel操作由Canny函数内部执行)。3
- 我们为的下限阈值设置最大值。100
- 加载源图像:
- 创建一个相同类型和大小的src(为dst)的矩阵:
- 将图像转换为灰度级(使用函数cv :: cvtColor):
cvtColor(src,src_gray,COLOR_BGR2GRAY);
- 创建一个窗口来显示结果:
- 创建一个跟踪栏,供用户输入Canny检测器的下限:
createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
观察以下内容:
- Trackbar要控制的变量是lowThreshold,最大值为max_lowThreshold(我们先前设置为100)
- 每次Trackbar注册一个动作时,将调用回调函数CannyThreshold。
- 让我们检查CannyThreshold函数,一步一步:
- 首先,我们用内核大小为3的过滤器模糊图像:
-
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
- 然后,我们应用OpenCV函数cv :: Canny:
Canny(gray_src, edge_output, t1_value, t1_value * 3, 3, false);
其中的解释:
-
- detected_edges:源图像,灰度
- detected_edges:检测器的输出(可以与输入相同)
- lowThreshold:用户移动轨迹栏输入的值
- highThreshold:在程序中设置为下限阈值的三倍(在Canny的建议之后)
- kernel_size:我们将它定义为3(要在内部使用的Sobel内核的大小)
结果
- 在编译上面的代码之后,我们可以运行它作为参数作为图像的路径。例如,使用以下图像作为输入:
- 移动滑块,尝试不同的阈值,我们得到以下结果:
- 注意图像如何与边缘区域上的黑色背景叠加。