目录
前言
本篇将介绍图像边缘检测的Sobel、Scharr和Laplacian算子以及Canny边缘检测算法及其效果。
一、图像边缘检测
1.边缘检测
是图形图像处理、计算机视觉和机器视觉中的一个基本工具,通常用于特征提取和特征检测,旨在检测一张数字图像中有明显变化的边缘或者不连续的区域。
2.边缘检测的方法
二、Sobel算子
1.Sobel算子
Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
2.计算
计算过程简单的来说就是x轴放箱费和y轴方向各一个矩阵,对图像的所有像素点做卷积操作寻找梯度
3.代码实现
完整代码:
import cv2
"""Sobel算子"""
yuan = cv2.imread('../yuan.png')
cv2.imshow('yuan', yuan)
cv2.waitKey(0)
'''x方向上的边缘'''
# 右端为负值 显示不出来
yuan_x_64 = cv2.Sobel(yuan, cv2.CV_64F, dx=1, dy=0)
cv2.imshow('yuan_x_64', yuan_x_64)
cv2.waitKey(0)
# 进行取绝对值操作即可
yuan_x_full = cv2.convertScaleAbs(yuan_x_64)
cv2.imshow('yuan_x_full', yuan_x_full)
cv2.waitKey(0)
'''y方向上的边缘'''
# y的下端为负值 显示不出来
# 进行取绝对值操作即可
yuan_y_64 = cv2.Sobel(yuan, cv2.CV_64F, dx=0, dy=1)
yuan_y_full = cv2.convertScaleAbs(yuan_y_64)
cv2.imshow('yuan_y_full', yuan_y_full)
cv2.waitKey(0)
'''使用加权运算组合图像得到完整边缘'''
yuan_xy_full = cv2.addWeighted(yuan_x_full, 1, yuan_y_full, 1, 10)
cv2.imshow('yuan_xy_full', yuan_xy_full)
cv2.waitKey(0)
cv2.destroyAllWindows()
"""使用彩色图获取边缘"""
zrn = cv2.imread('../zrn.jpg', cv2.IMREAD_GRAYSCALE)
zrn = cv2.resize(zrn, (400, 400))
x = cv2.Sobel(zrn, cv2.CV_64F, dx=1, dy=0)
y = cv2.Sobel(zrn, cv2.CV_64F, dx=0, dy=1)
x_full = cv2.convertScaleAbs(x)
y_full = cv2.convertScaleAbs(y)
xy = cv2.addWeighted(x_full, 1, y_full, 1, 0)
cv2.imshow('zrn_Sobel', xy)
cv2.waitKey(0)
输出:
4.代码步骤解析
1.导入图片
import cv2
"""Sobel算子"""
yuan = cv2.imread('../yuan.png')
cv2.imshow('yuan', yuan)
cv2.waitKey(0)
2.处理x轴和y轴的边缘并相加
- x轴:
'''x方向上的边缘'''
# 右端为负值 显示不出来
yuan_x_64 = cv2.Sobel(yuan, cv2.CV_64F, dx=1, dy=0)
cv2.imshow('yuan_x_64', yuan_x_64)
cv2.waitKey(0)
# 进行取绝对值操作即可
yuan_x_full = cv2.convertScaleAbs(yuan_x_64)
cv2.imshow('yuan_x_full', yuan_x_full)
cv2.waitKey(0)
输出:
左边的右边边缘没显示出来是因为进行计算之后这些位置的像素值为负值,显示不出来。
经过取绝对值操作之后即可完整显示出来
- 完整边缘:
y轴的处理与x轴一致
完整的边缘只需将两个轴上的数据进行加权相加即可
'''y方向上的边缘'''
# y的下端为负值 显示不出来
# 进行取绝对值操作即可
yuan_y_64 = cv2.Sobel(yuan, cv2.CV_64F, dx=0, dy=1)
yuan_y_full = cv2.convertScaleAbs(yuan_y_64)
cv2.imshow('yuan_y_full', yuan_y_full)
cv2.waitKey(0)
'''使用加权运算组合图像得到完整边缘'''
yuan_xy_full = cv2.addWeighted(yuan_x_full, 1, yuan_y_full, 1, 10)
cv2.imshow('yuan_xy_full', yuan_xy_full)
cv2.waitKey(0)
cv2.destroyAllWindows()
最终结果:
三、Scharr算子
1.Scharr算子
Scharr 算子是 Soble 算子在 ksize=3 时的优化,与 Soble 的速度相同,且精度更高。Scharr 算子与 Sobel 算子的不同点是在平滑部分,其中心元素占的权重更重,相当于使用较小标准差的高斯函数,也就是更瘦高的模板。
2.计算
计算过程与sobel算子相同,只是所用矩阵有差别
3.代码实现
完整代码:
- 实现步骤与Sobel的步骤一模一样,在此就不过多赘述了。
import cv2
"""Scharr(xia)算子"""
zrn1 = cv2.imread('../zrn.jpg', cv2.IMREAD_GRAYSCALE)
zrn1 = cv2.resize(zrn1, (400, 400))
x = cv2.Scharr(zrn1, cv2.CV_64F, dx=1, dy=0)
y = cv2.Scharr(zrn1, cv2.CV_64F, dx=0, dy=1)
x_full = cv2.convertScaleAbs(x)
y_full = cv2.convertScaleAbs(y)
xy = cv2.addWeighted(x_full, 1, y_full, 1, 0)
cv2.imshow('zrn_Scharr', xy)
cv2.waitKey(0)
输出:
四、Laplacian算子
1.Laplacian算子
不再以x和y的方向计算,而是以圆方向计算变化率。因此不需要Gx+Gy。
2.计算
简单来说就是只使用一个矩阵去跟所有的点进行卷积,得到的结果直接作为边缘
3.代码实现
完整代码:
步骤就是将Sobelx轴和y轴的步骤合二为一,并将取绝对值和加权相加的步骤去除了
import cv2
"""Laplacian算子"""
zrn1 = cv2.imread('zrn.jpg', cv2.IMREAD_GRAYSCALE)
zrn1 = cv2.resize(zrn1, (400, 400))
lap = cv2.Laplacian(zrn1, cv2.CV_64F, delta=10)
lap_full = cv2.convertScaleAbs(lap)
cv2.imshow('zrn_Lap', lap_full)
cv2.waitKey(0)
输出:
五、Canny边缘检测算法
1.Canny
Canny 边缘检测是一种图像处理技术,用于检测图像中的边缘。它通过以下几个步骤实现:首先对图像进行平滑处理以减少噪声;接着计算每个像素的梯度强度和方向;然后进行非极大值抑制以精确定位边缘;最后应用双阈值化和边缘连接来确定最终的边缘。这种方法能有效地识别和提取图像中的显著边缘。
2.计算
canny的计算分为四步:
- 图像降噪
- 梯度计算
- 非极大值抑制
- 双阈值边界跟踪
具体内容感兴趣的可以搜索查看
3.代码实现
完整代码:
使用算法的代码就cv2.Canny()那一行,数字参数代表高低阈值,可以自己调试看看效果有何不同
import cv2
"""Canny算子"""
suda = cv2.imread('suda.jpg', cv2.IMREAD_GRAYSCALE)
suda = cv2.resize(suda, (400, 400))
cv2.imshow('suda', suda)
cv2.waitKey(0)
can = cv2.Canny(suda, 100, 200) # 低阈值 高阈值
cv2.imshow('suda_canny', can)
cv2.waitKey(0)
输出:
总结
这么多种算法各有千秋,面对每种情况可以选择适合的算法