OpenCV4(C++)—— 边缘检测的使用


前言

边缘检测的简单介绍:LINK
本文只介绍如何使用。

一、Sobel算子和Scharr算子

  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算子会检测出更多的边缘。

在这里插入图片描述

二、Laplacian算子

  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算法

  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:13: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 算子在边缘检测中具有较好的速度,因此被广泛应用于许多实时和性能要求不高的图像处理应用中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要躺平的一枚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值