赞
踩
边缘检测的简单介绍:LINK
本文只介绍如何使用。
Sobel算子和Scharr算子的参数是一样,两者主要是X和Y方向的滤波器(卷积核)不同。Scharr算子可以看成Sobel算子的加强版,对一些导数较小(即像素值差距不大)的弱边缘仍然可以检测出。
void cv::Sobel(
InputArray src, // 输入图像,可以是单通道(灰度图)或多通道(彩色图)
OutputArray dst, // 输出图像,与输入图像具有相同的尺寸和深度
int ddepth, // 输出图像的深度,使用-1表示输出与输入图像具有相同的深度(也可写CV_16S)
int dx, int dy, // x方向和y方向上的导数阶数,0表示只计算横向导数,1表示只计算纵向导数
int ksize = 3, // Sobel核的大小,必须为1、3、5或7。默认值为3
double scale = 1, // 缩放因子,默认为1,将应用于计算得到的导数结果
double delta = 0 // 可选的增量,默认为0,将添加到最终结果中
)
第三个参数也可理解为输出图像的类型。由于梯度计算涉及差分运算,可能会产生负数值和超过 255 的正数值
故要使用有符号的 CV_16S 作为输出图像的深度参数,确保导数结果的范围足够大。
后续在需要显示或处理这些导数结果时,使用 cv::convertScaleAbs 函数将其转换为无符号 8 位整数(CV_8U)类型,便于显示和处理
int main() { cv::Mat image = cv::imread("C:/Users/Opencv/temp/niu.png", cv::IMREAD_GRAYSCALE); if (image.empty()) { cout << "Failed to read the image" << endl; return -1; } // 1、Sobel算子检测 cv::Mat sobelX, sobelY; cv::Sobel(image, sobelX, CV_16S, 1, 0); cv::Sobel(image, sobelY, CV_16S, 0, 1); // 转换为绝对值 cv::Mat sobelXAbs, sobelYAbs; cv::convertScaleAbs(sobelX, sobelXAbs); cv::convertScaleAbs(sobelY, sobelYAbs); // 整幅图的一阶边缘 cv::Mat edges1; edges1 = sobelXAbs + sobelYAbs; //cv::addWeighted(sobelXAbs, 0.5, sobelYAbs, 0.5, 0, edges); // 2、Scharr算子检测 cv::Mat scharrX, scharrY; cv::Scharr(image, scharrX, CV_16S, 1, 0); cv::Scharr(image, scharrY, CV_16S, 0, 1); // 转换为绝对值 cv::Mat scharrXAbs, scharrYAbs; cv::convertScaleAbs(scharrX, scharrXAbs); cv::convertScaleAbs(scharrY, scharrYAbs); // 整幅图的一阶边缘 cv::Mat edges2; edges2 = scharrXAbs + scharrYAbs; //cv::addWeighted(scharrXAbs, 0.5, scharrYAbs, 0.5, 0, edges); cv::imshow("原图", image); cv::imshow("sobel'检测", edges1); cv::imshow("scharr检测", edges2); cv::waitKey(0); cv::destroyAllWindows(); }
从结果可以看出,scharr算子会检测出更多的边缘。
Sobel算子和Scharr算子都具有方向性,因此需要分别求取X方向的边缘和Y方向的边缘,之后将两个方向的边缘综合得到图像的整体边缘(对一些斜角度的边缘,是否存在额外的加强?)。
Laplacian算子具有各方向同性的特点,能够对任意方向的边缘进行提取。Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用。
void cv::Laplacian(
InputArray src, // 输入图像,可以是单通道(灰度图)或多通道(彩色图)
OutputArray dst, // 输出图像,与输入图像具有相同的尺寸和深度
int ddepth, // 输出图像的深度,使用-1表示输出与输入图像具有相同的深度
int ksize = 1, // 拉普拉斯核的大小,可以设置为1、3、5或7。默认值为1,但常用为3
double scale = 1, // 缩放因子,默认为1,将应用于计算得到的拉普拉斯结果
double delta = 0, // 可选的增量,默认为0,将添加到最终结果中
int borderType = cv::BORDER_DEFAULT // 边界类型,默认为cv::BORDER_DEFAULT
);
cv::Mat edges3, edges4, Gresult;
cv::Laplacian(image, edges3, CV_16S, 3, 1, 0);
cv::convertScaleAbs(edges3, edges3);
cv::GaussianBlur(image, Gresult, cv::Size(3, 3), 5, 0); // 进行高斯滤波
cv::Laplacian(Gresult, edges4, CV_16S, 3, 1, 0);
cv::convertScaleAbs(edges4, edges4);
Canny算法的流程较为复杂,然而在OpenCV4中提供了Canny()函数用于实现Canny算法检测图像中的边缘,极大的简化了使用Canny算法提取边缘信息的过程。(使用高斯滤波平滑图像时,一般使用5×5的高斯滤波器)
void cv::Canny(
InputArray image, // 输入图像,单通道灰度图像
OutputArray edges, // 输出边缘图像,二值图像,非零像素表示边缘
double threshold1, // 第一个阈值,用于边缘链接的低阈值
double threshold2, // 第二个阈值,用于边缘链接的高阈值
int apertureSize = 3, // Sobel 算子的孔径大小,默认为 3
bool L2gradient = false // 是否使用 L2 梯度计算,默认为 false,即使用 L1 梯度计算
);
一般情况下,较大阈值与较小阈值的比值在2:1到3:1之间
cv::Mat edges5, edges6, Gcanny;
cv::GaussianBlur(image, Gcanny, cv::Size(3, 3), 5);
cv::Canny(Gcanny, edges5, 10, 20); // 小阈值
cv::Canny(Gcanny, edges6, 90, 180); // 大阈值
从结果可以看出,较大的阈值会降低噪声信息对图像提取边缘结果的影响,但是同时也会减少结果中的边缘信息。
进行边缘检测时,通常是输入灰度图,因为灰度图像边缘检测结果较为明显。每种方法都有其特点和适用范围,具体选择哪种方法取决于应用需求和图像特征。如 Sobel 算子在边缘检测中具有较好的速度,因此被广泛应用于许多实时和性能要求不高的图像处理应用中。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。