『OpenCV3』滤波器边缘检测

一、原理简介

边缘检测原理 - Sobel, Laplace, Canny算子

X方向Sobel算子

-1 -2 -1
0 0 0
1 2 1

Y方向Sobel算子

-1 0 1
-2 0 2
-1 0 1

Laplace算子

1 1 1
1 -8 1
1 1 1

Canny 边缘检测算子

高斯滤波器平滑图像

一阶差分偏导计算梯度值和方向

对梯度值不是极大值的地方进行抑制

用双阈值连接图上的联通点

通俗说一下,
1.用高斯滤波主要是去掉图像上的噪声。
2.计算一阶差分,OpenCV 源码中也是用 sobel 算子来算的。
3.算出来的梯度值,把不是极值的点,全部置0,去掉了大部分弱的边缘。所以图像边缘会变细。
4.双阈值 t1, t2, 是这样的,t1 <= t2
大于 t2 的点肯定是边缘
小于 t1 的点肯定不是边缘
在 t1, t2 之间的点,通过已确定的边缘点,发起8领域方向的搜索(广搜),图中可达的是边缘,不可达的点不是边缘。
最后得出 canny 边缘图。

二、代码演示

有关函数 convertScaleAbs,文档解释如下,不过这里不使用其放缩功能

1、Sobel 边缘检测算子

由于需要指定横向纵向,所以分两步进行,最后组合即可,

	cv::Mat image = cv::imread("test.jpg");
	cv::imshow("原图", image);
	cv::Mat gray;
	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

	cv::Mat contours;	
        cv::Mat sobelX, sobelY;
	cv::Sobel(
		image,
		sobelX,
		CV_16S,  // 图像depth,输入8U,输出16S防止外溢
		1, 0,   // xorder, yorder
		3,		// 内核尺寸
		1, 1	// 输出结果乘alpha加beta
	);
	cv::convertScaleAbs(sobelX, sobelX);
	cv::imshow("Sobel_X", sobelX);
	cv::Sobel(
		image,
		sobelY,
		CV_8U,
		0, 1,
		3,
		1, 1
	);
	cv::convertScaleAbs(sobelY, sobelY);
	cv::imshow("Sobel_Y", sobelY);
	cv::addWeighted(sobelX, 0.5, sobelY, 0.5, 0, contours);
	cv::imshow("Sobel", contours);    

 XY单方向输出如下,

两这合并如下,

2、Laplace 边缘检测算子

	// cv::Mat image = cv::imread("skin.jfif");
	cv::Mat image = cv::imread("test.jpg");
	cv::imshow("原图", image);
	cv::Mat gray;
	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

	cv::Mat contours;
        cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
	cv::Laplacian(
		gray,
		contours,
		CV_16S,
		3,  // 内核尺寸
		1, 0 // 放缩因子
	);
	
	cv::convertScaleAbs(contours, contours);
	cv::imshow("Laplacian", contours);

3、Canny 边缘检测算子

	// cv::Mat image = cv::imread("skin.jfif");
	cv::Mat image = cv::imread("test.jpg");
	cv::imshow("原图", image);
	cv::Mat gray;
	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

	cv::Mat contours;
	cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
	cv::Canny(
		gray,
		contours,
		10,  // 低阈值
		150   // 高阈值
	);
	cv::imshow("Canny", contours);

高低阈值参数的设定对于检测效果影响很大,一般来说低阈值检测出十分琐碎的边缘,且设置的越低检测出来的越多,而高阈值这决定了保留多少边缘,对于上图,我们将高阈值下调至50查看一下效果,会发现保留细节数目增加了

附录、函数总览

void edge() {
	// cv::Mat image = cv::imread("skin.jfif");
	cv::Mat image = cv::imread("test.jpg");
	cv::imshow("原图", image);
	cv::Mat gray;
	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

	cv::Mat contours;
	cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
	cv::Canny(
		gray,
		contours,
		10,  // 低阈值
		150   // 高阈值
	);
	cv::imshow("Canny", contours);

	cv::Laplacian(
		gray,
		contours,
		CV_16S,
		3,  // 内核尺寸
		1
	);
	cv::Mat abs_dst;
	cv::convertScaleAbs(contours, contours);
	cv::imshow("Laplacian", contours);

	cv::Mat sobelX, sobelY;
	cv::Sobel(
		image,
		sobelX,
		CV_16S,  // 图像depth,输入8U,输出16S防止外溢
		1, 0,   // xorder, yorder
		3,		// 内核尺寸
		1, 1	// 输出结果乘alpha加beta
	);
	cv::convertScaleAbs(sobelX, sobelX);
	cv::imshow("Sobel_X", sobelX);
	cv::Sobel(
		image,
		sobelY,
		CV_8U,
		0, 1,
		3,
		1, 1
	);
	cv::convertScaleAbs(sobelY, sobelY);
	cv::imshow("Sobel_Y", sobelY);
	cv::addWeighted(sobelX, 0.5, sobelY, 0.5, 0, contours);
	cv::imshow("Sobel", contours);
}
原文地址:https://www.cnblogs.com/hellcat/p/9891656.html