文章目录
- 一、图像边缘检测概述
- 二、常见的图像边缘检测算法(简单介绍)
- 1.sobel算子
- 2.Scharr算子
- 3.Laplacian算子
- 4.Canny算子
- 三、代码实现
一、图像边缘检测概述
- 图像边缘检测是一种重要的图像处理技术,用于定位二维或三维图像中对象的边缘。这些边缘通常是图像中亮度或灰度值发生显著变化的地方,对应着物体的轮廓、不同区域的边界等
- 图像边缘检测在图像分割、目标识别、图像分析等领域具有广泛的应用
- 图像边缘检测的目的:
- 特征提取:边缘是图像中重要的特征信息,通过边缘检测可以提取出这些特征,为后续处理如图像分割、目标识别等提供基础。
- 图像简化:边缘检测后的图像更为简洁,去除了大量冗余的像素点,有助于减少计算量,提高处理速度,并使图像更易于分析和理解。
- 结构分析:边缘检测有助于分析图像中的结构信息,如物体的形状、大小、方向等,这些信息对于图像理解、场景重建等任务至关重要。
- 提升图像质量:边缘检测可以突出图像中的轮廓信息,使图像更加清晰、易于观察,特别是在医学影像分析、遥感图像处理等领域尤为重要。
- 促进后续处理:边缘检测是许多图像处理任务的预处理步骤,如图像分割、目标检测、目标跟踪等,通过边缘检测可以更容易地识别出图像中的目标对象,并为后续处理提供准确的定位信息。
- 图像边缘检测的基本步骤:
- 滤波:边缘检测算法主要基于图像强度的一阶和二阶导数,但这些导数对噪声非常敏感。因此,滤波是边缘检测前的必要步骤,以减少噪声对边缘检测结果的影响。常用的滤波器有高斯滤波器,它通过离散化的高斯函数对图像进行平滑处理。
- 增强:增强算法的目的是将图像中灰度有显著变化的点(即潜在的边缘点)凸显出来。一般通过计算梯度幅值来完成,梯度反映了亮度变化的强度和方向。
- 检测:在增强后的图像中,需要进一步检测边缘点。常用的方法是通过阈值化来检测边缘点,即设定一个或多个阈值,将梯度幅值大于阈值的点视为边缘点。
- 定位:在检测到边缘点后,需要进一步确定边缘的精确位置。这通常涉及到对边缘点的进一步处理和分析,如亚像素边缘定位等,以提高边缘检测的精度。
- 连接:在某些情况下,由于噪声、光照变化等因素的影响,检测到的边缘点可能会呈现为断开的片段。因此,需要通过一定的算法(如霍夫变换、轮廓跟踪等)将这些断开的边缘片段连接起来,形成完整的边缘轮廓。
二、常见的图像边缘检测算法(简单介绍)
1.sobel算子
- Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
- Sobel算子包含2组3×3的矩阵,分别为横向(Y方向)和纵向(X方向)模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。
- 如下图所示卷积核沿着X和Y方向进行卷积
2.Scharr算子
- Scharr 算子是 Soble 算子在 ksize=3 (卷积核为3*3)时的优化,卷积核比Sobel算子更精细,与 Soble 的速度相同,且精度更高。Scharr 算子与 Sobel 算子的不同点是在平滑部分,其中心元素占的权重更重,相当于使用较小标准差的高斯函数,也就是更瘦高的模板。
- 卷积核如下:
- 以上两种算子的检测过程如下图所示
3.Laplacian算子
- Laplacian算子不再以x和y的方向计算,而是以圆方向计算变化率。因此不需要Gx+Gy。
- 卷积核类似下图:
4.Canny算子
- Canny算子是一种多步骤的边缘检测算法,它通过图像平滑(降噪)、计算梯度幅值和方向、非极大值抑制以及双阈值处理等多个步骤来提取边缘信息
- 因此Canny算子具有高精度、低误检率和抗噪声能力强的特点,是许多图像处理任务中边缘检测的首选算法
- 图像降噪:使用高斯滤波器对输入图像进行平滑处理,以消除图像中的噪声和细节。高斯滤波器是一种常用的平滑滤波器,它通过卷积操作降低图像噪声。
- 计算梯度幅值和方向:对平滑后的图像应用Sobel(或Prewitt)算子,计算每个像素点的梯度幅值和方向。梯度可以反映像素值的变化情况,是边缘检测的重要依据。
- 非极大值抑制:在梯度图像上,对每个像素点在其梯度方向上进行比较,并保留局部最大值点,抑制非边缘像素。这一步的目的是细化边缘,确保边缘的宽度为单个像素。
- 双阈值处理:根据设定的高阈值和低阈值,将梯度图像中的像素点分为强边缘、弱边缘和非边缘三个部分。高阈值用于确定边缘候选点,而低阈值用于连接边缘。
三、代码实现
-
对一张图片分别用以上不同的四种算子方法进行实现
import cv2 """ 读取图片 """ M = cv2.imread('kobe.jpg', cv2.IMREAD_GRAYSCALE) # 读取图片并转换为灰度图 MB = cv2.resize(M, dsize=None, fx=0.4, fy=0.4) # 对图片大小进行调整(可选) """ Sobel算子 """ """ cv2.Sobel(src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]])# 参数: src:输入图像 ddepth: 输出图像的深度(可以理解为数据类型),-1表示与原图像相同的深度 dx,dy:当组合为dx=1,du=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常效果不佳) ksize:(可选参数)Sobel算子的大小,必须是1,3,5或者7(奇数),默认为3。 """ # cv2.Sobel函数来分别计算水平和垂直的梯度 # 用cv2.CV_64F作为输出图像的深度时,结果可能会包含负数 MB_x_64 = cv2.Sobel(MB, cv2.CV_64F, dx=1, dy=0) MB_y_64 = cv2.Sobel(MB, cv2.CV_64F, dx=0, dy=1) # 使用cv2.convertScaleAbs函数将结果转换为可显示的格式(即取绝对值后转换为8位无符号整数) MB_x_full = cv2.convertScaleAbs(MB_x_64) MB_y_full = cv2.convertScaleAbs(MB_y_64) # 使用cv2.addWeighted来结合水平和垂直梯度,这是计算梯度幅度(而非方向)的一种常用方法 # 权重都设置为0.5,意味着水平和垂直梯度对最终结果的贡献是相同的 MB_xy_full_Sobel = cv2.addWeighted(MB_x_full, 0.5, MB_y_full, 0.5, 0) # 可以更改权重得到不同的效果 """ Scharr算子 """ """ cv.Scharr(src, ddepth, dx, dyl, dst[, scalel, deltal, borderType]]]]) src:输入图像 ddepth:输出图片的数据深度,由输入图像的深度进行选择 dx: x 轴方向导数的阶数 dy: y 轴方向导数的阶数 """ MB_x_64 = cv2.Scharr(MB, cv2.CV_64F, dx=1, dy=0) MB_y_64 = cv2.Scharr(MB, cv2.CV_64F, dx=0, dy=1) MB_x_full = cv2.convertScaleAbs(MB_x_64) MB_y_full = cv2.convertScaleAbs(MB_y_64) MB_xy_full_Scharr = cv2.addWeighted(MB_x_full, 0.5, MB_y_full, 0.5, 0) """ Laplacian算子 """ """ cv2.Laplacian(src, ddepth[, dst[, ksize[, scalel, delta[, borderType]]]]]) 参数说明: src:输入图像,可以是灰度图像,也可以是多通道的彩色图像 ddepth:输出图片的数据深度,由输入图像的深度进行选择 ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项 scale:缩放比例因子,可选项,默认值为 1 delta:输出图像的偏移量,可选项,默认值为 0 """ MB_lap = cv2.Laplacian(MB, cv2.CV_64F) MB_full_Laplacian = cv2.convertScaleAbs(MB_lap) """ Canny算子 """ """ cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]]) image 为输入图像 threshold1 表示处理过程中的第一个阈值。fL --> 低 threshold2 表示处理过程中的第二个阈值。fH --> 高 """ MB_canny = cv2.Canny(MB, 100, 150) # 设置高低阈值 """ 显示结果 """ cv2.imshow('MB', MB) # 原图 cv2.imshow('MB_xy_full_Sobel', MB_xy_full_Sobel) # Sobel算子 cv2.imshow('MB_xy_full_Scharr', MB_xy_full_Scharr) # Scharr算子 cv2.imshow('MB_full_Laplacian', MB_full_Laplacian) # Laplacian算子 cv2.imshow('MB_canny', MB_canny) # canny算子 # 等待任意键按下后关闭所有窗口 cv2.waitKey(0) cv2.destroyAllWindows()
-
结果如下:
- 原图
- sobel算子(左)和Scharr算子(右)结果图
- Laplacian算子(左)和Canny算子(右)结果图
- 原图
-
由结果可以看出四个算子中,Canny算子边缘检测的结果是最好的