一、什么是边缘检测
边缘(Edge)本质上是:
图像灰度值发生剧烈变化的位置
例如:
都属于边缘。
从数学角度说:
如果图像表示为二维函数:
[
f(x,y)
]
那么边缘就是:
[
\left|\nabla f(x,y)\right|
]
变化最大的区域。(维基百科)
二、边缘检测核心原理
本质就是求 像素梯度(导数)。
1)一阶导数:梯度边缘
梯度定义:
[
G=\sqrt{G_x^2+G_y^2}
]
其中:
梯度越大,越可能是边缘。
2)二阶导数:Laplacian
二阶导数更适合检测:
公式:
[
\nabla^2 f=\frac{\partial^2 f}{\partial x^2}+\frac{\partial^2 f}{\partial y^2}
]
三、经典边缘检测算法
1)Sobel 算法(最常用入门)
Sobel 使用两个卷积核分别计算水平和垂直梯度。(Muegenai)
X方向卷积核
[
\begin{bmatrix}
-1 & 0 & 1 \
-2 & 0 & 2 \
-1 & 0 & 1
\end{bmatrix}
]
Y方向卷积核
[
\begin{bmatrix}
-1 & -2 & -1 \
0 & 0 & 0 \
1 & 2 & 1
\end{bmatrix}
]
Python 实现(纯 OpenCV)
import cv2
import numpy as np
img = cv2.imread("test.jpg", 0)
sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
magnitude = cv2.magnitude(sobel_x, sobel_y)
cv2.imshow("sobel", np.uint8(magnitude))
cv2.waitKey(0)
纯 Python 手写 Sobel(深入理解)
import cv2
import numpy as np
img = cv2.imread("test.jpg", 0)
kernel_x = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]
])
kernel_y = np.array([
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]
])
h, w = img.shape
result = np.zeros((h, w))
for i in range(1, h - 1):
for j in range(1, w - 1):
region = img[i-1:i+2, j-1:j+2]
gx = np.sum(region * kernel_x)
gy = np.sum(region * kernel_y)
result[i, j] = np.sqrt(gx**2 + gy**2)
result = np.clip(result, 0, 255).astype(np.uint8)
cv2.imshow("manual sobel", result)
cv2.waitKey(0)
四、Canny 边缘检测(工业级最常用)
Canny 是实际项目里最经典的边缘检测算法。(维基百科)
它包含 5个核心步骤:
第一步:高斯滤波去噪
先消除噪声:
blur = cv2.GaussianBlur(img, (5, 5), 1.4)
第二步:计算梯度
底层仍然是 Sobel。
[
G=\sqrt{G_x^2+G_y^2}
]
第三步:非极大值抑制(NMS)
作用:
让边缘从“粗线”变成“细线”
保留局部最大值。
第四步:双阈值检测
两个阈值:
第五步:滞后阈值连接
如果弱边缘连接强边缘,则保留,否则去掉。(Python Geeks)
Python 实现 Canny
import cv2
img = cv2.imread("test.jpg", 0)
edges = cv2.Canny(img, 100, 200)
cv2.imshow("canny", edges)
cv2.waitKey(0)
五、自己手写 Canny(核心流程版)
下面给你一个简化版流程,适合算法学习。
import cv2
import numpy as np
img = cv2.imread("test.jpg", 0)
# 1 高斯滤波
blur = cv2.GaussianBlur(img, (5, 5), 1)
# 2 Sobel梯度
gx = cv2.Sobel(blur, cv2.CV_64F, 1, 0)
gy = cv2.Sobel(blur, cv2.CV_64F, 0, 1)
mag = np.sqrt(gx**2 + gy**2)
angle = np.arctan2(gy, gx)
如果你继续深入,可以再实现:
就接近完整工业版。
六、Sobel vs Canny 对比
| 算法 | 优点 | 缺点 | 场景 |
|---|
| Sobel | 快、简单 | 噪声敏感 | 教学、预处理 |
| Laplacian | 细节强 | 容易误检 | 纹理检测 |
| Canny | 精度高、边缘细 | 计算复杂 | 工业视觉 |
(OpenCV)
七、工程实战:视频实时边缘检测
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 80, 150)
cv2.imshow("edge", edges)
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
适用于:
- 摄像头轮廓识别
- 实时车道线检测
- OCR 预处理
- 缺陷检测
八、生产级优化思路(非常重要)
你做实际项目时建议这样优化:
1)先做 CLAHE 增强
clahe = cv2.createCLAHE(clipLimit=2.0)
img = clahe.apply(img)
提升低对比度边缘。
2)边缘后做形态学闭运算
kernel = np.ones((3,3), np.uint8)
edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
连接断裂边缘。
3)结合霍夫变换
用于:
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100)
九、边缘检测在 AI / CV 中的作用
边缘是很多高级算法的第一步:
- OCR文字识别
- 图像分割
- 人脸检测
- 目标检测
- 视频跟踪
- 缺陷检测
- 医学影像
十、总结(面试高频)
核心记忆:
Sobel
一阶梯度 + 卷积核
Canny
高斯滤波 → 梯度 → NMS → 双阈值 → 边缘连接
最佳实践
如果你做生产系统:
优先 Canny + CLAHE + Morphology
这是工业视觉最稳的一套。