边缘检测算子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)
上一篇 2022年5月29日 下午10:16
下一篇 2022年5月29日 下午10:36


相关推荐

  • gamma correction什么意思_伽马校正计算方法

    gamma correction什么意思_伽马校正计算方法伽马是数字成像系统的一个重要特征,它定义了像素值与其实际亮度之间的关系。在标准显示器上面,如果没有伽马,数码相机拍摄到的阴影内容便会跟我们实际看到的有所差异。平时我们所说的伽马校正、伽马编码、伽马压缩,都是伽马曲线的各种应用场景,属于相似的概念。对于伽马工作原理的理解,一方面可以提高摄影者的曝光技术,另一方面可以帮助人们更好地利用后期的图像编辑功能。

    2026年3月4日
    3
  • 国产AI大模型全解析[项目代码]

    国产AI大模型全解析[项目代码]

    2026年3月14日
    2
  • SSM整合Activiti工作流[通俗易懂]

    SSM整合Activiti工作流[通俗易懂]学完Activiti所有的知识点了,现在可以用一个小项目实战一下。本来自己想写一个简单点的流程,但是发现项目太小有些知识点用不上,所有就写了一个流程比较长、复杂点。把我前面博客中写的知识点多用上了,也巩固一下前面所掌握的。通过首先介绍一下项目的流程:1.员工发起请假申请——>项目组长进行初步审批——>就进入并行网关未通过就直接结束流程2.并行网关:…

    2022年5月3日
    54
  • css控制滚动条透明,CSS控制滚动条样式的解析

    我们在之前的两篇文章中,我们给大家介绍了关于CSS设置div滚动条样式、以及CSS3自定义滚动条样式的实例,都知道当内容超出容器时,容器会出现滚动条,那我们如何使用CSS控制滚动条样式的呢?今天就给大家详细介绍!例子:/*作为IT界最前端的技术达人,页面上的每一个元素的样式我们都必须较真,就是滚动条我们也不会忽略。下面我给大家分享一下如何通过CSS来控制滚动条的样式,代码如下:*//*定义滚动条…

    2022年4月8日
    137
  • idea切换到远程分支_git看不到远程分支

    idea切换到远程分支_git看不到远程分支描述最近项目建了分支,在并行开发,需要切换远程分支,在网上找了很多资料都不行。远程分支代码始终更新的是其他分支。解决方案话不多说,直接看图。操作上述之后,开始pull下远程代码,完毕后也可发现分支发生变化说明以上只在2016.1.3上验证。

    2026年2月8日
    10
  • 高级编程之 socker编程

    高级编程之 socker编程1 网络基础 1 1 IP 地址 1 1 1 目的 用来标记网络上的一台电脑 1 1 2 如何查看 IPwindow ifconfigLinu ipconfig1 1 3 IP 地址分类 1 1 3 1 IPV4 被广泛使用的 IP 协议的版本号是 4 当前再用 目前被广泛应用 IPv4 的地址位数为 32 位 4 位字节 地址有限 几乎全部耗尽 1 1 3 2 IPV6

    2026年3月16日
    2

发表回复

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

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