一.边缘检测
1.Canny 边缘检测
(1)概念
Canny边缘检测是图像处理中最著名,最常用的边缘检测算法之一,是1986年John F.Canny提出,一个最优的边缘检测器,满足三个标准
1.良好的检测性能,能够尽可能多的找出真是的边缘也就是低错误率。
2.良好的定位性能,检测到的边缘像素应该尽可能的接近真实边缘中心,即高定位精度。
3.清晰的响应,对于同一条边缘,算法只返回一个像素点,在最大限度上减少虚假响应。
(2)方法与解析
Canny 边缘检测是一个多阶段的算法,其流程如下图所示:

(3)使用
下面代码中简单使用了Canny边缘检测:
python
import cv2
# 读取图像,为灰度
image = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# 使用canny进行边缘检测
edges = cv2.Canny(image, threshold1=50, threshold2=100)
# 显示结果
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中有两个关键参数threshold1与threshold2,threshold1为低阈值,用于连接边缘,如果太高会漏掉弱边缘,如果太低会以引入过多噪声。threshold2为高阈值,如果太高会漏掉一些重要的边缘,如果太低会有过多噪声。在下图中左图为50:100右图为100:200。
观察图片发现左图有太多噪声,右图缺少边缘。这一点可以在图像处理过程中,先使用高斯滤波进行降噪再执行Canny边缘检测,能够显著提升边缘检测的质量。高斯滤波通过平滑图像有效抑制噪声干扰,避免噪声被误识别为边缘,使得后续Canny算子检测到的边缘更加准确和连续。这一预处理步骤尤其适用于噪声较多的图像,它能够在保留主要结构特征的同时减少虚假边缘,从而得到更清晰、更可靠的边缘检测结果。
代码:
python
import cv2
# 读取图像
image = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# 高斯滤波降噪
blurred_image = cv2.GaussianBlur(image, (5, 5), sigmaX=1.5)
# 使用 Canny 进行边缘检测
edges = cv2.Canny(blurred_image, threshold1=50, threshold2=100)
# 显示结果
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果:

2.Sobel 算子
(1)概念
Sobel算子用于边缘检测的离散微分算子,通过计算图像亮度函数的灰度近似值来近似其梯度。其核心思想是一阶微分,卷积操作和梯度计算。
其中一阶微分是在图像边缘对应着图像函数的一阶导数的极值点;卷积操作是Sobel算子使用两个3*3的卷积核与原始图像进行平面卷积运算;梯度计算是通过两个方向的卷积结果,可以计算出每个像素点的梯度幅值和方向,梯度幅值越大说明该点越可能是边缘点。
(2)使用
下面的代码实现了以灰度模式读取test.png图像,然后分别计算x方向和y方向的Sobel梯度,通过平方和开方合并两个方向的梯度结果。代码将浮点型梯度数据转换为8位无符号整型以便显示,最后用Matplotlib并排展示原始图像、水平梯度、垂直梯度及综合梯度结果图,同时将三个梯度结果分别保存为PNG文件。整个过程展示了Sobel算子提取图像边缘特征的基本流程。
python
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读取图片
image = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# Sobel算子边缘检测
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3) # x方向
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3) # y方向
sobel_combined = np.sqrt(sobel_x**2 + sobel_y**2) # 合并x和y方向
# 转换为8位无符号整型
sobel_x_abs = cv2.convertScaleAbs(sobel_x)
sobel_y_abs = cv2.convertScaleAbs(sobel_y)
sobel_combined_abs = cv2.convertScaleAbs(sobel_combined)
# 显示结果
plt.figure(figsize=(12, 6))
plt.subplot(2, 2, 1), plt.imshow(image, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 2), plt.imshow(sobel_x_abs, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 3), plt.imshow(sobel_y_abs, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 4), plt.imshow(sobel_combined_abs, cmap='gray')
plt.title('Sobel Combined'), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()
# 保存结果
cv2.imwrite('sobel_x.png', sobel_x_abs)
cv2.imwrite('sobel_y.png', sobel_y_abs)
cv2.imwrite('sobel_combined.png', sobel_combined_abs)
3.Scharr 算子
(1)概念
Scharr算子是Sobel算子的改进版本,同样用于边缘检测的离散微分算子。它在计算图像梯度时使用了优化的卷积核,能够提供更好的旋转对称性和更高的精度,特别是在检测45度方向的边缘时表现更优。
(2)使用
下面的代码实现了以灰度模式读取test.png图像,然后分别计算x方向和y方向的Scharr梯度,通过平方和开方合并两个方向的梯度结果。代码将浮点型梯度数据转换为8位无符号整型以便显示,最后用Matplotlib并排展示原始图像、水平梯度、垂直梯度及综合梯度结果图,同时将三个梯度结果分别保存为PNG文件。整个过程展示了Scharr算子提取图像边缘特征的基本流程。
python
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读取图片
image = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# Scharr算子边缘检测
scharr_x = cv2.Scharr(image, cv2.CV_64F, 1, 0) # x方向
scharr_y = cv2.Scharr(image, cv2.CV_64F, 0, 1) # y方向
scharr_combined = np.sqrt(scharr_x**2 + scharr_y**2) # 合并x和y方向
# 转换为8位无符号整型
scharr_x_abs = cv2.convertScaleAbs(scharr_x)
scharr_y_abs = cv2.convertScaleAbs(scharr_y)
scharr_combined_abs = cv2.convertScaleAbs(scharr_combined)
# 显示结果
plt.figure(figsize=(12, 6))
plt.subplot(2, 2, 1), plt.imshow(image, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 2), plt.imshow(scharr_x_abs, cmap='gray')
plt.title('Scharr X'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 3), plt.imshow(scharr_y_abs, cmap='gray')
plt.title('Scharr Y'), plt.xticks([]), plt.yticks([])
plt.subplot(2, 2, 4), plt.imshow(scharr_combined_abs, cmap='gray')
plt.title('Scharr Combined'), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()
# 保存结果
cv2.imwrite('scharr_x.png', scharr_x_abs)
cv2.imwrite('scharr_y.png', scharr_y_abs)
cv2.imwrite('scharr_combined.png', scharr_combined_abs)
4.Laplacian 算子
(1)概念
Laplacian算子是一种基于二阶微分的边缘检测算子,通过计算图像的二阶导数来检测边缘。与Sobel和Scharr算子不同,Laplacian算子对图像中的灰度突变(如边缘、角点等)更加敏感,能够同时检测出边缘的位置和方向变化。
(2)使用
下面的代码实现了以灰度模式读取test.png图像,然后使用Laplacian算子计算二阶导数,并将结果转换为8位无符号整型以便显示。最后用Matplotlib展示原始图像和Laplacian边缘检测结果,同时保存Laplacian结果图。
python
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读取图片
image = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# Laplacian算子边缘检测
laplacian = cv2.Laplacian(image, cv2.CV_64F) # 计算Laplacian
# 转换为8位无符号整型
laplacian_abs = cv2.convertScaleAbs(laplacian)
# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1), plt.imshow(image, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(laplacian_abs, cmap='gray')
plt.title('Laplacian Edge Detection'), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()
# 保存结果
cv2.imwrite('laplacian.png', laplacian_abs)
