图像边缘检测
在 OpenCV 中,图像边缘检测是提取图像中灰度变化剧烈区域的重要技术,广泛应用于目标识别、图像分割等领域。以下是四种常用边缘检测算法的简单介绍:
1. Sobel 算子
原理:基于一阶导数计算,通过卷积核在图像的水平(X 方向)和垂直(Y 方向)分别进行梯度运算,检测边缘的强度和方向。
特点:对噪声有一定抑制能力,计算效率高。
需分别计算 X、Y 方向梯度,再通过加权融合得到完整边缘。
边缘检测效果中等,可能存在边缘较粗或模糊的情况。
适用场景:实时性要求较高、对边缘精度要求不极致的场景,如简单目标轮廓提取。
2. Scharr 算子
原理:是 Sobel 算子的改进版本,使用更精确的卷积核系数,增强了对边缘的敏感性,尤其在小算子(3x3)时效果更优。
特点:与 Sobel 算子参数用法类似,但边缘检测更灵敏,细节保留更好。
对弱边缘的响应更强,适合检测细微边缘。
适用场景:需要保留更多边缘细节的场景,如纹理丰富的图像边缘提取。
3. Laplacian 算子
原理:基于二阶导数计算,通过检测图像中灰度的二阶变化率(拐点)来识别边缘,本质是对图像进行二阶差分运算。
特点:对噪声非常敏感,通常需要先进行高斯模糊降噪。
边缘检测结果是双向的(正负边缘),需通过绝对值转换处理。
能检测出图像中所有方向的边缘,但边缘定位精度较低。
适用场景:对边缘方向无偏好的场景,或作为其他边缘检测算法的辅助步骤。
4. Canny 算子
原理:一种多阶段边缘检测算法,包括高斯降噪、梯度计算、非极大值抑制(边缘细化)、双阈值筛选(确定强 / 弱边缘)和边缘连接五个步骤。
特点:边缘定位准确,抗噪声能力强,能有效检测出真正的边缘并抑制虚假边缘。
输出的边缘通常是单像素宽度,连续性好。
需手动设置两个阈值(高阈值和低阈值),阈值选择对结果影响较大。
适用场景:对边缘质量要求高的场景,如目标检测、图像分割等核心任务,是实际应用中最常用的边缘检测算法。
案例:对一片图片分别进行这四种算子处理
代码实现:
import cv2
'''------边缘检测------'''
'''sobel算子'''
hw = cv2.imread('2197.jpg',0)
hw = cv2.resize(hw,dsize=None,fx=0.2,fy=0.2)
cv2.imshow('yuantu',hw)
cv2.waitKey(0)
hw_x_64 = cv2.Sobel(hw,cv2.CV_64F,dx=1,dy=0)
hw_x_full = cv2.convertScaleAbs(hw_x_64)
hw_y_64 = cv2.Sobel(hw,cv2.CV_64F,dx=0,dy=1)
hw_y_full = cv2.convertScaleAbs(hw_y_64)
hw_xy_full = cv2.addWeighted(hw_x_full,1,hw_y_full,1,10)
cv2.imshow('hw_xy_sobel_fill',hw_xy_full)
cv2.waitKey(0)'''scharr算子'''
hw_x_64 = cv2.Scharr(hw,cv2.CV_64F,dx=1,dy=0)
hw_x_full = cv2.convertScaleAbs(hw_x_64)
hw_y_64 = cv2.Scharr(hw,cv2.CV_64F,dx=0,dy=1)
hw_y_full = cv2.convertScaleAbs(hw_y_64)
hw_xy_full = cv2.addWeighted(hw_x_full,1,hw_y_full,1,10)
cv2.imshow('hw_xy_scharr_fill',hw_xy_full)
cv2.waitKey(0)'''Laplacian算子'''
hw_lap =cv2.Laplacian(hw,cv2.CV_64F)
hw_lap_full = cv2.convertScaleAbs(hw_lap)
cv2.imshow('hw_laplacian_full',hw_lap_full)
cv2.waitKey(0)'''Canny算子'''hw_canny = cv2.Canny(hw,190,240)
cv2.imshow('hw_canny',hw_canny)
cv2.waitKey(0)
代码解析:
导入 OpenCV 库
import cv2
导入 OpenCV 库,用于图像处理和边缘检测。
图像读取与预处理
hw = cv2.imread('2197.jpg', 0) # 以灰度模式读取图像 hw = cv2.resize(hw, dsize=None, fx=0.2, fy=0.2) # 将图像缩小到原来的20% cv2.imshow('yuantu', hw) # 显示原图 cv2.waitKey(0) # 等待按键输入,0表示无限等待
- 读取图像时使用参数
0
将图像直接转为灰度图,简化后续处理 - 图像缩小是为了加快处理速度并适应显示窗口
cv2.waitKey(0)
确保图像窗口会一直显示,直到用户按下任意键
- 读取图像时使用参数
Sobel 算子边缘检测
# 计算X方向边缘 hw_x_64 = cv2.Sobel(hw, cv2.CV_64F, dx=1, dy=0) hw_x_full = cv2.convertScaleAbs(hw_x_64)# 计算Y方向边缘 hw_y_64 = cv2.Sobel(hw, cv2.CV_64F, dx=0, dy=1) hw_y_full = cv2.convertScaleAbs(hw_y_64)# 合并X和Y方向边缘 hw_xy_full = cv2.addWeighted(hw_x_full, 1, hw_y_full, 1, 10) cv2.imshow('hw_xy_sobel_fill', hw_xy_full) cv2.waitKey(0)
cv2.Sobel()
计算图像梯度,dx=1, dy=0
检测水平方向边缘,dx=0, dy=1
检测垂直方向边缘- 使用
cv2.CV_64F
数据类型是为了保留梯度的正负值(边缘可能是从亮到暗或从暗到亮) cv2.convertScaleAbs()
将结果转换为绝对值并转为 8 位图像,确保边缘不会丢失cv2.addWeighted()
将 X 和 Y 方向的边缘按权重合并,得到完整的边缘图像
Scharr 算子边缘检测
hw_x_64 = cv2.Scharr(hw, cv2.CV_64F, dx=1, dy=0) hw_x_full = cv2.convertScaleAbs(hw_x_64) hw_y_64 = cv2.Scharr(hw, cv2.CV_64F, dx=0, dy=1) hw_y_full = cv2.convertScaleAbs(hw_y_64) hw_xy_full = cv2.addWeighted(hw_x_full, 1, hw_y_full, 1, 10) cv2.imshow('hw_xy_scharr_fill', hw_xy_full) cv2.waitKey(0)
- Scharr 算子是 Sobel 算子的改进版,在 3x3 核的情况下能提供更精确的梯度计算
- 使用方法与 Sobel 算子完全相同,但通常能检测到更细微的边缘
Laplacian 算子边缘检测
hw_lap = cv2.Laplacian(hw, cv2.CV_64F) hw_lap_full = cv2.convertScaleAbs(hw_lap) cv2.imshow('hw_laplacian_full', hw_lap_full) cv2.waitKey(0)
- Laplacian 算子计算二阶导数,对图像中的快速变化(边缘)很敏感
- 它对噪声更敏感,但能同时检测多个方向的边缘,不需要分别计算 X 和 Y 方向
Canny 算子边缘检测
hw_canny = cv2.Canny(hw, 190, 240) cv2.imshow('hw_canny', hw_canny) cv2.waitKey(0)
- Canny 是一种多阶段的边缘检测算法,效果通常更好
- 两个参数 (190, 240) 是高低阈值:低于低阈值的点被丢弃,高于高阈值的点被保留为边缘,介于两者之间的点只有与边缘点相连时才被保留
- Canny 算法能有效抑制噪声并检测出真正的边缘