OpenCV 如何实现边缘检测器

2024-04-24 23:36
文章标签 实现 opencv 边缘 检测器

本文主要是介绍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

这篇关于OpenCV 如何实现边缘检测器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/933146

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

vcpkg安装opencv中的特殊问题记录(无法找到opencv_corexd.dll)

我是按照网上的vcpkg安装opencv方法进行的(比如这篇:从0开始在visual studio上安装opencv(超详细,针对小白)),但是中间出现了一些别人没有遇到的问题,虽然原因没有找到,但是本人给出一些暂时的解决办法: 问题1: 我在安装库命令行使用的是 .\vcpkg.exe install opencv 我的电脑是x64,vcpkg在这条命令后默认下载的也是opencv2:x6

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

亮相WOT全球技术创新大会,揭秘火山引擎边缘容器技术在泛CDN场景的应用与实践

2024年6月21日-22日,51CTO“WOT全球技术创新大会2024”在北京举办。火山引擎边缘计算架构师李志明受邀参与,以“边缘容器技术在泛CDN场景的应用和实践”为主题,与多位行业资深专家,共同探讨泛CDN行业技术架构以及云原生与边缘计算的发展和展望。 火山引擎边缘计算架构师李志明表示:为更好地解决传统泛CDN类业务运行中的问题,火山引擎边缘容器团队参考行业做法,结合实践经验,打造火山

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页:

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

python实现最简单循环神经网络(RNNs)

Recurrent Neural Networks(RNNs) 的模型: 上图中红色部分是输入向量。文本、单词、数据都是输入,在网络里都以向量的形式进行表示。 绿色部分是隐藏向量。是加工处理过程。 蓝色部分是输出向量。 python代码表示如下: rnn = RNN()y = rnn.step(x) # x为输入向量,y为输出向量 RNNs神经网络由神经元组成, python