边缘检测算子Canny原理概述并利用OpenCV的库函数Canny()对图像进行边缘检测[通俗易懂]

边缘检测算子Canny原理概述并利用OpenCV的库函数Canny()对图像进行边缘检测[通俗易懂]图像边缘检测的概念和大概原理可以参考我的另一篇博文,链接如下:https://blog.csdn.net/wenhao_ir/article/details/51743382本篇博文介绍边缘检测算子Canny,并利用OpenCV的库函数Canny()对图像进行边缘检测。Canny算子是JohnCanny在1986年发表的论文中首次提出的边缘检测算子,该算子检测性能比较好,应用广泛。Canny算法被推崇为当今最优的边缘检测的算法。Canny算子进行边缘检测的原理和步骤如下:⑴消除噪声。边缘

大家好,又见面了,我是你们的朋友全栈君。

图像边缘检测的概念和大概原理可以参考我的另一篇博文,链接如下:
https://blog.csdn.net/wenhao_ir/article/details/51743382

本篇博文介绍边缘检测算子Canny,并利用OpenCV的库函数Canny()对图像进行边缘检测。

Canny算子是John Canny在1986年发表的论文中首次提出的边缘检测算子,该算子检测性能比较好,应用广泛。Canny 算法被推崇为当今最优的边缘检测的算法。

Canny算子进行边缘检测的原理和步骤如下

⑴消除噪声。边缘检测的算法主要是基于图像强度的一阶和二阶微分操作,但导数通常对噪声很敏感,边缘检测算法常常需要根据图像源的数据进行预处理操作,因此采用滤波器来改善与噪声有关的边缘检测性能,比如在进行边缘检测前,可以对原始数据先作高斯滤波处理。如果不做滤波平滑处理,不仅是噪声,原图片中不是边缘但是灰度变化频率较高的部分也容易被认为是边缘,这样会导致边缘检测性能的下降。

⑵找到图片的强度梯度。在对图像进行平滑处理后,Canny边缘算法的第二步是找到图片的强度梯度。尽管“强度梯度”这个名词可能听起来很复杂,其实很简单,它是指边缘的方向。一条边实际上可以指向任何方向,但该算法只查看四个方向以简化事情。方向是水平、垂直和两个对角线方向。在数学中,我们将其写为 [0 ° , 90 ° , 45 ° , 135 ° ]。
OpenCV中的函数Canny()使用3×3 Sobel内核来确定水平方向的导数,然后将其转置以确定垂直方向的导数,这些导数可用于在所需的四个方向上找到我们的边缘。

⑶非极大值抑制。非极大值抑制的目的是剔除第⑵部中计算出来的结果中的大部分非边缘点。其原理是通过像素的八邻域来判断要不要将这个像素置为边缘点,如果不置为边缘点,那么就置为背景色。判断的方法如下:

①判断范围是像素的八邻域,所以是局部最优判断法;

②判断的标准是如果某个像素在其八邻域内,既是最大值,梯度值也最大,那么可判断该点为像素边缘点,否则就不是。具体判断的方法如下:

首先,梯度值的判断是很好判断的,用边缘检测微分算子得到的结果直接比较就可以了,但是最大值的判断可不是只比较其旁边的八个点哦,还要比较另外两个点,详情如下:

边缘检测算子Canny原理概述并利用OpenCV的库函数Canny()对图像进行边缘检测[通俗易懂]

如果已经判断出上图中的C点比其旁边的8个点的像素值都大,那么接下来判断上图中dTmp1和dTmp2的值是否也小于C点的值,那么dTmp1和dTmp2的值怎么求呢?上图中蓝色的线条方向为C点的梯度方向,由于是梯度方向,所以可以确定其局部的最大值肯定分布在这条线上,也即除了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。因此,判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点。如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。

⑷用滞后阈值算法求解图像边缘。上一步对边缘检测算子的结果进行了非极大值抑制,接下来我们用二值化的方法来求解图像边缘。单阈值处理边缘效果不好,所以Cannny算法中采用滞后阈值法求解。滞后阈值法需要设置一个高阈值和一个低阈值,解后按如下法则进行:

第一,如果某一像素位置的梯度幅值超过高阈值,则像素被保留为边缘像素;

第二,如果某一像素位置的梯度幅值小于低阈值,则像素被排除;

第三,如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。

在以上的法则中,推荐的高阈值与低阈值比在2:1到3:1之间。

通过消除噪声、计算梯度幅度与方向、非极大值抑制及用滞后阈值算法求解图像边缘四个步骤就可实现Canny边缘检测。

OpenCV提供了函数Canny()实现Canny算子,其原型如下:

void Canny( InputArray image, 
			OutputArray edges, 
			double threshold1, 
			double threshold2, 
			int apertureSize=3, 
			bool L2gradient=false 
		  )

Image—输入图像,要求是数据深度为8bit的图像,官方文档中并没有说输入图像必须为单通道,但很多资料上都说要求是单通道的图像。

edges—输出图像,单通道8bit的图像,尺寸与输入图像相同。

 threshold1—滞后阈值算法的低阈值;

 threshold2—滞后阈值算法的高阈值;

apertureSize—Sobel算子的大小,为什么是Sobel算子,请看上面对Canny算子描述的第二点。

L2gradient—是否使用L2范数来计算图像梯度幅值。

以下是使用函数Canny()实现图像边缘检测的示例代码:

代码中用

//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601

//OpenCV版本:3.0
//VS版本:2012

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
 
using namespace cv;
 
int main()
{
        //载入原始图    
        Mat src = imread("F:/material/images/P0042-building_edge_detection.jpg");  
        Mat src_1 = imread("F:/material/images/P0042-building_edge_detection.jpg", 0);
        Mat gray = imread("F:/material/images/P0042-building_edge_detection.jpg", 0);
 
        imshow("原图", src);
 
        //----------------------------------------------------------------------------------  
        //  一、最简单的canny用法,拿到原图的灰度图后直接用。  
        //----------------------------------------------------------------------------------  
        Canny(src_1, src_1, 100, 150, 3);
        imshow("简单用法的Canny边缘检测结果", src_1);
 
        //----------------------------------------------------------------------------------  
        //  二、高级的canny用法,转成灰度图,降噪,用canny,最后将得到的边缘作为掩码,拷贝原图到效果图上,得到彩色的边缘图  
        //----------------------------------------------------------------------------------  
        Mat dst, edge;
 
        // 【1】创建与src同类型和大小的矩阵(dst)  
        dst.create(gray.size(), gray.type());
 
        // 【2】先用使用 3x3内核来降噪  
        blur(gray, edge, Size(3, 3));
 
        // 【3】运行Canny算子  
        Canny(edge, edge, 100, 150, 3);
 
        imshow("高级用法的Canny边缘检测结果", edge);
 
        //【4】将g_dstImage内的所有元素设置为0   
        dst = Scalar::all(0);
 
        //【5】使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中  
        src.copyTo(dst, edge);
 
        //【6】显示效果图   
        imshow("高级用法的合成图", dst);
 
        waitKey(0);
 
        return 0;
}

运行结果如下图所示:

边缘检测算子Canny原理概述并利用OpenCV的库函数Canny()对图像进行边缘检测[通俗易懂]

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/139370.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • lnk2001 lnk1120_lnk1120

    lnk2001 lnk1120_lnk1120LNK2001..转自百度百科学习VC++时经常会遇到链接错误LNK2001,该错误非常讨厌,因为对于编程者来说,最好改的错误莫过于编译错误,而一般说来发生连接错误时,编译都已通过。产生连接错误的原因非常多,尤其LNK2001错误,常常使人不明其所以然。如果不深入地学习和理解VC++,要想改正连接错误LNK2001非常困难。  初学者在学习VC++的过程中,遇到的LNK20

    2022年10月5日
    0
  • tensorflow2.0 cnn(layerwise)

    实验环境:tensorflow版本1.2.0,python2.7介绍depthwise_conv2d来源于深度可分离卷积:Xception:DeepLearningwithDepthwiseSeparableConvolutionstf.nn.depthwise_conv2d(input,filter,strides,padding,rate=None,name=None,data_fo

    2022年4月16日
    38
  • python保存json格式_如何写json文件

    python保存json格式_如何写json文件Python小白之创建json文件做数据处理的时候需要用Python生成轨迹点的json文件,在百度上搜了一下Python如何创建json文件,第一页竟然都没有我想要的内容,大家都乱起标题么。。。真的对小白不友好,这里记录一下自己用的方法。我是从csv里面读出的dataframe,要取里面的经度和纬度两列的值,然后生成json文件,再在cesium上画出轨迹。要生成对应的json文件,先创建一个…

    2022年10月12日
    0
  • 国内IT公司速查手册

    国内IT公司速查手册可以看到网友们对国内IT公司的评价:)

    2022年7月1日
    23
  • 系统学习Pytorch笔记三:Pytorch数据读取机制(DataLoader)与图像预处理模块(transforms)

    系统学习Pytorch笔记三:Pytorch数据读取机制(DataLoader)与图像预处理模块(transforms)Pytorch官方英文文档:https://pytorch.org/docs/stable/torch.html?Pytorch中文文档:https://pytorch-cn.readthedocs.io/zh/latest/1.写在前面疫情在家的这段时间,想系统的学习一遍Pytorch基础知识,因为我发现虽然直接Pytorch实战上手比较快,但是关于一些内部的原理知识其实并不是太懂,这样…

    2022年4月28日
    48
  • vue+mongodb_mongodb开启auth认证

    vue+mongodb_mongodb开启auth认证刚刚安装完mongodb并且让这个mongodb安装成系统服务,然后给启动啦,以为自己这就可以像MySQL那样;安装好之后,配合可视化工具NavicatforMySQL简单的就跑起来了,但是呢,并不是这个样子。出bug啦,我暂且记录一下,正在找解决之法。UnabletofetchCollectionstatsInvalidcredentialsfordataba

    2022年8月21日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号