OpenCV 如何实现边缘检测器

返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV如何实现拉普拉斯算子的离散模拟
下一篇 :OpenCV系列文章目录(持续更新中......)

目标

在本教程中,您将学习如何:

  • 使用 OpenCV 函数 cv::Canny 实现 Canny 边缘检测器。

理论

Canny Edge探测器[48]由John F. Canny于1986年开发。Canny 算法也被许多人称为最佳检测器,旨在满足三个主要标准:

  • 低错误率:这意味着仅对现有边缘的良好检测。
  • 良好的本地化:必须最小化检测到的边缘像素与实际边缘像素之间的距离。
  • 最小响应:每个边沿只有一个检测器响应。

步骤

  1. 过滤掉任何噪音。高斯滤波器用于此目的。可能使用的(size = 5)高斯核示例如下所示:

  1. 找到图像的强度渐变。为此,我们遵循类似于 Sobel 的过程:

 a).应用一对卷积掩码在 x 和y 方向上:

 

​编辑 

 b).通过以下方式找到梯度强度和方向::

​编辑

  1. 方向四舍五入为四个可能的角度之一(即 0、45、90 或 135)
  2. 应用非最大抑制。这将删除不被视为边的一部分的像素。因此,将只保留细线(候选边)。
  3. 滞后:最后一步。Canny 确实使用两个阈值(上限和下限):

    1. 如果像素渐变高于上限阈值,则该像素被接受为边缘
    2. 如果像素渐变值低于限阈值,则将拒绝该值。
    3. 如果像素渐变介于两个阈值之间,则仅当它连接到高于上限阈值的像素时,才会被接受。

    Canny 建议在 2:1 和 3:1 之间使用上比例。

  4. 有关更多详细信息,您可以随时查阅您最喜欢的计算机视觉书籍。

1、C++代码演示:

  • 教程代码如下所示。您也可以从这里下载
    #include "opencv2/imgproc.hpp"
    #include "opencv2/highgui.hpp"
    #include <iostream>using namespace cv;Mat src, src_gray;
    Mat dst, detected_edges;int lowThreshold = 0;
    const int max_lowThreshold = 100;
    const int ratio = 3;
    const int kernel_size = 3;
    const char* window_name = "Edge Map";static void CannyThreshold(int, void*)
    {blur( src_gray, detected_edges, Size(3,3) );Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );
    }int main( int argc, char** argv )
    {CommandLineParser parser( argc, argv, "{@input | fruits.jpg | input image}" );src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR ); // Load an imageif( src.empty() ){std::cout << "Could not open or find the image!\n" << std::endl;std::cout << "Usage: " << argv[0] << " <Input image>" << std::endl;return -1;}dst.create( src.size(), src.type() );cvtColor( src, src_gray, COLOR_BGR2GRAY );namedWindow( window_name, WINDOW_AUTOSIZE );createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );CannyThreshold(0, 0);waitKey(0);return 0;
    }

  • 这个程序是做什么的?
    • 要求用户输入一个数值来设置我们的 Canny Edge Detector 的下限阈值(通过跟踪栏)。
    • 应用 Canny Detector 并生成蒙版(亮线表示黑色背景上的边缘)。
    • 应用在原始图像上获取的蒙版并将其显示在窗口中。

 创建一些需要的变量:

 2、说明(C++ 代码)

Mat src, src_gray;
Mat dst, detected_edges;int lowThreshold = 0;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
const char* window_name = "Edge Map";

  1. 请注意以下事项:

    1. 我们建立了 3:1 的下限:上限阈值(具有可变比率)。
    2. 我们将内核大小设置为 (用于由 Canny 函数在内部执行的 Sobel 操作)。3
    3. 我们为 的下限阈值设置了最大值。100
  2. 加载源图像:
 CommandLineParser parser( argc, argv, "{@input | fruits.jpg | input image}" );src = i mread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR ); // Load an imageif( src.empty() ){std::cout << "Could not open or find the image!\n" << std::endl;std::cout << "Usage: " << argv[0] << " <Input image>" << std::endl;return -1;}

  1. 创建一个与 src 类型和大小相同的矩阵(待 dst):
     dst.create( src.size(), src.type() );

  2. 将图像转换为灰度(使用函数 cv::cvtColor ):
     cvtColor( src, src_gray, COLOR_BGR2GRAY );

  3. 创建一个窗口来显示结果:
     namedWindow( window_name, WINDOW_AUTOSIZE );

  4. 为用户创建一个跟踪栏,以输入我们的 Canny 检测器的下限:
     createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );

  5. 请注意以下事项:
    1. 要由 Trackbar 控制的变量是 lowThreshold,限制为 max_lowThreshold(我们之前将其设置为 100)
    2. 每次 Trackbar 注册操作时,都会调用回调函数 CannyThreshold
  6. 让我们一步一步地检查 CannyThreshold 函数:

 a、首先,我们用内核大小为 3 的过滤器对图像进行模糊处理

 blur( src_gray, detected_edges, Size(3,3) );

 b、其次,我们应用 OpenCV 函数 cv::Canny 

 Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
  1. 其中参数为:
    • detected_edges:源图像、灰度
    • detected_edges:检测器输出(可与输入相同)
    • lowThreshold:用户移动跟踪栏时输入的值
    • highThreshold:在程序中设置为下限的三倍(遵循 Canny 的建议)
    • kernel_size:我们将其定义为 3(内部使用的 Sobel 内核的大小)

7、我们用零填充目标图像(表示图像完全是黑色的)。

 dst = Scalar::all(0);

8、最后,我们将使用函数 cv::Mat::copyTo 仅映射图像中标识为边缘的区域(在黑色背景上)。cv::Mat::copy将 src 映像复制到 dst 上。但是,它只会复制像素具有非零值的位置。由于 Canny 检测器的输出是黑色背景上的边缘轮廓,因此生成的 dst 在除检测到的边缘之外的所有区域都将是黑色的。

 src.copyTo( dst, detected_edges);

9、我们显示我们的结果

 imshow( window_name, dst );

结果

  • 编译上面的代码后,我们可以运行它,将图像的路径作为参数。例如,使用以下图像作为输入:

  • 移动滑块,尝试不同的阈值,我们得到以下结果:

​请注意图像如何叠加到边缘区域的黑色背景上。


参考文献:

1、《Canny Edge Detector》---Ana Huamán

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/2859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

测试用例设计方法-异常测试

飞的最高的海鸥&#xff0c;能看到最远的奇景。大家好&#xff0c;继续给大家分享如何进行异常测试&#xff0c;首先要做好异常测试&#xff0c;需要我们对被测系统进行全面的了解&#xff0c;熟悉被测系统的功能、架构和运行机制&#xff0c;然后在这个基础上尽可能覆盖各种的…

MATLAB命令

MATLAB是一个用于数值计算和数据可视化的交互式程序。您可以通过在命令窗口的MATLAB提示符 ‘>>’ 处键入命令来输入命令。 在本节中&#xff0c;我们将提供常用的通用MATLAB命令列表。 用于管理会话的命令 MATLAB提供了用于管理会话的各种命令。下表提供了所有此类命令…

递归神经网络(RNN)在AI去衣技术中的深度应用

在人工智能&#xff08;AI&#xff09;技术飞速发展的今天&#xff0c;图像处理和计算机视觉领域不断取得新的突破。其中&#xff0c;AI去衣技术作为一个具有挑战性的研究方向&#xff0c;引起了广大研究者和公众的关注。递归神经网络&#xff08;RNN&#xff09;作为深度学习的…

《Python源码剖析》之PyTypeObject

前言 这一篇博客原本应该是写在上一篇关于pyObject对象的博客中的&#xff0c;但是为了不把内容写的又臭又长&#xff0c;给读者减轻痛苦&#xff0c;给我也减少压力&#xff0c;于是就专门用一篇介绍一下今天的主角—pyTypeObject。 开始 还记得在上一篇我们有聊到&#xf…

vscode 使用文件模板功能来添加版权信息

vscode 新建文件的时候&#xff0c;自动填充作者及版权信息 无需使用插件&#xff0c;操作如下&#xff1a; 选择 “首选项(Preferences)”。在搜索框中输入 “file template” 或者 “文件模板”&#xff0c;然后选择相关的设置项。 {"C_Cpp.clang_format_fallbackSt…

嵌入式虽然入门容易,但精通难度很大。

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;此外&#xff0c;嵌入式系统的…

蓝桥杯——分巧克力

思路非常简单&#xff0c;就是一个二分法。 注意一下l和r的取值&#xff0c;就可以了。 // 如何进行切分巧克力&#xff1a;横纵除法。例如&#xff1a;一块6*5的&#xff0c;欲切为3*3的小块&#xff0c;横&#xff1a;6/2 3&#xff1b;纵&#xff1a;5/31.所以可以切成3*…

职业技能鉴定服务中心(新闻系统+证书查询系统)

后端采用ThinkPHP8&#xff0c;最新tp框架 前端采用divcss布局 数据库采用MySQL 采用三种技术实现新闻系统和证书查询系统 源码&#xff1a;git clone https://gitee.com/3539949703/certificate-website.git 效果图如下&#xff1a;

[Linux_IMX6ULL驱动开发]-设备树简述

目录 设备树的引入 设备树具体框架 设备树的属性 label address-cells和size-cells compatible model status reg 设备树的编译 内核对设备树的处理 plateform_device如何对应plateform_driver 设备树的引入 之前已经学习了解过了总线驱动模型的概念&#xff0c;也…

webots学习记录8:R2023b如何在某个零件上添加一个恒定的力(矩)

在webots安装路径下&#xff0c;从include\controller\c\webots\supervisor.h中可以看到如下定义&#xff1a; void wb_supervisor_node_add_force(WbNodeRef node, const double force[3], bool relative); void wb_supervisor_node_add_force_with_offset(WbNodeRef node, c…

37-5 基于时间的盲注 SQL 注入 PoC 的 Python 编写

攻击目标就用sql靶场的第9关,手注与靶场搭建:22-5 SQL注入攻击 - 基于时间的盲注-CSDN博客 poc import concurrent.futures # 导入并发模块 import requests # 导入发送HTTP请求的库 import string # 导入处理字符串的库url = "http://127.0.0.1/sqli-labs-master…

AndroidStudio中虚拟机(AVD)无法启动,出现unable to locate adb错误

1.检查Android SDK Platform-Tools是否安装(个人是通过这个方法解决的) 首先通过File-Project Structure-Project SDK检查SDK有没有被选中 步骤&#xff1a;打开file -> settings &#xff0c;搜索SDK 之后点击"-",在点击Apply进行安装 2.可能是驱动的问题 电脑…

深入解析YOLOv2

深入解析YOLOv2 引言 目标检测是计算机视觉中的一个核心问题&#xff0c;它旨在识别图像中所有感兴趣的目标&#xff0c;并给出它们的类别和位置。近年来&#xff0c;随着深度学习技术的发展&#xff0c;目标检测领域取得了巨大的进步。YOLO&#xff08;You Only Look Once&a…

基于OSAL 实现UART、LED、ADC等基础示例 4

1 UART 实验目的 串口在我们开发单片机项目是很重要的&#xff0c;可以观察我们的代码运行情况&#xff0c;本节的目的就 是实现串口双工收发。 虽然说 osal 相关的代码已经跟硬件关系不大了&#xff0c;但是我们还是来贴出相关的硬件原理图贴出来。 1.1 初始化 osal_init_s…

交换式网络捕获网络流量的方法

交换式网络捕获网络流量的方法 参考资料&#xff1a; https://blog.csdn.net/weixin_44143678/article/details/107559329 # 一.端口镜像 端口镜像&#xff0c;又称为“端口监视”或“端口抄送”&#xff0c;是一种网络管理技术&#xff0c;旨在将网络设备上的特定端口的流…

PyTorch Conv2d 前向传递中发生了什么?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Springboot的日常操作技巧

文章目录 1、自定义横幅2、容器刷新后触发方法自定义3、容器启动后触发方法自定义**CommandLineRunner**ApplicationRunner 不定时增加 参考文章 1、自定义横幅 简单就一点你需要把banner.text放到classpath 路径下 &#xff0c;默认它会找叫做banner的文件&#xff0c;各种格式…

spring的bean创建流程源码解析

文章目录 IOC 和 DIBeanFactoryApplicationContext实现的接口1、BeanFactory接口2、MessageSource 国际化接口3、ResourcePatternResolver&#xff0c;资源解析接口4、EnvironmentCapable接口&#xff0c;用于获取环境变量&#xff0c;配置信息5、ApplicationEventPublisher 事…

使用扩展卡尔曼滤波器进行包裹测量的状态估计

此示例说明如何使用扩展卡尔曼滤波器算法对涉及圆形包裹角度测量的 3D 跟踪进行非线性状态估计。对于目标跟踪&#xff0c;传感器通常采用球形框架来报告物体的方位角、距离和仰角位置。该组的角度测量值在一定范围内报告。例如&#xff0c;报告的方位角范围为- 180∘ 到180∘或…

UE5 GAS开发P34 游戏效果理论

GameplayEffects Attributes&#xff08;属性&#xff09;和Gameplay Tags&#xff08;游戏标签&#xff09;分别代表游戏中实体的特性和标识。 Attributes&#xff08;属性&#xff09;&#xff1a;Attributes是用来表示游戏中实体的特性或属性的值&#xff0c;例如生命值、…