当前位置:   article > 正文

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

c++opencv sobel边缘检测


前言

边缘检测的简单介绍: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)类型,便于显示和处理

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

从结果可以看出,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
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
    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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

三、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之间
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    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);  // 大阈值
  • 1
  • 2
  • 3
  • 4

从结果可以看出,较大的阈值会降低噪声信息对图像提取边缘结果的影响,但是同时也会减少结果中的边缘信息。
在这里插入图片描述

总结

进行边缘检测时,通常是输入灰度图,因为灰度图像边缘检测结果较为明显。每种方法都有其特点和适用范围,具体选择哪种方法取决于应用需求和图像特征。如 Sobel 算子在边缘检测中具有较好的速度,因此被广泛应用于许多实时和性能要求不高的图像处理应用中。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/959103
推荐阅读
相关标签
  

闽ICP备14008679号