计算机视觉全系列实战教程:(十一)边缘检测(差分、Roberts、Sobel、Prewitt、LoG、基于形态学的边缘检测等)

1.边缘检测概述

(1)What

  • 边缘检测:找到有差异的相邻像素
  • 锐度:边缘的对比度
  • 图像锐化:增加边缘的对比度
  • 边缘点:图像中灰度显著变化的点
  • 边缘段:边缘点坐标及方向的总和,边缘的方向可以是梯度角
  • 轮廓:边缘列表
  • 边缘检测器:抽取边缘的算法
  • 边缘连接:从无序边缘形成有序边缘的过程
  • 边缘跟踪:确定轮廓图像的搜索过程

(2)How(边缘检测的一般步骤)

  • A.图像获取:将获取的图像转化为灰度图像,进而进行边缘检测操作
  • B.图像去噪:使用滤波器来改善与噪音有关的边缘检测器的性能
  • C.图像增强:突出邻域强度的变化值
  • D.图像检测:计算图像的梯度,根据阈值进行调整
  • E.图像定位:得到单像素的二值边缘图像

(3)Why(边缘检测的目标)

  • 边缘定位精度高,单像素
  • 对噪声不敏感
  • 检测的灵敏度受方向影响小

2.经典的边缘检测算法

(1)梯度基本介绍

在多维连续函数z=f(x,y)中,函数在任一点P=(x,y)的梯度为函数f(x,y)对每个维度的分量[x,y]分别进行偏微分组成的向量,该向量即为函数z=f(x,y)在P=(x,y)处的梯度。

(2)差分边缘检测

x方向上的一阶差分:f(x+1, y) - f(x, y)
y方向上的一阶差分:f(x, y+1) - f(x, y)
二阶差分:在一阶差分的基础上再进行一次差分操作
以下是本人利用一阶差分编写的提取图像边缘的算法,供大家参考,该函数提供x方向,y方向和对角方向上的一阶差分运行以提取图像边缘

/*@author: @还下着雨ZG
* @brief 一阶差分运算提取图像边缘
* @param[in], imSrc, 待提取边缘的图像
* @param[out], imEdg, 输出边缘图像
* @param[in], diffType, 差分类型:0表示对x方向进行差分(垂直边缘),1表示对y方向进行差分(水平边缘),2表示对角方向进行差分(倾斜边缘)
* @return, 正整数表示提取成功,负数表示提取失败
*/
int DiffEdgDtct(const cv::Mat& imSrc, cv::Mat& imEdg, int diffType)
{if(imSrc.empty()) return -1;//转换为对灰度图像的操作以减少计算量cv::Mat imGray;if (imSrc.channels() == 1)imGray = imSrc.clone();else cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);//图像预处理:去噪cv::GaussianBlur(imGray, imGray, cv::Size(3, 3), 0);//对预处理的灰度图像进行差分运算:0表示x方向上的差分,1表示y方向差分,2表示对角线方向差分cv::Mat kernel;if (diffType == 0){kernel = (cv::Mat_<int>(3, 3) << 0, 0, 0, -1, 1, 0, 0, 0, 0);}else if (diffType == 1){kernel = (cv::Mat_<int>(3, 3) << 0, -1, 0, 0, 1, 0, 0, 0, 0);}else if (diffType == 2){kernel = (cv::Mat_<int>(3, 3) << -1, 0, 0, 0, 1, 0, 0, 0, 0);}else{std::cerr<<"diffType you input is error!"<<std::endl;return -1;}cv::filter2D(imGray,imEdg,CV_16S, kernel); //对图像进行卷积操作cv::convertScaleAbs(imEdg,imEdg,30); //转为CV_8U//自适应二值化图像处理cv::Mat imEdgTmp;cv::threshold(imEdg, imEdgTmp, 0, 255, cv::THRESH_BINARY+cv::THRESH_OTSU);cv::medianBlur(imEdg, imEdg, 5);return 1;
}

使用方式:通常调用两次该函数并进行加权处理得到边缘图像,但该函数提取的边缘较粗,需要结合形态学操作以提取更加精确的边缘

(3)Roberts边缘检测

Roberts算子又称“交叉微分算法“,当图像边缘接近正负45度的时候,该算法处理效果很不错。缺点是边缘定位不是很精确,且提取的边缘也较粗。

/*@author: @还下着雨ZG
* @brief Robert算子提取图像边缘
* @param[in], imSrc, 待提取边缘的图像
* @param[out], imEdg, 提取的边缘图像
* @param[in], type, 差分类型:0表示对x方向进行差分,1表示对y方向进行差分
* @return, 正整数表示提取成功,负数表示提取失败
*/
int RobertEdgDtct(const cv::Mat &imSrc, cv::Mat &imEdg, int type=0)
{if(imSrc.empty()) return -1;//转换为对灰度图像的操作以减少计算量cv::Mat imGray;if (imSrc.channels() == 1)imGray = imSrc.clone();else cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);//图像预处理:去噪cv::GaussianBlur(imGray, imGray, cv::Size(3, 3), 0);//对预处理的灰度图像进行差分运算:0表示x方向上的差分,1表示y方向差分cv::Mat kernel;if (diffType == 0){kernel = (cv::Mat_<int>(2, 2) << -1, 0, 0, 1);}else if (diffType == 1){kernel = (cv::Mat_<int>(2, 2) << 0, -1, 1, 0);}else{std::cerr<<"The type you input is error!"<<std::endl;return -2;}cv::filter2D(imGray,imEdg,CV_16S, kernel); //对图像进行卷积操作cv::convertScaleAbs(imEdg,imEdg); //转为CV_8U//自适应二值化图像处理cv::Mat imEdgTmp;cv::threshold(imEdg, imEdgTmp, 0, 255, cv::THRESH_BINARY+cv::THRESH_OTSU);cv::medianBlur(imEdg, imEdg, 5);return 1;
}

使用方法:在实际应用时,应该利用该函数分别提取正45度方向上的边缘,再提取负45度方向上的边缘,最后加权,并结合形态学操作和轮廓查找函数findContours得到图像的轮廓或边缘。

(4)Sobel算子检测边缘

Sobel算子利用像素的上下左右邻域进行加权的算法,根据在边缘点处达到极值这一原理进行边缘检测。该方法能很好地检测出边缘,且对噪声具有平滑作用,提取的边缘信息比较精确。缺点是Sobel算子并没有严格地将前景和背景分开。

/*@author, @还下着雨ZG
* @brief Sobel算子提取图像边缘
* @param[in], imSrc, 待提取边缘的图像
* @param[out], imEdg, 提取的边缘图像
* @param[in], type, 差分类型:0表示x方向,1表示y方向差分
* @return, 正整数表示提取成功,负数表示提取失败
*/
int SobelEdgDtct(const cv::Mat &imSrc, cv::Mat &imEdg, int type=0)
{if(imSrc.empty()) return -1;//转换为对灰度图像的操作以减少计算量cv::Mat imGray;if (imSrc.channels() == 1)imGray = imSrc.clone();else cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);//图像预处理:去噪cv::GaussianBlur(imGray, imGray, cv::Size(3, 3), 0);//对预处理的灰度图像进行差分运算:0表示x方向上的差分,1表示y方向差分cv::Mat kernel;if (diffType == 0){kernel = (cv::Mat_<int>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);}else if (diffType == 1){kernel = (cv::Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);}else{std::cerr<<"The type you input is error!"<<std::endl;return -2;}cv::filter2D(imGray,imEdg,CV_16S, kernel); //对图像进行卷积操作cv::convertScaleAbs(imEdg,imEdg); //转为CV_8U,30根据自己需求确定//自适应二值化图像处理cv::Mat imEdgTmp;cv::threshold(imEdg, imEdg, 0, 255, cv::THRESH_BINARY+cv::THRESH_OTSU);cv::medianBlur(imEdg, imEdg, 5);return 1;
}

另外,opencv提供了自带的Sobel函数来探测图像的边缘信息:

void cv::Sobel(cv::Mat &imSrc,cv::Mat &imDst, int ddepth, //imDst的图像数据格式,如CV_8U,CV_16S,CV_32S等int dx, //表示x方向的差分阶数int dy, //表示y方向上的差分阶数int ksize = 3,//Sobel边缘算子的尺寸double scale = 1, //对计算结果的缩放因子double delta = 0, //对计算结果的偏置,res = scale * x + deltaint borderType = BORDER_DEFAULT //表示不包含边界值的倒序填充);

一般dx,dy和ksize存在一定关系

  • dx和dy一定小于ksize,特殊情况时当ksize=1时,
  • dx和dy都应该小于3
  • dx或dy最大值为1时,ksize=3
  • dx或dy最大值为2时,ksize=5
  • dx或dy最大值为3时,ksize=7 dx和dy都应该小于等于

(5)Prewitt算子边缘检测

相比于Robert算子,Prewitt算子对噪声具有抑制作用,抑制原理时进行像素平均,因此对噪声不敏感,但由于像素平均相当于对图像进行低通滤波,所以定位不如Roberts精确。

/*@author, @还下着雨ZG
* @brief Prewitt算子提取图像边缘
* @param[in], imSrc, 待提取边缘的图像
* @param[out], imEdg, 提取的边缘图像
* @param[in], type, 差分类型:0表示对正45度方向进行差分
* @return, 正整数表示提取成功,负数表示提取失败
*/
int PrewittEdgDtct(const cv::Mat &imSrc, cv::Mat &imEdg, int type=0)
{if(imSrc.empty()) return -1;//转换为对灰度图像的操作以减少计算量cv::Mat imGray;if (imSrc.channels() == 1)imGray = imSrc.clone();else cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);//图像预处理:去噪cv::GaussianBlur(imGray, imGray, cv::Size(3, 3), 0);//对预处理的灰度图像进行差分运算:0表示x方向上的差分,1表示y方向差分cv::Mat kernel;if (diffType == 0){kernel = (cv::Mat_<int>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);}else if (diffType == 1){kernel = (cv::Mat_<int>(3, 3) <<1, 1, 1, 0, 0, 0, -1, -1, -1);}else{std::cerr<<"The type you input is error!"<<std::endl;return -2;}cv::filter2D(imGray,imEdg,CV_16S, kernel); //对图像进行卷积操作cv::convertScaleAbs(imEdg,imEdg); //转为CV_8U,30根据自己需求确定//自适应二值化图像处理cv::Mat imEdgTmp;cv::threshold(imEdg, imEdg, 0, 255, cv::THRESH_BINARY+cv::THRESH_OTSU);cv::medianBlur(imEdg, imEdg, 5);return 1;
}

(6)Laplacian边缘检测

void Laplacian(InputArray imSrc, //输入图像outputArray imDst,  //输出的边缘图像int ddepth,  //imDst的数据类型CV_16S,CV_32S等int ksize=1,  //拉普拉斯算子的尺寸double scale=1, //计算结果的缩放尺度doubel delta=0,  //偏置值int borderType=BORDER_DEFAULT);

(7)LoG边缘检测算子

LoG算子把高斯滤波器和拉普拉斯滤波器结合起来使用,先平滑掉噪声,再进行边缘检测,形成的LoG滤波器核如下面代码kernel所示。LoG是检测边缘比较好的边缘检测器。

/*@author, @还下着雨ZG
* @brief LoG算子提取图像边缘
* @param[in], imSrc, 待提取边缘的图像
* @param[out], imEdg, 提取的边缘图像
* @return, 正整数表示提取成功,负数表示提取失败
*/
int LoGEdgDtct(const cv::Mat &imSrc, cv::Mat &imEdg)
{if(imSrc.empty()) return -1;//转换为对灰度图像的操作以减少计算量cv::Mat imGray;if (imSrc.channels() == 1)imGray = imSrc.clone();else cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);//图像预处理:去噪cv::GaussianBlur(imGray, imGray, cv::Size(3, 3), 0);//对预处理的灰度图像进行差分运算:0表示x方向上的差分,1表示y方向差分cv::Mat kernel;kernel = (cv::Mat_<int>(5, 5) << -2, -4, -4, -4, -2, -4,  0,  8,  0, -4,-4,  8,  24, 8, -4,-4,  0,  8,  0, -4,-2, -4, -4, -4, -2);cv::filter2D(imGray,imEdg,CV_16S, kernel); //对图像进行卷积操作cv::convertScaleAbs(imEdg,imEdg); //转为CV_8U,30根据自己需求确定//自适应二值化图像处理cv::Mat imEdgTmp;cv::threshold(imEdg, imEdg, 0, 255, cv::THRESH_BINARY+cv::THRESH_OTSU);cv::medianBlur(imEdg, imEdg, 5);return 1;
}

3.边缘检测新技术和方法

(1)基于小波与分形理论的边缘检测技术

小波变换在时域和频域中都具有良好的局部特性,可将信号或图像分成交织在一起的多尺度组成成分,并对大小不同的尺度成分使用相应粗细的时域或空域取样步长。其灵活的信号处理能力能够不断地聚焦对象的任意微小细节。
边缘检测就是准确定位出信号突变的部分,在数学中表现为不连续点或尖点。

(2)基于数学形态学的边缘检测技术

用集合论的方法定量描述几何结构的技术。
常见的形态学操作如下:膨胀和腐蚀是最基本的两种操作,其它操作时这两种操作的组合

  • 膨胀:增加图像中亮色部分,可以对彩色图像、灰度图像和二值图像进行操作
  • 腐蚀:增加图像中暗色部分
  • 开操作:先腐蚀后膨胀,效果:去除暗色区域中的亮点
  • 闭操作:先膨胀后腐蚀,效果:去除亮色区域中的暗点
  • 击中与击不中操作:三种值(-1,0,1),-1表示黑,1表示白,0表示任意(黑或白),通过设计模板核,进行击中与击不中操作实现边缘检测、模式匹配等功能。
  • 黑帽操作:先对图像进行闭运算,然后将闭运算的结果与原始图像相减,用于增强小细节
  • 厚化操作:先对图像进行开运算,然后将结果和原始图像相减,用于强调大细节
    形态学操作进行边缘提取的基本使用如下代码所示:
//形态学操作实现边缘提取,可根据具体场景优化后直接拷贝使用
int MorphEdgDtct(const cv::Mat& imSrc, cv::Mat& imEdg)
{if (imSrc.empty()) return -1;cv::Mat imGray;if (imSrc.channels() == 3){cv::cvtColor(imSrc, imGray, cv::COLOR_RGB2GRAY);}else{imGray = imSrc.clone();}cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));int iTms = 1;cv::Mat imTmp01, imTmp02;cv::dilate(imGray, imTmp01, kernel, cv::Point(-1, -1), iTms);cv::erode(imGray, imTmp02, kernel, cv::Point(-1, -1), iTms);cv::Mat imSobel = imTmp01 - imTmp02; //膨胀-腐蚀=边缘//自适应二值化图像处理cv::threshold(imSobel, imSobel, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);cv::medianBlur(imSobel, imEdg, 5);return 1;
}

(3)基于神经网络的边缘检测技术

利用神经网络的方法得到的边缘图像边界连续性比较好,边界封闭性也比较好,并且对于任何灰度图检测都能得到良好的效果。

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

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

相关文章

手把手!从头构建LLaMA3大模型(Python)

1. 前期准备 让我们先来想一想大概需要做什么。 首先是模型架构的选择。原工作用的是 GPT Neo 架构&#xff08;可以看他们的 config&#xff09;&#xff0c;这个算是很老的模型了&#xff0c;最初是 EleutherAI 用来复现追踪 GPT-3 的工作的&#xff0c;现在用的也比较少了…

洛谷 P1726:上白泽慧音 ← Tarjan算法

【题目来源】https://www.luogu.com.cn/problem/P1726【题目描述】 在幻想乡&#xff0c;上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞&#xff0c;使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新…

鸿蒙开发组件:【创建DataAbility】

创建DataAbility 实现DataAbility中Insert、Query、Update、Delete接口的业务内容。保证能够满足数据库存储业务的基本需求。BatchInsert与ExecuteBatch接口已经在系统中实现遍历逻辑&#xff0c;依赖Insert、Query、Update、Delete接口逻辑&#xff0c;来实现数据的批量处理。…

redis复习

redis知识点 redis持久化redis 订阅发布模式redis主从复制哨兵模式redis雪崩&#xff0c;穿透缓存击穿&#xff08;请求太多&#xff0c;缓存过期&#xff09;缓存雪崩 redis持久化 redis是内存数据库&#xff0c;持久化有两种方式&#xff0c;一种是RDB&#xff08;redis dat…

【计算机网络】[第4章 网络层][自用]

1 概述 (1)因特网使用的TCP/IP协议体系(四层)的网际层,提供的是无连接、不可靠的数据报服务; (2)ATM、帧中继、X.25的OSI体系(七层)中的网络层,提供的是面向连接的、可靠的虚电路服务。 (3)路由选择分两种: 一种是由用户or管理员人工进行配置(只适用于规…

图解Linux内核(基于6.x):解读Linux内存反向映射之匿名映射

文章目录 &#x1f4d1;前言一、匿名映射的mapping二、推荐阅读2.1 一图速览2.2 内容简介 &#x1f4d1;前言 内存映射中&#xff0c;我们经常讨论的是由虚拟内存定位物理内存&#xff08;也就是folio或者page&#xff09;&#xff0c;实际上在很多场景中&#xff08;比如内存回…

linux写代码环境和工具

基础指令 目录 前言 二、yum工具的使用 1.yum是什么&#xff1f; 2.查看软件包 3.配置sudo 4.如何卸载软件 三、vim的使用 1. vim的基本概念 2. vim的基本操作 3. vim正常模式命令集 4.简单vim配置 四、Linux编译器-gcc/g使用 1、格式 2、gcc选项 3.gcc/g工作和…

浅谈Java23种设计模式之11种行为型模式的使用场景(第三部分)

前言 行为型设计模式实际使用场景第三部分; 1.状态模式&#xff08;State&#xff09; 概念: 它允许对象在其内部状态改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。这种模式主要用于当一个对象的行为依赖于它的状态&#xff08;对象的状态改变&#xff0c;行…

专业技能篇--算法

文章目录 前言经典算法思想总结一、贪心算法二、动态规划三、回溯算法四、分治算法 前言 这篇简单理解一些常见的算法。如果面试的时候问到相关的算法&#xff0c;能够应付一二。 经典算法思想总结 一、贪心算法 思想&#xff1a;贪心算法是一种在每一步选择中都采取在当前状…

Python——Gradio

什么是 Gradio&#xff1f; Gradio 是一个开源的 Python 库&#xff0c;用于创建用户友好的、交互式的网页界面。这个界面可以用来展示和测试机器学习模型&#xff0c;或者任何需要用户输入的 Python 应用程序。Gradio 的目标是让开发者快速地将他们的机器学习模型部署为可供他…

Vue CLI,Vue Router,Vuex

前言 Vue CLI、Vue Router 和 Vuex 都是 Vue.js 生态系统中的重要组成部分&#xff0c;它们在构建 Vue 应用程序时扮演着关键角色。 Vue CLI Vue CLI 介绍 Vue CLI 是 Vue.js 的官方命令行工具&#xff0c;用于快速搭建 Vue.js 项目。它提供了一个图形界面&#xff08;通过…

Effective C++ 改善程序与设计的55个具体做法笔记与心得 1

一. 让自己习惯C 1. 视C为一个语言联邦 2. 尽量以const, enum, inline替换#define #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))int a 5 , b 0;CALL_WITH_MAX(a,b); // a 6, b 0 CALL_WITH_MAX(a,b10); // a 8, b 0你观察到的这个现象是由于宏替换(C prep…

工程打包与运行

黑马程序员Spring Boot2 文章目录 先点击cean&#xff0c;确保打包之前是个干净的环境点击package进行打包&#xff0c;打包成功之后可以看到target文件夹下的文件 到项目目录下使用终端打开&#xff0c;并使用以下命令运行打包好的程序 如果遇到没有主清单属性的问题&#xff…

搜维尔科技邀您共赴2024第四届轨道车辆工业设计国际研讨会

会议内容 聚焦“创新、设计、突破”&#xff0c;围绕“面向生命健康、可持续发展的轨道交通系统” 为主题&#xff0c;从数字化、智能化、人性化、绿色发展等方面&#xff0c;探索轨道交通行业的设计新趋势及发展新机遇。 举办时间 2024年7月10日-12日 举办地点 星光岛-青岛融…

5.音视频基础 FLV

目录 简说FLV FLV Header FLV Body Tag Header ​编辑Tag Data Audio Data Video Data Script Data 简说FLV FLV格式可以包含音频、视频和文本数据&#xff0c;并且可以在网络上进行流媒体传输。优点是文件大小较小&#xff0c;压缩效率高&#xff0c;并且可以在较低…

ROS 激光雷达

ROS 激光雷达 基本工作原理 激光雷达&#xff08;LIDAR&#xff0c;Light Detection and Ranging&#xff09;是一种用于测量距离的远程感应技术。它通过向目标发射激光并分析反射回来的光来测量目标与激光发射源之间的距离。激光雷达广泛应用于多种领域&#xff0c;包括地理…

feign原理

Feign远程调用&#xff0c;核心就是通过一系列的封装和处理&#xff0c;将以JAVA注解的方式定义的远程调用API接口&#xff0c;最终转换成为HTTP的请求形式&#xff0c;然后将HTTP的请求的响应结果&#xff0c;解码成JAVA Bean&#xff0c;放回给调用者。 流程 FeignClient远程…

Vue3 之 Pinia 服务端渲染 (SSR) (九)

Pinia SSR概述 Pinia是一个用于Vue.js的状态管理库&#xff0c;它支持服务端渲染(SSR)。在SSR中&#xff0c;页面在服务器端渲染成HTML字符串&#xff0c;然后发送到客户端&#xff0c;从而提升首屏加载速度和SEO优化。Pinia通过其设计使得在SSR环境下也能轻松使用和管理状态。…

WiFi/BLE芯片(1):英飞凌

前言: 大部分客户很少直接接触到WiFi/Bluetooth的芯片,一般是直接封装到了模块中,隔了一层。具体到芯片而言,WiFi/BLE芯片,芯片厂家有:Qualcomm高通、broadcom博通、Infineon英飞凌、Nordic诺迪科、Espressof乐鑫等。而英飞凌这块产品也是很丰富的,低功耗、距离等性能指…