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

相关推荐
差不多的周周1 小时前
《MotionLLM:从人体运动和视频理解人类行为》论文核心部分详解
人工智能·深度学习·机器学习·计算机视觉·语言模型·音视频
luj_17682 小时前
一线一区一变破解人盯人防守密码
开发语言·网络·c++·经验分享·算法
广州山泉婚姻2 小时前
C/C++动态内存:堆内存的申请、使用与释放
c++·人工智能
LeapMay2 小时前
中国科学院深圳先进技术研究院-深圳职业技术大学联合培养博士后招聘(具身智能/多模态感知/视觉检测方向)
人工智能·计算机视觉·3d·机器人
Jackson_GJH2 小时前
日志_图解spdlog
开发语言·c++
kyle~3 小时前
ISP---RAW 成像的物理基础
计算机视觉·接口隔离原则·相机
hansang_IR3 小时前
【题解】P4454 [CQOI2018] 破解D-H协议
c++·算法·密码学·数论
梓䈑3 小时前
【动态规划系列】路径问题、子数组 和 子序列问题、背包问题
c++·算法·动态规划
aqiu1111113 小时前
【数位 DP / 记忆化搜索】蓝桥云课 - 光轨区的 AI 数 题解
c++·算法·蓝桥杯·数位dp
欧特克_Glodon3 小时前
OpenCV计算机视觉开发入门与实践<三十七>:OpenCV中的机器学习
c++·opencv·机器学习·计算机视觉