角点检测
要检测图像中对象的角点,可以先检测边缘,然后确定两条边缘的交点。 然而,还有其他方法,其中包括:
Moravec检测器 [Moravec 1980],
Harris检测器 [Harris & Stephens 1988]。
Moravec检测器¶
该检测器的原理是观察一个子图像在所有方向上移动一个像素时是否发生显著变化。 如果发生显著变化,则所考虑的像素是一个角点。

Figure 1:Moravec检测器的原理。 从左到右: 在一个平坦区域,子图像(红色)的微小移动不会引起任何变化; 在一个轮廓上,我们只在一个方向上观察到变化; 在一个角点周围,所有方向上都有显著的变化。
在数学上,图像中每个像素 的变化由 来表征,它表示偏移 后子图像之间的差异:
其中:
和 表示四个方向上的偏移:,
是围绕像素 的一个矩形窗口,
是子图像 与偏移后的图像块 之间的差异,
在每个像素 处,保留 在四个方向上的最小值,并记为 。 最后,检测到的角点对应于 的局部最大值, 即在像素 处, 的最小值较大。
事实证明,Moravec检测器有几个局限性。 首先, 是一个二值窗口,因此检测器对窗口中的所有像素都给予相同的权重。 当图像中的噪声很高时,可能导致错误的角点检测。 其次,只考虑了四个方向。 第三,由于只考虑了 的最小值,检测器对边缘仍然非常敏感。 由于这些原因,Harris提出了一个检测器来克服这些局限性。
Harris检测器¶
为了避免噪声响应,Moravec检测器的矩形窗口 在 的表达式中被替换为高斯窗口 。
为了将Moravec检测器扩展到所有方向,而不仅限于最初的四个方向, 对移位的子图像 进行泰勒级数展开:
因此:
这个表达式可以写成以下矩阵形式:
其中
矩阵 是结构张量,由图像的一阶导数构建而成。它是一个对称矩阵,其特征值 和 提供了关于窗口 内局部图像结构的信息。请注意,这与基于二阶导数的海森矩阵不同。
结构张量的特征值可以解释如下(如 Figure 2 所示):
平坦区域:如果两个特征值 和 都很小,这意味着在任何方向上的强度变化都很小。
边缘:如果一个特征值很大而另一个很小(例如 ),这表示在一个方向上有强梯度,但在正交方向上没有。
角点:如果两个特征值都很大( 和 都很大,且 ),这表示在多个方向上有显著的强度变化,这对应于一个角点。

Figure 2:根据特征值做出的决策。
计算 的特征值可能很困难,因此一个替代方法是计算:
其中 。
因此, 的值在平坦区域较低,在边缘上为负,在角点上为正 (Figure 3)。

Figure 3:根据 做出的决策。

Harris检测器在 Figure 5 的例子中得到了说明。
Figure 5:Harris检测器。 二值图像表示系数 的负值(轮廓)、弱值(平坦区域)和正值(角点)。
代码示例¶
这是一个使用 scikit-image 库进行Harris角点检测的示例。我们将使用一个棋盘格图像,这对于演示角点检测非常理想。
import matplotlib.pyplot as plt
from skimage import data
from skimage.feature import corner_harris, corner_subpix, corner_peaks
# 配置中文字体支持
plt.rcParams['font.sans-serif'] = [
'Noto Sans CJK SC', 'Noto Sans CJK JP', 'SimHei',
'Microsoft YaHei', 'WenQuanYi Micro Hei', 'DejaVu Sans'
]
plt.rcParams['axes.unicode_minus'] = False
# 创建一个样本图像
image = data.checkerboard()
# 计算Harris角点响应图像
coords = corner_peaks(corner_harris(image), min_distance=5, threshold_rel=0.02)
# 寻找亚像素角点估计
coords_subpix = corner_subpix(image, coords, window_size=13)
# 显示结果
fig, ax = plt.subplots()
ax.imshow(image, cmap=plt.cm.gray)
ax.plot(coords[:, 1], coords[:, 0], '.b', markersize=3)
ax.plot(coords_subpix[:, 1], coords_subpix[:, 0], '+r', markersize=15)
ax.axis((0, 350, 350, 0))
plt.show()
