欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV图像边缘检测(Canny算法)

程序员文章站 2024-01-28 09:43:52
...

一、图像边缘检测简介
  图像的边缘是指图像局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。图像的边缘部分集中了图像的大部分信息,图像边缘的确定与提取对于整个图像场景的识别与理解是非常重要的,同时也是图像分割所依赖的重要特征,边缘检测主要是图像的灰度变化的度量、检测和定位,自从1959提出图像边缘检测以来,经过五十多年的发展,已有许多中不同的图像边缘检测方法。常见的方法有canny算子、Laplace算子,sobel算子和Scharr算子等。
  关于图像边缘检测一般有以下步骤,如下图所示:

OpenCV图像边缘检测(Canny算法)

  下面将对边缘检测算法进行分别介绍。

二、Canny算子
2.1、Canny算子简介
  JohnCanny于1986年提出Canny算子,它与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法。它是一个多级边缘检测算法。Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:
  (1)好的检测- 算法能够尽可能多地标识出图像中的实际边缘;
  (2)好的定位- 标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近;
  (3)最小响应- 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。
  为了满足这些要求 Canny 算法使用了变分法,这是一种寻找满足特定功能的函数的方法。最优检测使用四个指数函数项的和表示,但是它非常近似于高斯函数的一阶导数。
2.2、Canny 边缘检测的步骤
(1)去噪声
  用高斯滤波器对输入图像做平滑处理 (大小为 5x5 的高斯核),即利用高斯平滑模板与原始数据作卷积,得到的图像与原始图像相比有些轻微的模糊(blurred)。这样,单独的一个像素噪声在经过高斯平滑的图像上变得几乎没有影响。

OpenCV图像边缘检测(Canny算法)

(2)计算梯度幅值和方向( x 和 y 方向上的卷积核)
  图像中的边缘可能会指向不同的方向,所以 Canny 算法使用 4 个 mask 检测水平、垂直以及对角线方向的边缘。原始图像与每个 mask 所作的卷积都存储起来。对于每个点我们都标识在这个点上的最大值以及生成的边缘的方向。这样我们就从原始图像生成了图像中每个点亮度梯度图以及亮度梯度的方向。

OpenCV图像边缘检测(Canny算法)

  角度方向近似为四个可能值,即 0, 45, 90, 135。
(3)对图像的梯度强度进行非极大抑制
  这一步排除非边缘像素, 仅仅保留了一些细线条(候选边缘)。
(4)利用双阈值检测和连接边缘
  较高的亮度梯度比较有可能是边缘,但是没有一个确切的值来限定多大的亮度梯度是边缘多大,所以 Canny 使用了滞后阈值。滞后阈值需要两个阈值——高阈值与低阈值。假设图像中的重要边缘都是连续的曲线,这样我们就可以跟踪给定曲线中模糊的部分,并且避免将没有组成曲线的噪声像素当成边缘。所以我们从一个较大的阈值开始,这将标识出我们比较确信的真实边缘,使用前面导出的方向信息,我们从这些真正的边缘开始在图像中跟踪整个的边缘。在跟踪的时候,我们使用一个较小的阈值,这样就可以跟踪曲线的模糊部分直到我们回到起点。
  若候选边缘点大于上阈值,则被保留;小于下阈值,则被舍弃;处于二者之间,须视其所连接的像素点。
2.3、OpenCV中Canny( )函数解析
  Canny( )函数在opencv中的方法如下:
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false)
下面 对每个参数进行解析:
  第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。
  第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和类型。
  第三个参数,double类型的threshold1,第一个滞后性阈值,即上阈值。
  第四个参数,double类型的threshold2,第二个滞后性阈值,即下阈值。
  第五个参数,int类型的apertureSize,表示应用Sobel算子的孔径大小,其有默认值3。
  第六个参数,bool类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false。
2.4、Canny算法实例
(1)代码

#include <opencv2/opencv.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<opencv2/imgproc/imgproc.hpp>  

using namespace cv;

int main()
{
    //载入原始图    
    Mat src = imread("1.jpg");    
    Mat src1 = src.clone();

    //显示原始图   
    imshow("【原始图】Canny边缘检测", src);

    //----------------------------------------------------------------------------------  
    //  一、最简单的canny用法,拿到原图后直接用。  
    //----------------------------------------------------------------------------------  
    Canny(src, src, 150, 100, 3);
    imshow("【效果图】Canny边缘检测", src);

    //----------------------------------------------------------------------------------  
    //  二、高阶的canny用法,转成灰度图,降噪,用canny,最后将得到的边缘作为掩码,拷贝原图到效果图上,得到彩色的边缘图  
    //----------------------------------------------------------------------------------  
    Mat dst, edge, gray;

    // 【1】创建与src同类型和大小的矩阵(dst)  
    dst.create(src1.size(), src1.type());

    // 【2】将原图像转换为灰度图像  
    cvtColor(src1, gray, CV_BGR2GRAY);

    // 【3】先用使用 3x3内核来降噪  
    blur(gray, edge, Size(3, 3));

    // 【4】运行Canny算子  
    Canny(edge, edge, 3, 9, 3);

    //【5】将g_dstImage内的所有元素设置为0   
    dst = Scalar::all(0);

    //【6】使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中  
    src1.copyTo(dst, edge);

    //【7】显示效果图   
    imshow("【效果图】Canny边缘检测2", dst);

    waitKey(0);

    return 0;
}

(2)运行效果图
原图:

OpenCV图像边缘检测(Canny算法)

初级边缘检测:

OpenCV图像边缘检测(Canny算法)

高级边缘检测:

OpenCV图像边缘检测(Canny算法)