OpenCV 边缘检测(Edge Detection)cv2.Canny
flyfish
import cv2video_path = 'input_video.mp4'
cap = cv2.VideoCapture(video_path)while True:ret, frame = cap.read()if not ret:break # 视频结束# 转灰度frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 高斯模糊(减少噪声)blurred = cv2.GaussianBlur(frame_gray, (5, 5), 0)# 边缘检测**edges = cv2.Canny(blurred, threshold1=100, threshold2=200) # Canny 算子参数# 可视化结果cv2.imshow('Original Frame', frame)cv2.imshow('Edges', edges) # 显示边缘检测结果if cv2.waitKey(1) == ord('q'):breakcap.release()
cv2.destroyAllWindows()
解释
1. 边缘检测(Canny 算子)
edges = cv2.Canny(blurred, threshold1=100, threshold2=200)
cv2.Canny
函数:
OpenCV 中经典的边缘检测算法,通过梯度运算和阈值处理检测图像边缘。- 参数说明:
blurred
:输入的模糊后的灰度图像(减少噪声后效果更好)。threshold1=100
:低阈值(用于检测弱边缘)。threshold2=200
:高阈值(用于检测强边缘)。- 强边缘会被保留,弱边缘如果与强边缘相连也会被保留,否则被丢弃。
- 返回值
edges
是单通道二值图像(0 表示非边缘,255 表示边缘)。
2. 显示边缘结果
cv2.imshow('Edges', edges)
- 窗口显示:
新增一个窗口Edges
,显示检测到的边缘(黑白图像,白色为边缘)。 - 同时显示原图:
cv2.imshow('Original Frame', frame)
可选保留,方便对比。
参数调整建议
(1) 阈值参数 threshold1
和 threshold2
- 默认值
100
和200
:适用于大多数场景,但需根据视频内容调整。 - 调整方向:
- 提高阈值(如
threshold1=150, threshold2=250
):
减少边缘检测的敏感度,抑制噪声干扰,但可能丢失细节。 - 降低阈值(如
threshold1=50, threshold2=150
):
增加敏感度,检测更多边缘,但可能包含更多噪声。
- 提高阈值(如
(2) 高斯模糊的核大小
- 当前设置
(5,5)
:平衡去噪和保留细节。 - 调整方向:
- 增大核(如
(7,7)
):更强的去噪,但边缘可能更模糊。 - 减小核(如
(3,3)
):保留更多细节,但噪声可能更明显。
- 增大核(如
扩展功能(可选)
1. 在原图上绘制边缘
如果希望将边缘叠加到原图上(彩色显示),可以这样做:
# 将边缘图转换为三通道图像(与原图合并)
edges_color = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
# 合并原图和边缘图(横向拼接)
combined = np.hstack((frame, edges_color))
cv2.imshow('Combined', combined)
2. 调整 Canny 的其他参数
apertureSize
:Sobel 算子的核大小(默认3
,可选5
增加边缘检测的鲁棒性):edges = cv2.Canny(blurred, 100, 200, apertureSize=5)
Canny 边缘检测是一种经典且广泛应用的边缘检测算法,它具有低错误率、高定位精度和抑制虚假边缘等优点。
1. 高斯平滑
在进行边缘检测之前,图像中可能存在噪声,这些噪声会干扰边缘的检测结果。因此,第一步通常是对图像进行高斯平滑处理,使用高斯滤波器来减少噪声。高斯滤波器是一个二维的高斯函数,它对图像中的每个像素及其邻域像素进行加权平均,使得噪声的影响得到抑制。具体来说,就是通过 cv2.GaussianBlur
这样的操作,将图像中的高频噪声去除,让图像变得更加平滑,为后续的边缘检测做准备。
2. 计算梯度强度和方向
经过高斯平滑后的图像,需要计算其梯度信息,因为边缘通常对应着图像中灰度值变化较大的区域,而梯度可以反映这种变化。一般使用 Sobel 算子分别在水平( x x x 方向)和垂直( y y y 方向)计算梯度。
- 水平梯度计算:使用 3 × 3 3\times3 3×3 的 Sobel 算子 G x G_x Gx 与图像进行卷积操作,得到水平方向的梯度分量 G x G_x Gx。
- 垂直梯度计算:使用 3 × 3 3\times3 3×3 的 Sobel 算子 G y G_y Gy 与图像进行卷积操作,得到垂直方向的梯度分量 G y G_y Gy。
- 梯度强度计算:根据 G x G_x Gx 和 G y G_y Gy 计算梯度的强度 G G G,计算公式为 G = G x 2 + G y 2 G=\sqrt{G_x^2 + G_y^2} G=Gx2+Gy2。
- 梯度方向计算:计算梯度的方向 θ \theta θ,计算公式为 θ = arctan ( G y G x ) \theta=\arctan(\frac{G_y}{G_x}) θ=arctan(GxGy)。梯度方向通常被近似为四个方向之一: 0 ∘ 0^{\circ} 0∘、 4 5 ∘ 45^{\circ} 45∘、 9 0 ∘ 90^{\circ} 90∘ 或 13 5 ∘ 135^{\circ} 135∘。
3. 非极大值抑制
在计算得到梯度强度和方向后,图像中可能存在很多梯度强度较大的点,但这些点不一定都对应真正的边缘。非极大值抑制的目的是在局部范围内找出梯度强度的极大值点,将非极大值点的梯度值设为 0,从而细化边缘。具体步骤如下:
- 对于每个像素点,根据其梯度方向,判断其在梯度方向上的相邻像素点。
- 如果该像素点的梯度强度小于其相邻像素点的梯度强度,则将该像素点的梯度值设为 0;否则,保留该像素点的梯度值。
4. 双阈值检测和边缘连接
经过非极大值抑制后,仍然可能存在一些虚假的边缘点。双阈值检测通过设置两个阈值(低阈值 T l o w T_{low} Tlow 和高阈值 T h i g h T_{high} Thigh)来进一步筛选边缘点。具体步骤如下:
- 强边缘点确定:将梯度强度大于高阈值 T h i g h T_{high} Thigh 的像素点标记为强边缘点,这些点肯定是边缘点。
- 弱边缘点确定:将梯度强度介于低阈值 T l o w T_{low} Tlow 和高阈值 T h i g h T_{high} Thigh 之间的像素点标记为弱边缘点,这些点可能是边缘点,也可能是噪声。
- 边缘连接:检查弱边缘点是否与强边缘点相连。如果弱边缘点与强边缘点相连,则将其标记为边缘点;否则,将其视为噪声并去除。
操作图像的示例代码
import cv2# 读取图像
image = cv2.imread('example.jpg', 0) # 以灰度模式读取图像# 进行 Canny 边缘检测
edges = cv2.Canny(image, 100, 200)# 显示原始图像和边缘检测结果
cv2.imshow('Original Image', image)
cv2.imshow('Canny Edges', edges)# 等待按键事件
cv2.waitKey(0)# 关闭所有窗口
cv2.destroyAllWindows()
cv2.Canny
函数的第二个和第三个参数分别是低阈值和高阈值,你=可以根据实际情况调整这两个参数的值,以获得不同的边缘检测效果。