图像边缘检测

article/2025/9/29 15:30:08

文章目录

  • 1. 什么是边缘检测
  • 2 边缘检测的常用方法及Python应用
    • 2.1 一阶微分算子
      • 2.1.1 Roberts算子
      • 2.1.2 Prewitt算子
      • 2.1.3 Sobel算子
    • 2.2 二阶微分算子
      • 2.2.1 Laplacian算子
      • 2.2.2 Canny算子
  • 3. 源码仓库地址

1. 什么是边缘检测

边缘检测是图像处理与计算机视觉中的重要技术之一。其目的是检测识别出图像中亮度变化剧烈的像素点构成的集合。图像边缘的正确检测对于分析图像中的内容、实现图像中物体的分割、定位等具有重要的作用。边缘检测大大减少了源图像的数据量,剔除了与目标不相干的信息,保留了图像重要的结构属性。

图像的边缘指的是图像中像素灰度值突然发生变化的区域,如果将图像的每一行像素和每一列像素都描述成一个关于灰度值的函数,那么图像的边缘对应在灰度值函数中是函数值突然变大的区域。函数值的变化趋势可以用函数的导数描述。当函数值突然变大时,导数也必然会变大,而函数值变化较为平缓区域,导数值也比较小,因此可以通过寻找导数值较大的区域去寻找函数中突然变化的区域,进而确定图像中的边缘位置。

2 边缘检测的常用方法及Python应用

边缘检测的方法大致可分为两类:基于搜索和基于零交叉。

基于搜索的边缘检测方法:首先计算边缘强度,通常用一阶导数表示,例如梯度模,然后,计算估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值。

基于零交叉的边缘检测方法:找到由图像得到的二阶导数的零交叉点来定位边缘,通常用拉普拉斯算子或非线性微分方程的零交叉点。

滤波作为边缘检测的预处理通常是必要的,通常采用高斯滤波。

2.1 一阶微分算子

一阶微分为基础的边缘检测,通过计算图像的梯度值来检测图像的边缘,如Roberts算子、Prewitt算子和Sobel算子等。

2.1.1 Roberts算子

Roberts算子是一种最简单的算子,它利用局部差分算子寻找边缘。采用对角线相邻两像素之差近似梯度幅值检测边缘,检测垂直边缘的效果比斜向边缘要好,定位精度高,但对噪声比较敏感,无法抑制噪声的影响。

Roberts算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差,如下的2个卷积核形成了Roberts算子,图像中的每一个点都用这2个核做卷积:

在这里插入图片描述

若对于输入图像f(x,y),使用Roberts算子后输出的目标图像为g(x,y),则

在这里插入图片描述

在Python中,Roberts算子主要是通过Numpy定义模板,再调用OpenCV的filter2D()函数实现边缘提取。该函数主要是利用内核实现对图像的卷积运算,其函数原型如下:

dst = filter2D(src, ddepth, kernel, dts, anchor,delta, borderType)

参数说明:
src:表示输入图像;
ddepth: 表示目标图像所需的深度;
kernel: 表示卷积核,一个单通道浮点型矩阵;
anchor: 表示内核的基准点,其默认值为(-1, -1),位于中心位置;
delta:表示在存储目标图像前可选的添加到像素的值,默认值为0;
borderType:表示边框模式。

实验代码如下:

 def Roberts(srcImg_path):img = cv2.imread(srcImg_path)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Roberts算子kernelx = np.array([[1, 0], [0, -1]], dtype=int)kernely = np.array([[0, -1], [1, 0]], dtype=int)x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)# 转成uint8absX = cv2.convertScaleAbs(x)absY = cv2.convertScaleAbs(y)Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)# 显示图形titles = ["Original Image", "Roberts Image"]images = [img, Roberts]for i in range(2):plt.subplot(1, 2, i+1)plt.imshow(images[i], "gray")plt.title(titles[i])plt.axis('off')plt.show()

效果如下:

在这里插入图片描述

2.1.2 Prewitt算子

Prewitt是一种图像边缘检测的微分算子,其原理是利用特定区域内像素值产生的差分实现边缘检测。由于Prewitt算子采用3x3模板对区域内的像素值进行计算,而Roberts算子的模板为2x2,故Prewitt算子的边缘检测结果在水平和垂直方向均比Roberts算子更加明显。Prewitt算子适合用来识别噪声较多,灰度渐变的图像。

Prewitt算子卷积核如下:

在这里插入图片描述

实验代码如下:

 def Prewitt(srcImg_path):img = cv2.imread(srcImg_path)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Prewitt算子kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)# 转成uint8absX = cv2.convertScaleAbs(x)absY = cv2.convertScaleAbs(y)Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)# 显示图形titles = ["Original Image", "Prewitt Image"]images = [img, Prewitt]for i in range(2):plt.subplot(1, 2, i+1)plt.imshow(images[i], "gray")plt.title(titles[i])plt.axis('off')plt.show()

效果如下:

在这里插入图片描述

2.1.3 Sobel算子

在边缘检测中,常用的一种模板是Sobel算子。Sobel算子有两个卷积核,一个是检测水平边缘的;另一个是检测垂直边缘的。与Prewitt算子相比,Sobel算子对于像素的位置的影响做了加权,可以降低边缘模糊程度,因此效果更好。

Sobel算子卷积核如下:

在这里插入图片描述

在opencv-python中定义了Sobel算子,其函数原型如下:

dst = Sobel(src, ddepth, dx, dy, dst,ksize, scale, delta, borderType)

参数说明:
src:表示输入图像;
dst:表示输出的边缘图,其大小和通道数与输入图像相同;
ddepth:表示目标图像所需的深度,针对不同的输入图像,输出目标图像有不同的深度;
dx:表示x方向上的差分阶数,取值1或0;
dy:表示y方向上的差分阶数,取值1或0;
ksize:表示Sobel算子的大小,其值必须是正数和奇数;
scale:表示缩放导数的比例常数,默认情况下没有伸缩系数;
delta:表示将结果存入目标图像之前,添加到结果中的可选增量值。

实验代码如下:

 def Sobel_demo(srcImg_path):img = cv2.imread(srcImg_path)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Sobel算子x = cv2.Sobel(grayImage, cv2.CV_16S, 1, 0)y = cv2.Sobel(grayImage, cv2.CV_16S, 0, 1)# 转成uint8absX = cv2.convertScaleAbs(x)absY = cv2.convertScaleAbs(y)Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)# 显示图形titles = ["Original Image", "Sobel Image"]images = [img, Sobel]for i in range(2):plt.subplot(1, 2, i+1)plt.imshow(images[i], "gray")plt.title(titles[i])plt.axis('off')plt.show()

效果如下:

在这里插入图片描述

2.2 二阶微分算子

二阶微分为基础的边缘检测,通过寻求二阶导数中的过零点来检测边缘,如Laplacian算子和Canny算子等。

2.2.1 Laplacian算子

Laplacian算子是n维欧几里德空间中的一个二阶微分算子,常用于图像增强和边缘提取。它通过灰度差分计算邻域内的像素,基本流程是:判断图像中心像素灰度值与它周围其他像素的灰度值,如果中心像素的灰度更高,则提升中心像素的灰度;反之降低中心像素的灰度,从而实现图像锐化操作。在算法实现过程中,Laplacian算子通过对邻域中心像素的四方向或八方向求梯度,再将梯度相加起来判断中心像素灰度与邻域内其他像素灰度的关系,最后通过梯度运算的结果对像素灰度进行调整。

在opencv-python中,Laplacian算子封装在Laplacian()函数中,其函数原型如下:

dst = Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])

参数说明:
src:表示输入图像;
dst:表示输出的边缘图,其大小和通道数与输入图像相同;
ddepth:表示目标图像所需的深度;
ksize:表示用于计算二阶导数的滤波器的孔径大小,其值必须是正数和奇数,且默认值为1;
scale:表示计算拉普拉斯算子值的可选比例因子,默认值为1;
delta:表示将结果存入目标图像之前,添加到结果中的可选增量值,默认值为0;
borderType:表示边框模式。

当ksize=1时,Laplacian()函数采用3x3模板(四邻域)进行变换处理。下面的实验代码是采用ksize=3的Laplacian算子进行图像锐化处理:

def Laplacian_demo(srcImg_path):img = cv2.imread(srcImg_path)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Laplacian算子Laplacian = cv2.Laplacian(grayImage, cv2.CV_16S, ksize=3)# 转成uint8Laplacian = cv2.convertScaleAbs(Laplacian)# 显示图形titles = ["Original Image", "Laplacian Image"]images = [img, Laplacian]for i in range(2):plt.subplot(1, 2, i+1)plt.imshow(images[i], "gray")plt.title(titles[i])plt.axis('off')plt.show()

效果如下:

在这里插入图片描述

2.2.2 Canny算子

Canny算子由John F. Canny在1986年提出,由于它出色的检测和容错能力,至今一直被广泛使用。Canny边缘检测具有以下特点:
(1)较低的错误率 - 只有真实存在的边缘才会被检测到。
(2)较好的边缘定位 - 检测出来的结果和图像中真实的边缘在距离上的误差很小。
(3)没有重复的检测 - 对于每一条边缘,只会返回一个与之对应的结果。

Canny算子的计算步骤大概分成以下几步:

  1. 图像灰度化
  2. 用高斯滤波去噪:目的是平滑一些纹理较弱的非边缘区域,以得到更准确的边缘。
  3. 计算梯度方向和大小:图像梯度表达的是各个像素点之间,像素值大小的变化幅度大小,变化较大,则可以认为是处于边缘位置。
  4. 非极大值抑制:在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点,即对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。
  5. 双阈值选取和滞后边界跟踪:确定哪些边界才是真正的边界。这时我们需要设置两个阈值:minVal和maxVal。当图像的灰度梯度高于maxVal时被认为是真的边界,那些低于minVal的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。

在Python Opencv接口中,提供了Canny函数,其函数原型如下:

canny = cv2.Canny(image,threshold1,threshold2)

参数说明:
image:灰度图;
threshold1:minval,较小的阈值将间断的边缘连接起来;
threshold2:maxval,较大的阈值检测图像中明显的边缘。

实验代码如下:

def Canny_demo(srcImg_path):img = cv2.imread(srcImg_path)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 高斯滤波img_GaussianBlur = cv2.GaussianBlur(gray, (3,3), 0)# Canny算子Canny = cv2.Canny(img_GaussianBlur, 0, 100)# 显示图形titles = ["Original Image", "Canny Image"]images = [img, Canny]for i in range(2):plt.subplot(1, 2, i+1)plt.imshow(images[i], "gray")plt.title(titles[i])plt.axis('off')plt.show()

效果如下:
在这里插入图片描述

3. 源码仓库地址

🌼图像处理、机器学习的常用算法汇总


http://chatgpt.dhexx.cn/article/c6VHh7B8.shtml

相关文章

图像检测:图像分类

图像分类 判断图片中是否有某个物体,一个图对应一个标签 卷积神经网络(CNN) 网络进化: 网络: AlexNet→VGG→GoogLeNet→ResNet 深度: 8→19→22→152 VGG结构简洁有效: 容易修改,迁移到其…

相似图像的检测方法

背景 以图搜图,是日常生活中我们经常会用到,例如在选购一款商品时,想要对比价格,往往会在各个购物app上通过搜图的形式来看同一款产品的价格;当你碰到某种不认识的植物时,也可以通过以图搜图的方式来获取该…

图像检测

图像中的目标检测涉及识别各种子图像并且围绕每个识别的子图像周围绘制一个边界框。 不需要判断是什么类型,后面可以做图像识别 经典网络: 图像分类的深度学习工具是区域卷积神经网络(R-CNN) 第一阶段:R-CNN->S…

计算机视觉-深度学习图像检测方法梳理

计算机视觉-深度学习图像检测方法梳理 由于之后要转方向啦,趁这段时间整理手中硕士研究方向的一些阅读笔记,这是一篇关于计算机视觉的基础知识梳理 先搞清一些小知识点 首先我们要弄清楚图像分类、目标定位、语义分割、实例分割的区别 a. 图像分类 &…

树上倍增法

一 点睛 树上倍增法不仅可以解决 LCA问题,还可以解决很多其他问题。 F[i,j] 表示 i 2^j 辈祖先,即 i 节点向根节点走 2^j 步到达的节点。 u 节点向上走 2^0步,即为 u 的父节点 x, F[u,0] x ;向上走 2^1…

光电倍增管国产型号及相关知识

国产光电倍增管 南京永纪,GDB235 参考网址 请教光电倍增管在安装、使用注意事项,谢谢 (amobbs.com 阿莫电子论坛) 光电倍增管(PMT)使用注意 光电倍增管(PMT)使用注意_滨松光子学商贸(中国)有限公司 (ham…

倍增node

倍增 普及组的内容,思想很简单,但是考的可以挺难 倍增是啥东西 “ 倍增,顾名思义,就是每次增加一倍。 展开来说,就是每次根据已经得到的信息,将考虑的范围增加一倍, 从而加速操作。倍增思想有…

倍增求LCA

一:定义 LCA指的是最近公共祖先。具体地,给定一棵有根数,若结点z既是结点x的祖先,也是结点y的祖先,则称z是x,y的公共祖先。在x,y的公共祖先中,深度最大的那个节点成为x,y…

倍增数组基础

应用: 给定一个数列a, 基本的倍增数组可以用O(1)的时间复杂度计算出区间[i,j]的最值。 具体操作: 维护倍增数组 1、状态 dp[j][i]表示区间从i到 i(2^j)-1,即以i开始长度为2^j 这个区间范围的最值。(下面以最小值为例) 2、状态转移…

倍增LCA

朴素算法求LCA,即暴力求解,当树近乎为一条链时,找祖先时一级一级向上跳,时间复杂度接近O(n),所以可以考虑一次跳尽可能大的距离,即倍增算法;一次跳2^i(i0,1,2....)级。 倍增法 一个节…

倍增算法

倍增算法 【序言】 我认为吧,所有能够优化复杂度的算法都是神奇的,所有能够化繁琐为形象的文字都是伟大的。一直觉得倍增算法是个很神奇的东西,所以决定写点东西纪念一下它。但是作为一个非常不称职的OIER,我非常讨厌在看别人的算法解析时整版的i,j,k等我看到鼠标…

浅谈倍增及应用

浅谈倍增 倍增思想 原理: 倍增,即成倍增长。在处理一系列序列数据时,倍增可通过指数级的增长快速覆盖所有数据。 倍增算法采用2倍增长的方式,其核心思想是建立以下数组T a[i][j] ,表示自i向后共 2 j 2^j 2j个数据的…

倍增(ST表与LCA)

倍增(ST表与LCA) 什么是倍增? 倍增,就是成倍增长。指我们进行递推时,如果状态空间很大,通常线性递推无法满足时空复杂度要求,那么可以通过成倍增长的方式,只递推状态空间中 2 的整…

V4L2-框架

1.概述 V4L2 是专门为linux 设备设计的一套视频框架,其主体框架在linux内核,可以理解为是整个linux系统上面的视频源捕获驱动框架。 相机驱动层位于HAL Moudle 与硬件层之间,借助linux 内核驱动框架,以文件节点的方式暴露接口给用…

V4L2学习笔记

首先附上,Linux内核网站: 入口 v4l2非常棒的一篇文章 入口 内核代码查看: 入口 一个博客文档: 入口 https://lwn.net/Articles/204545/ 别人整理 关于linux内核头函数: /usr/src/xxx 系列文 在其内部有media文件…

V4L2框架学习

V4L2框架 0 查看videodev2 0.1 头文件/usr/include/linux/videodev2.h 0.2 使用ioctl函数 使用ioctl函数 // 添加头文件 #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h>int ioctl (int __fd, unsigned long int __request, ...…

V4L2介绍

V4L2介绍 V4L2介绍主要功能框架v4L2编程 V4L2介绍 V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中&#xff0c;视频设备是设备文件&#xff0c;可以像访问普通文件一样对其进行读写&#xff0c;摄像头在/dev/video*下&#xff0c;如果只有一个视频…

linux V4L2子系统——v4l2架构(7)之V4L2应用编程

linux V4L2子系统——v4l2架构&#xff08;7&#xff09;之V4L2应用编程 备注&#xff1a;   1. Kernel版本&#xff1a;5.4   2. 使用工具&#xff1a;Source Insight 4.0   3. 参考博客&#xff1a; &#xff08;1&#xff09;Linux V4L2子系统-应用层访问video设备&a…

[2022.8.15]v4l2-ctl基本使用方法

v4l2-ctl使用帮助可以参考&#xff1a;https://www.mankier.com/1/v4l2-ctl 1 v4l2-ctl --list-devices 列出所有设备 USB 2.0 Camera: USB Camera (usb-0000:00:14.0-9):/dev/video0/dev/video1 一个USB camera对应两个设备&#xff1a;一个是图像/视频采集&#xff0c;一…