第4章 经典边缘检测算子(上)
Roberts算子 · Prewitt算子 · Laplacian算子 — 原理与代码实现
边缘是图像中灰度发生剧烈变化的位置,经典的微分算子通过卷积核近似梯度。本章深入讲解三种基础算子的数学原理、特性与 Python 实现,为后续 Canny 等高级算子打下根基。
| 算子 | 类型 | 核大小 | 方向敏感性 | 对噪声 |
|---|---|---|---|---|
| Roberts | 一阶差分 | 2×2 | 对角 | 敏感 |
| Prewitt | 一阶导数 | 3×3 | 水平/垂直 | 有一定抑制 |
| Laplacian | 二阶导数 | 3×3 | 各向同性 | 非常敏感 |
1. Roberts 交叉梯度算子
Roberts 算子利用局部差分寻找边缘,采用 2×2 对角差分:
核定义:
Gx = [[1, 0], [0, -1]] Gy = [[0, 1], [-1, 0]]
Gx = [[1, 0], [0, -1]] Gy = [[0, 1], [-1, 0]]
梯度幅值近似为 |Gx| + |Gy|。优点是计算极快,但对噪声敏感。
import cv2
import numpy as np
def roberts_edge(image):
# 2x2 核
kernel_x = np.array([[1, 0], [0, -1]], dtype=np.float32)
kernel_y = np.array([[0, 1], [-1, 0]], dtype=np.float32)
grad_x = cv2.filter2D(image, cv2.CV_32F, kernel_x)
grad_y = cv2.filter2D(image, cv2.CV_32F, kernel_y)
edge = cv2.magnitude(grad_x, grad_y)
return cv2.convertScaleAbs(edge)
2. Prewitt 算子
Prewitt 使用 3×3 核,在中心行/列赋予更高权重,平滑噪声的同时计算梯度:
水平核 Gx: [[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]]
垂直核 Gy: [[-1, -1, -1], [0, 0, 0], [1, 1, 1]]
垂直核 Gy: [[-1, -1, -1], [0, 0, 0], [1, 1, 1]]
相比 Roberts,Prewitt 对噪声有更好的鲁棒性,且能分别提取水平与垂直边缘。
def prewitt_edge(image):
kernel_x = np.array([[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]], dtype=np.float32)
kernel_y = np.array([[-1, -1, -1],
[ 0, 0, 0],
[ 1, 1, 1]], dtype=np.float32)
grad_x = cv2.filter2D(image, cv2.CV_32F, kernel_x)
grad_y = cv2.filter2D(image, cv2.CV_32F, kernel_y)
edge = cv2.magnitude(grad_x, grad_y)
return cv2.convertScaleAbs(edge)
3. Laplacian 算子
Laplacian 是二阶微分算子,各向同性,对边缘产生零交叉。常用 3×3 核:
标准核: [[0, 1, 0], [1, -4, 1], [0, 1, 0]] 或带对角扩展 [[1,1,1],[1,-8,1],[1,1,1]]
由于二阶导数对噪声极度敏感,通常先做高斯平滑再应用 Laplacian (LoG)。
def laplacian_edge(image):
# 使用 OpenCV 内置 Laplacian
lap = cv2.Laplacian(image, cv2.CV_32F, ksize=3)
edge = cv2.convertScaleAbs(lap)
return edge
# 或者自定义核
def laplacian_custom(image):
kernel = np.array([[0, 1, 0],
[1, -4, 1],
[0, 1, 0]], dtype=np.float32)
lap = cv2.filter2D(image, cv2.CV_32F, kernel)
return cv2.convertScaleAbs(lap)