OpenCV 如何实现边缘检测器

news2024/11/18 15:27:05

返回: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 image
     
     if( 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 image
 
 if( 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.coloradmin.cn/o/1621110.html

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

相关文章

基于RK3588的全国产鸿蒙边缘计算工控机在智能交通ETC收费系统的应用

1.1 产品简介 基于智能交通、工业互联等行业快速智能化发展的需求&#xff0c;以 OpenHarmony 为框架开发嵌入 HamonyOS&#xff0c;打造了具有高智能、高可靠、高安全的自主 可控的边缘处理器 XM-RK3588。 图 1-1 边缘处理器 HamonyOS强化 IoT 互联互动能力&#xff0c;让边缘…

【JAVA基础之IO】字节流、字符流以及乱码问题

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 目录 1. IO概述 1.1 什么是IO 1.2 IO的分类 1.3 字节和字符流的顶级父类 2. 字节流 2.1 一切皆为字节 2.2 字节输出流【OutputStream】 2.3 FileOutputStream类…

【Python】自定义修改pip下载模块默认的安装路径

因为电脑下载了Anaconda提供的默认Python 3.9 以及后期下载的python3.10所以在Pychram进行项目开发时&#xff0c;发现一些库怎么导入都导入不了&#xff0c;手动install也是失败&#xff0c;后期在cmd里面发现python以及pip配置有点儿混乱&#xff0c;导致执行命令时&#xff…

学习c语音的自我感受

因为是自学&#xff0c;所以走过不少弯路。去年&#xff0c;受知乎“python性能弱”风潮的影响&#xff0c;学过go,rust。 在学习这些新语言的时候&#xff0c;由衷感受到&#xff0c;或是本身侧重方向的原因&#xff08;如go侧重服务器&#xff09;&#xff0c;或是语言太新不…

01-服务与服务间的通信

这里是极简版&#xff0c;仅用作记录 概述 前端和后端可以使用axios等进行http请求 服务和服务之间也是可以进行http请求的spring封装的RestTemplate可以进行请求 用法 使用bean注解进行依赖注入 在需要的地方&#xff0c;自动注入RestTemplate进行服务和服务之间的通信 注…

探索React Router:实现动态二级路由

我有一个路由配置的二维数组&#xff0c;想根据这个数组结合路由组件来动态生成路由&#xff0c;应该怎么样实现。在 React Router 6 中渲染二级路由的方式跟 React Router 65相比有一些变化,但核心思路仍然是利用 Route 组件和路由嵌套的方式。下面是具体的步骤: 定义路由数组…

C系统编程:从零手搓一个shell

背景 这么久没更新就是在干这件事&#xff01;&#xff01;因为系统编程已经学的差不多了&#xff0c;所以想找几个项目练练手&#xff0c;之前就一直想写一个自己的shell&#xff01;&#xff01;现在终于有机会实现了。 首先说明一下我的操作系统&#xff1a;Arch linux 服务…

C++ - STL详解(七)— stack和queue的介绍及使用

目录 一. stack 1.1 stack的介绍 1.2 stack的定义 1.3 stack的使用 ​编辑 二. queue 2.1 queue的介绍 2.2 queue的定义 2.3 queue的使用 一. stack 1.1 stack的介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除…

redis底层数据结构之ziplist

目录 一、概述二、ziplist结构三、Entry结构四、为什么ZipList特别省内存五、ziplist的缺点 redis底层数据结构已完结&#x1f44f;&#x1f44f;&#x1f44f;&#xff1a; ☑️redis底层数据结构之SDS☑️redis底层数据结构之ziplist☑️redis底层数据结构之quicklist☑️red…

ETL工具-nifi干货系列 第十六讲 nifi Process Group实战教程,一文轻松搞定

1、目前nifi系列已经更新了10多篇教程了&#xff0c;跟着教程走的同学应该已经对nifi有了初步的解&#xff0c;但是我相信同学们应该有一个疑问&#xff1a;nifi设计好的数据流列表在哪里&#xff1f;如何同时运行多个数据流&#xff1f;如启停单个数据流&#xff1f; 带着这些…

第二期书生浦语大模型训练营第四次笔记

大模型微调技术 大模型微调是一种通过在预训练模型的基础上&#xff0c;有针对性地微调部分参数以适应特定任务需求的方法。 微调预训练模型的方法 微调所有层&#xff1a;将预训练模型的所有层都参与微调&#xff0c;以适应新的任务。 微调顶层&#xff1a;只微调预训练模型…

Pandas数据分析小技巧

Pandas数据分析小技巧&#xff1a;提升数据处理效率与准确性的秘诀 Pandas是一个强大的Python数据分析库&#xff0c;它提供了快速、灵活且富有表现力的数据结构&#xff0c;使得数据清洗、转换、分析等操作变得简单而高效。本文将介绍一些Pandas数据分析的小技巧&#xff0c;…

年如何在不丢失数据的情况下解锁锁定的 Android 手机?

当您忘记密码、PIN 码或图案并且想要解锁 Android 手机时&#xff0c;您可能会丢失 Android 手机上的数据。但您无需再担心&#xff0c;因为在这里&#xff0c;我们想出了几种解锁锁定的 Android 手机而不丢失数据的方法。 方法 1. 使用 Android Unlock 解锁锁定的 Android 且不…

【上海大学计算机组成原理实验报告】四、指令系统实验

一、实验目的 了解指令结构、PC寄存器的功能和指令系统的基本工作原理。 学习设计指令的方法。 二、实验原理 根据实验指导书的相关内容&#xff0c;对于部分使用频率很高&#xff0c;且只用几条微指令即可完成的简单操作&#xff0c;可以把这部分简单操作的微指令序列固定下…

mfc140.dll丢失如何修复,分享多种有效的修复方法

在日常操作和使用电脑的过程中&#xff0c;我们可能会遇到一种较为常见的问题&#xff0c;即在尝试启动或运行某个应用程序时&#xff0c;系统突然弹出一个错误提示窗口&#xff0c;明确指出“mfc140.dll文件丢失”。这个mfc140.dll实际上是一个动态链接库文件&#xff08;DLL&…

linux运行ant 报错 Unable to locate tools.jar【已解决】

linux安装 ant 运行时报错 Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/lib/tools.jar 原因 已安装的jdk只有运行环境&#xff0c;没有tool.jar&#xff0c;而ant运行需要java开发环境&#xff0c;因…

不可思议!我的AI有道英语字典助手竟然与百度千帆AI应用创意挑战赛K12教育主题赛榜首作品差之毫厘

目录 一、前言二、效果对比三、优化《AI英语词典》提示词四、其他获奖作品链接 一、前言 今天看百度千帆AI原生应用创意挑战赛——K12教育主题赛&#xff0c;发现第一名的《我爱记单词》和我早两天发布的一篇《AI英语词典》的想法不谋而合。当时我们应该都是互相不知道对方的&a…

软件游戏缺失d3dcompiler_43.dll怎么修复?分享多种靠谱的解决方法

在我们日常频繁地操作和使用电脑的过程中&#xff0c;时常会遇到一些突发的技术问题。其中一种常见的情况是&#xff0c;在尝试启动或运行某个应用程序时&#xff0c;系统会弹出一个错误提示窗口&#xff0c;明确指出当前电脑环境中缺少了一个至关重要的动态链接库文件——d3dc…

Mysql全局优化总结

Mysql全局优化总结 从上图可以看出SQL及索引的优化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我们要在这块花更多时间 服务端系统参数 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_connections…

【MATLAB源码-第197期】基于matlab的粒子群算法(PSO)结合人工蜂群算法(ABC)无人机联合卡车配送仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于粒子群优化&#xff08;PSO&#xff09;算法的无人机联合卡车配送系统是一个高效的物流配送策略&#xff0c;旨在优化配送过程中的成本、时间和资源利用率。该系统融合了无人机和卡车的配送能力&#xff0c;通过智能算法…