C++版本OpenCv教程(三十六 )Canny算法

本节中最后介绍的边缘检测算法是Canny算法,该算法不容易受到噪声的影响,能够识别图像中的弱边缘和强边缘,并结合强弱边缘的位置关系,综和给出图像整体的边缘信息。Canny边缘检测算法是目前最优越的边缘检测算法之一,该方法的检测过程分为以下5个步骤:

  • Step1:使用高斯滤波平滑图像,减少图像中噪声。一般情况下使用式(5.23)所示的5×5的高斯滤波器。
    在这里插入图片描述

  • Step2:计算图像中每个像素的梯度方向和幅值。首先通过Sobel算子分别检测图像X方向的边缘和Y方向的边缘,之后利用式(5.24)计算梯度的方向和幅值。
    在这里插入图片描述

为了简便,梯度方向常取值0°、45°、90°和135°这个四个角度之一。

  • Step3:应用非极大值抑制算法消除边缘检测带来的杂散响应。首先将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较,如果当前像素的梯度强度与另外两个像素梯度强度相比最大,则该像素点保留为边缘点,否则该像素点将被抑制。
  • Step4:应用双阈值法划分强边缘和弱边缘。将边缘处的梯度值与两个阈值进行比较,如果某像素的梯度幅值小于较小的阈值,则会被去除掉;如果某像素的梯度幅 值大于较小阈值但小于较大阈值,则将该像素标记为弱边缘;如果某像素的梯度幅值大于较大阈值,则将该像素标记为强边缘。
  • Step5:消除孤立的弱边缘。在弱边缘的8邻域范围寻找强边缘,如果8邻域内存在强边缘,则保留该弱边缘,否则将删除弱边缘,最终输出边缘检测结果。

Canny算法具有复杂的流程,然而在OpenCV 4中提供了Canny()函数用于实现Canny算法检测图像中的边缘,极大的简化了使用Canny算法提取边缘信息的过程。Canny()函数的函数原型在代码清单5-32中给出。

void cv::Canny(InputArray  image,
               OutputArray  edges,
               double  threshold1,
               double  threshold2,
               int  apertureSize = 3,
               bool  L2gradient = false 
               )
  • image:输入图像,必须是CV_8U的单通道或者三通道图像。
  • edges:输出图像,与输入图像具有相同尺寸的单通道图像,且数据类型为CV_8U。
  • threshold1:第一个滞后阈值。
  • threshold2:第二个滞后阈值。
  • apertureSize:Sobel算子的直径。
  • L2gradient:计算图像梯度幅值方法的标志,幅值的两种计算方式如式(5.25)所示。
    在这里插入图片描述

该函数利用Canny算法提取图像中的边缘信息。第一个参数是需要提取边缘的输入图像,目前只支持数据类型为CV_8U的图像,输入图像可以是灰度图像或者彩色图像。第二个参数是边缘检测结果的输出图像,图像是数据类型为为CV_8U的单通道灰度图像。函数第三个和第四个参数是Canny算法中用于区分强边缘和弱边缘的两个阈值,两个参数不区分较大阈值和较小阈值,函数会自动比较区分两个阈值的大小,不过一般情况下,较大阈值与较小阈值的比值在2:1到3:1之间。函数最后一个参数是计算梯度幅值方法的选择标志,无特殊需求的情况下,使用默认值即可。

为了更好的理解Canny()函数的使用方法,在代码清单5-33中给出了利用Canny()函数检测图像边缘的示例程序。程序中通过设置不同的阈值来比较阈值的大小对图像边缘检测效果的影响,程序的输出结果在图5-35给出。通过结果可以发现,较高的阈值会降低噪声信息对图像提取边缘结果的影响,但是同时也会减少结果中的边缘信息。同时程序中先对图像进行高斯模糊后再进行边缘检测,结果表明高斯模糊在边缘纹理较多的区域能减少边缘检测的结果,但是对纹理较少的区域影响较小。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

int main(){
    
    
    //读取图像,黑白图像边缘检测结果较为明显
    Mat img=imread("luffy.jpg");
    Mat luffy,luffy_gray;
    resize(img,luffy,Size(img.rows/2,img.cols/2));
    cvtColor(luffy,luffy_gray,COLOR_BGR2GRAY);
    if(luffy_gray.empty()){
    
    
        cout<<"请确认输入的图片路径是否正确"<<endl;
        return -1;
    }
    Mat resultHigh,resultLow,resultG;

    //大阈值检测图像边缘
    Canny(luffy_gray,resultHigh,100,200,3);

    //小阈值检测图像边缘
    Canny(luffy_gray,resultLow,20,40,3);

    //高斯滤波后检测图像边缘
    GaussianBlur(luffy_gray,resultG,Size(3,3),5);
    Canny(resultG,resultG,100,200,3);

    //显示图像
    imshow("resultHigh",resultHigh);
    imshow("resultLow",resultLow);
    imshow("resultG",resultG);
    waitKey(0);
    return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_33287871/article/details/112647806