《opencv实用探索·十三》opencv之canny边缘检测

1、canny边缘检测应用场景

目标检测:
Canny边缘检测可以用于检测图像中的目标边缘,从而帮助识别和定位物体。在目标检测的流程中,边缘通常是检测的第一步。
图像分割:
Canny边缘检测可用于图像分割,即将图像划分为具有相似属性的区域。图像分割是许多计算机视觉任务的基础,如图像分析、物体识别等。
图像增强:
Canny边缘检测可以突出图像中的边缘特征,从而增强图像的结构信息。这对于图像处理任务,如图像重建和特征提取,非常有帮助。
边缘跟踪:
Canny边缘检测是一种强边缘跟踪器,可以用于跟踪图像中的曲线和边缘。
机器视觉和自动驾驶: 在机器视觉和自动驾驶系统中,Canny边缘检测可用于检测道路边缘、车辆和行人等物体。
医学图像处理:
在医学图像中,Canny边缘检测用于检测器官的边缘,从而协助医生进行诊断和手术规划。
光学字符识别(OCR):
在文字识别领域,Canny边缘检测可用于提取文本的边缘,以帮助进行光学字符识别。
图像分析:
Canny边缘检测在图像分析中是一种常见的工具,用于提取图像的重要特征。

2、canny边缘检测步骤
(1)噪声抑制:
在进行边缘检测之前,通常会对图像进行平滑以抑制噪声。这通常使用高斯滤波器来实现,可以通过cv::GaussianBlur函数完成。
(2)计算图像梯度:
使用Sobel算子计算图像在水平和垂直方向上的梯度。这个过程可以通过cv::Sobel函数实现。
(3)计算梯度的幅值和方向:
根据梯度的水平和垂直分量,计算梯度的幅值和方向。这可以通过cv::magnitude和cv::phase实现。
(4)非极大值抑制:
对梯度幅值图进行非极大值抑制,保留梯度方向上的局部最大值。这一步骤有助于细化边缘,使其更接近实际的边界。
(5)双阈值边缘跟踪:
根据设定的两个阈值(高阈值和低阈值),对非极大值抑制后的图像进行阈值处理,得到二值图像。高阈值用于确定强边缘,低阈值用于确定可能的边缘。通常,高阈值选取的较高,低阈值选取的较低。
(6)边缘连接:
对低阈值下的边缘像素进行连接,使其连接到高阈值下的边缘。这一步骤可以使用递归或迭代方法实现。

对于高斯滤波和梯度计算在之前的章节已经阐述过,请点击高斯滤波和梯度计算进行回顾。

这里解释下什么是梯度幅值和方向:
边缘检测算子返回水平方向的Gx和垂直方向的Gy。梯度的幅度𝐺和方向𝛩(用角度值表示)为:
在这里插入图片描述
式中,atan2(•)表示具有两个参数的 arctan 函数。

梯度幅值是梯度矢量的长度,表示图像在某一点的强度变化的大小,梯度的方向总是与边缘垂直的,通常就近取值为水平(左、右)、垂直(上、下)、对角线(右上、左上、左下、右下)等 8 个不同的方向。

因此,在计算梯度时,我们会得到梯度的幅度和角度(代表梯度的方向)两个值。

下图展示了梯度的表示法。其中,每一个梯度包含幅度和角度两个不同的值。为了方便观察,这里使用了可视化表示方法。例如,左上角顶点的值“2↑”实际上表示的是一个二元数对“(2, 90)”,表示梯度的幅度为 2,角度为 90°。
在这里插入图片描述

非极大值像素梯度抑制:
在具体实现时,逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点。如果当前像素点是周围像素点中最大值,我们保留该像素值,否则将其抑制为零。

例如A、B、C 三点具有相同的方向(梯度方向垂直于边缘)如下图。判断这三个点是否为各自的局部最大值:如果是,则保留该点;否则,抑制该点(归零)。
在这里插入图片描述
从图中可以看到A点在图像边缘,所以A 点具有最大的局部值,所以保留 A 点(称为边缘),其余两点(B和 C)被抑制(归零)。

再比如下图中,黑色背景的点都是向上方向梯度(边缘处于水平)的局部最大值。因此,这些点会被保留;其余点被抑制(处理为 0)。这意味着,这些黑色背景的点最终会被处理为边缘点,而其他点都被处理为非边缘点。
在这里插入图片描述
经过上述处理后,对于同一个方向的若干个边缘点,基本上仅保留了一个,使得检测到的边缘更狭窄,更接近实际的边界。

当完成非极大值抑制后,只保留了效果明显的边缘,然而,对于这些边缘,有些确实是图像的边缘,而有些却是由噪声产生的。之前用高斯滤波只是降噪,并不能消除噪声。而这些噪声造成的边缘被称为虚边缘,我们需要通过双值域将其消除。

双阈值设置:
首先设置两个阈值:高阈值(highThreshold)和低阈值(lowThreshold),高阈值用于确定强边缘,低阈值用于确定可能的边缘。对于所有的像素点,逐一遍历,如果当前边缘像素的梯度值 大于高阈值定为强边缘, 低于高阈值但是高于低阈值被定为虚边缘, 低于低阈值的像素点(抑制)置零。
所有的强边缘保留,而对于虚边缘,我们要做个判断。如果这些虚边缘是连接着强边缘的,那么保留,如果不是,那么抑制(置零)。

下面以一个示例图来说明。
图中Max和Min表示高低阈值,A在Max上面为强边缘直接保留,B在Max和Min之间为虚边缘,但B连着B,故也认定为边缘,保留。C也处于Max和Min之间,但C和A没有连接,故认定C不是边缘,被抑制。D之间小于低阈值,之间被抑制为0。

最后进行边缘连接,其过程如下:
(1)遍历经过非极大值抑制后的梯度幅值图像(图像经过非极大值抑制后只有边缘上的像素点的梯度幅值被保留,其他像素点的梯度幅值为零。)
(2)将大于高阈值的像素点标记为强边缘,高低阈值之间的像素值标记为弱边缘。
(3)从弱边缘像素出发,沿着其梯度方向前进,如果相邻像素中有强边缘像素(梯度幅值大于高阈值),则将其标记为强边缘,并继续追踪。追踪过程中,可能的边缘像素逐渐被标记为强边缘,形成一个连接的边缘。
(4)重复以上步骤,直到没有新的像素被添加到连接的边缘。最终,连接的边缘像素集合就是Canny边缘检测算法的输出。

3、opencv之canny接口调用

void cv::Canny(
    InputArray image,         // 输入图像(单通道8位灰度图像)
    OutputArray edges,         // 输出边缘图像
    double threshold1,        // 低阈值
    double threshold2,        // 高阈值
    int apertureSize = 3,      // Sobel算子核的大小,默认为3
    bool L2gradient = false    // 是否使用更精确的L2范数梯度计算,默认为false
);

双阈值怎么设定?

通常建议高阈值与低阈值的比例在2:1到3:1之间。
例如,如果设置高阈值为100,则低阈值可以设置为50或33。
根据图像特性:
可以根据图像的特性来调整阈值。如果图像中的边缘比较弱,可以适当降低阈值;如果图像中的边缘比较强,可以适当提高阈值。

参考代码:

int main() 
{  
    // 读取灰度图像
    cv::Mat image = cv::imread("1.jpg", cv::IMREAD_GRAYSCALE);

    // 检查图像是否成功读取
    if (image.empty()) {
        std::cerr << "Error: Could not read the image." << std::endl;
        return -1;
    }

    // 应用Canny边缘检测
    cv::Mat edges;
    double lowThreshold = 50;  // 低阈值
    double highThreshold = 150;  // 高阈值
    //高斯滤波去噪后检测图像边缘
    GaussianBlur(image, image, Size(3, 3), 0);
    cv::Canny(image, edges, lowThreshold, highThreshold);

    // 显示原始图像和Canny边缘检测的输出
    cv::imshow("Original Image", image);
    cv::imshow("Canny Edges", edges);
    // 等待用户按键
    cv::waitKey(0);

    return 0;
}

效果图如下:
左边是之间通过canny检测的边缘,右边是先通过高斯滤波去噪后再使用canny检测的边缘,可以明显的发现先去噪再检测边缘效果会更好。
在这里插入图片描述

参考文章:opencv基础44- Canny边缘检测详解-cv.Canny()

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

css 元素前后添加图标(::before 和 ::after 的妙用)

<template><div class"container"><div class"label">猜你喜欢</div></div> </template><style lang"scss" scoped> .label {display: flex;&::before,&::after {content: "";widt…

Python小案例:while练习题

目录 while练习题&#xff1a;1、存款多少年能翻倍2.小球坠落长度计算3、猴子吃桃4、计算&#xff1a;1-23-4...99-100的和 while练习题&#xff1a; 1、存款多少年能翻倍 1万本金&#xff0c;年利息&#xff1a;0.0325&#xff0c;求连本带息多少年能翻倍 解析&#xff1a;…

智能化与数字化:开展企业合规工作的新价值与方法

在现代商业环境中&#xff0c;企业合规成为了一项至关重要的任务。随着法规和监管标准的增加以及对企业道德和责任的更高要求&#xff0c;开展合规工作不仅有助于保护企业的声誉和利益&#xff0c;还能提升企业的竞争力和可持续发展。本文将探讨通过智能化和数字化手段开展合规…

领先英伟达的GPU1.6倍性能,AMD发布最强AI芯片Instinct MI300

AMD发布最强AI芯片 Instinct MI300X AI 加速器和 Instinct MI300A 数据中心 APU&#xff0c;声称比 Nvidia 的竞争 GPU 领先 1.6 倍。与 Nvidia 竞争产品相比&#xff0c;在以下几个关键方面展示了显著优势&#xff1a;配置方面 内存容量&#xff1a;MI300X&#xff1a;拥有 1…

系列学习前端之第 2 章:一文精通 HTML

全套学习 HTMLCSSJavaScript 代码和笔记请下载网盘的资料&#xff1a; 链接: https://pan.baidu.com/s/1-vY2anBdrsBSwDZfALZ6FQ 提取码: 6666 HTML 全称&#xff1a;HyperText Markup Language&#xff08;超文本标记语言&#xff09; 1、 HTML 标签 1. 标签又称元素&#…

系列学习前端之第 3 章:一文精通 css

全套学习 HTMLCSSJavaScript 代码和笔记请下载网盘的资料&#xff1a; 链接: 百度网盘 请输入提取码 提取码: 6666 一、CSS基础 1. CSS简介 CSS 的全称为&#xff1a;层叠样式表 ( Cascading Style Sheets ) 。 CSS 也是一种标记语言&#xff0c;用于给 HTML 结构设…

欧洲原料药认证注册信息查询方法-CEP数据库

欧盟是全球最大、最重要的药品国际市场之一&#xff0c;药品需求市场非常庞大。中国药企要进入欧盟市场&#xff0c;必须获得CEP认证。 CEP认证与COS认证等同&#xff0c;均代表欧洲药典适应性证书 COS&#xff08;Certificate of Suitability&#xff09;是指欧洲药典适用性认…

NVRAM相关

1. Modem NVRAM四个分区 nvdata&#xff1a;手机运行过程中&#xff0c;使用(读写)的NVRAM(除了存在protect_f和protect_s中的NVRAM)都是该分区的nvram文件。存储着普通NVRAM数据、 IMEI、barcode、Calibration数据等。对应的modem path是Z:\NVRAM。NVRAM目录下有CALIBRAT、NVD…

window环境下使用nginx部署多个项目(详细)

在官网下载相应版本的nginx安装包&#xff0c;链接如下&#xff1a;nginx: download 下载压缩包之后找一个目录解压就行了&#xff0c;我这里放在 D:\Program Files (x86) 目录下。 可以直接双击nginx.exe 本地启动nginx服务器。但是更推荐使用命令行&#xff1a;在这个目录下c…

「神印王座」萝莉女神小六打劫,白送10万功勋点,王原原恋人登场

Hello,小伙伴们&#xff0c;我是拾荒君。 备受瞩目的《神印王座》第84集终于更新了。更新后&#xff0c;拾荒君也是迫不及待地观看了一番。在本集中&#xff0c;龙皓晨率领的光之晨曦猎魔团在成功完成一项王级任务后&#xff0c;每个成员都获得了丰厚的功勋点。然而&#xff0…

[⑦ADRV902x]: JESD204学习笔记

前言 JESD204B/C基于SERDES&#xff08;SERialization/DESerialization&#xff09;技术&#xff0c;也就是串化和解串&#xff0c;在发送端将多位并行的数据转换为1 bit的串行数据&#xff0c;在接收端将串行数据恢复成原始的并行数据。 在JESD204接口出现以前&#xff0c;数…

Java程序员,你掌握了多线程吗?【文末送书】

目录 摘要 01、多线程对于Java的意义 02、为什么Java工程师必须掌握多线程 03、Java多线程使用方式 04、如何学好Java多线程 参与方式&#x1f947; 推荐一个人工智能学习网站 https://www.captainbed.cn/bear 摘要 互联网的每一个角落&#xff0c;无论是大型电商平台的…

亚马逊自养号测评和真人测评的区别,优劣剖析

大家都知道亚马逊的review对产品listing曝光和流量是有很大影响&#xff0c;但是亚马逊的review又不是那么容易获取的&#xff0c;再加上亚马逊平台风控的不断严苛&#xff0c;所以卖家们想尽办法打造爆款listing是每个亚马逊卖家共同的目标&#xff0c;尤其是当旺季到来时&…

0基础学习云计算难吗?

很多人经常会问云计算是什么&#xff1f;云计算能干什么&#xff1f;学习云计算能做什么工作&#xff1f;其实我们有很多人并不知道云计算是什么&#xff0c;小知今天来给大家讲讲学习云计算能做什么。 中国的云计算行业目前正处于快速发展阶段&#xff0c;随着互联网和数字化…

部署springboot项目到GKE(Google Kubernetes Engine)

GKE是 Google Cloud Platform 提供的托管 Kubernetes 服务&#xff0c;允许用户在 Google 的基础设施上部署、管理和扩展容器。本文介绍如何部署一个简单的springboot项目到GKE. 本文使用podman. 如果你用的是docker, 只需要把本文中所有命令中的podman替换成docker即可 非H…

工作中的疑难杂症(编译ninja failed with: exit status 137)

问题&#xff1a;先来看报错提示 起初出现这个问题我就搜索了一下&#xff0c;大家都说。 此问题是因为asop/build/soong/java/config/config.go文件内定义了pctx.StaticVariable("JavacHeapSize", "2048M")&#xff0c;javaheap的大小与ubuntu18系统的内…

网络通信的流程,浏览器地址?

1.没有交换机的通信 在一个机房内,有两台电脑相互需要通信 假设现在有三台电脑: 随着电脑的增加,线的数量也在增加,因此显得很臃肿&#xff0c;次数交换机诞生&#xff0c;很好的解决了这一方面&#xff0c; 交换机不需要进行多条线的连接: 通过给设备分配,ip地址来实现局域网…

C语言内存函数讲解

目录 文章目录 内存函数针对的数据类型不确定可能是整型数据&#xff0c;字符数据&#xff0c;结构体数据...... memcpy的使用和模拟实现 memcpy的使用 memcpy打印字符数据 memcpy打印整型数据 memcpy的模拟实现 模拟实现的memcpy打印重叠情境 memmove的使用和模拟实现 memm…

【HarmonyOS开发】DevEco Studio安装及其配置

目录 前言下载工具准备开始安装配置开始新建一个项目 前言 DevEco Studio是一款用于开发HarmonyOS应用的集成开发环境&#xff0c;在安装DevEco Studio的时候&#xff0c;可能会在安装或者配置的时候出现各种各样的小问题&#xff0c;在此做下记录。 下载工具准备 官网下载地…

详解线段树

前段时间写过一篇关于树状数组的博客树状数组&#xff0c;今天我们要介绍的是线段树&#xff0c;线段树比树状数组中的应用场景更加的广泛。这些问题也是在leetcode 11月的每日一题频繁遇到的问题&#xff0c;实际上线段树就和红黑树 、堆一样是一类模板&#xff0c;但是标准库…