更多学习:四种边缘检测
边缘检测
1. 边缘检测的概念
在图像处理中,**边缘(Edge)**是像素灰度值急剧变化的区域,通常对应图像中的物体边界、纹理或者结构特征。检测边缘有助于我们提取图像的几何结构,广泛应用于物体识别、分割和计算机视觉任务。
最常见的边缘检测方法之一就是 Sobel 算子。
2. Sobel 算子的基本原理
Sobel 算子通过计算图像在 水平方向(x) 和 垂直方向(y) 的梯度,来检测图像的边缘。
-
梯度(Gradient):反映灰度值变化的快慢,变化越大说明该区域越可能是边缘。
-
Sobel 算子在计算时,会结合平滑 和微分操作,减少噪声干扰。
其常见的卷积核为:
- 水平方向(x方向)核:

- 垂直方向(y方向)核:

通过与图像进行卷积,分别得到 x方向梯度 和 y方向梯度,再进行组合就能得到最终的边缘。
3. cv2.Sobel() 函数
在 OpenCV 中,Sobel 算子的函数为:
cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
参数说明:
参数 | 说明 |
---|---|
src | 输入图像(一般用灰度图像) |
ddepth | 输出图像的深度。常用 cv2.CV_64F,避免数据溢出 |
dx | x方向的差分阶数(1 表示一阶导数) |
dy | y方向的差分阶数(1 表示一阶导数) |
ksize | Sobel 核大小,必须是 1, 3, 5, 7(常用 3) |
scale | 可选参数,缩放导数值 |
delta | 可选参数,结果加上某个值 |
borderType | 边界填充方式,默认 cv2.BORDER_DEFAULT |
4. 代码解析与效果
可直接使用下图,也可自备图片:但是要记得灰度处理(根据需要也可以尝试彩色)

所有处理后的结果:


(1)读取与显示图像
import cv2
img = cv2.imread('violet.jpg',cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img,(800,500))
cv2.imshow('img', img)
cv2.waitKey(0)
-
使用灰度图像,便于边缘提取。
-
图像缩放到合适大小,便于展示。
(2)x方向的边缘
# x方向上的边缘
img_x = cv2.Sobel(img, -1, dx=1, dy=0)
cv2.imshow('img_x', img_x)
cv2.waitKey(0)
-
这里
dx=1, dy=0
,表示只计算水平方向的梯度。 -
能突出 竖直边缘(例如物体左右边界)。
-
使用
-1
表示输出图像深度与原图相同。
(3)保留负值信息
# x方向上的边缘,包含负值信息(直接显示不出来,因为范围是0~255)
img_x_64 = cv2.Sobel(img, cv2.CV_64F, dx=1, dy=0) # 默认uint8改为float64, 可保存负数
cv2.imshow('img_x_64', img_x_64)
cv2.waitKey(0)
-
cv2.CV_64F
可保存浮点数,包括正负值。 -
因为梯度可能是正数(亮到暗的变化)或负数(暗到亮的变化)。
-
但直接显示会出现"黑屏",因为显示范围是
0~255
。
(4)转换为可视化图像
# x方向上的边缘,将负数的数值信息转成可视化的数值,右端的负值信息就能显示出来了
img_x_full = cv2.convertScaleAbs(img_x_64) # 转换为绝对值,负数转换为正数
cv2.imshow('img_x_full', img_x_full)
cv2.waitKey(0)
-
将梯度的负值转换为绝对值,保证显示效果。
-
这样左右边界都能显示出来。
(5)y方向的边缘
# y方向的边缘
img_y = cv2.Sobel(img, -1, dx=0, dy=1)
cv2.imshow('img_y', img_y)
cv2.waitKey(0)
# y方向上的边缘,包括负数信息(下端),但是示不出来,因为范围是(0~255)
img_y_64= cv2.Sobel(img,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
img_y_full = cv2.convertScaleAbs(img_y_64)#转换为绝对值,负数转换为正数
cv2.imshow( 'img_y_full',img_y_full)
cv2.waitKey(0)
-
dx=0, dy=1
,表示只计算垂直方向的梯度。 -
能突出 水平边缘(例如物体上下边界)。
同样地,可以通过 cv2.CV_64F
+ cv2.convertScaleAbs
来显示完整信息。
(6)直接同时计算 x 和 y
# 同时使用x与y方向的边缘(不建议直接使用!!)
img_xy = cv2.Sobel(img, -1, dx=1, dy=1)
cv2.imshow('img_xy', img_xy)
cv2.waitKey(0)
- 这种方式会将 x 和 y 梯度直接结合,但通常效果不佳,不推荐。
(7)分别计算x和y后,加权融合
# 使用图像加权运算组合x和y方向的2个边缘
img_xy_full = cv2.addWeighted(img_x_full,1,img_y_full,1,0)
cv2.imshow('img_xy_full', img_xy_full)
cv2.waitKey(0)
cv2.destroyAllWindows()
-
更合理的方式是把
x方向
和y方向
的梯度结果加权融合。 -
addWeighted
会线性叠加两张图像。 -
得到的结果类似于常见的 梯度幅值图像,即完整的边缘检测效果。
5. 总结
-
Sobel 算子利用梯度变化检测边缘,能提取水平与垂直方向上的特征。
-
使用
cv2.CV_64F
保留负值信息,再通过cv2.convertScaleAbs
转换为可视化结果。 -
x方向突出竖直边缘,y方向突出水平边缘。
-
最佳实践是分别提取 x、y 梯度,然后再融合,得到更清晰的边缘图像。
📌 扩展 :除了 Sobel 算子,常用的边缘检测方法还有 Prewitt 算子、Laplacian 算子、Canny 算子,各有优劣,Canny 是实际应用最广的。