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

文章目录


前言

边缘检测的简单介绍:LINK

本文只介绍如何使用。

一、Sobel算子和Scharr算子

Sobel算子和Scharr算子的参数是一样,两者主要是X和Y方向的滤波器(卷积核)不同。Scharr算子可以看成Sobel算子的加强版,对一些导数较小(即像素值差距不大)的弱边缘仍然可以检测出。

c 复制代码
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)类型,便于显示和处理
c 复制代码
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算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用。

c 复制代码
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
);
c 复制代码
    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的高斯滤波器)

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

相关推荐
景彡先生3 小时前
C++并行计算:OpenMP与MPI全解析
开发语言·c++
归去_来兮5 小时前
深度学习模型在C++平台的部署
c++·深度学习·模型部署
pay4fun6 小时前
2048-控制台版本
c++·学习
hjjdebug7 小时前
ffplay6 播放器关键技术点分析 1/2
c++·ffmpeg·音视频
一只小灿灿8 小时前
前端计算机视觉:使用 OpenCV.js 在浏览器中实现图像处理
前端·opencv·计算机视觉
Azxcc08 小时前
C++异步编程入门
开发语言·c++
吐泡泡_8 小时前
C++(STL源码刨析/vector)
c++
你的冰西瓜8 小时前
C++排序算法全解析(加强版)
c++·算法·排序算法
特立独行的猫a9 小时前
11款常用C++在线编译与运行平台推荐与对比
java·开发语言·c++
笑鸿的学习笔记9 小时前
qt-C++笔记之setCentralWidget的使用
c++·笔记·qt