951 字
5 分钟
[计算机视觉] Harris哈里斯角点检测

基本思想#

想象一个小窗口在图像上滑动,可以分为三种情况:

  1. 窗口在大面积像素值相近的平坦区域:无论怎么移动,窗口内的像素值变化都很小
  2. 窗口在平直边缘上:沿着边缘方向移动,像素值变化很小;垂直于边缘方向移动,像素值变化很大
  3. 窗口在角点上:无论怎么移动,窗口内的像素值变化都很大

所以我们只要找到无论怎么移动窗口,像素值变化都很大的点,也就是像素值变化量的最小值大于一个阈值的点,就可以认为它是一个角点

推导#

假设窗口每次移动(u,v)(u, v),窗口内像素值的变化可以用平方差之和来表示为:

E(u,v)=x,y[I(x+u,y+v)I(x,y)]2E(u, v) = \sum_{x, y} [I(x + u, y + v) - I(x, y)]^2
  • I(x,y)I(x, y):图像在点(x,y)(x, y)的像素值,后续简写为IxI_xIyI_y

因为uuvv很小,所以可以使用泰勒展开来近似I(x+u,y+v)I(x + u, y + v)

I(x+u,y+v)I(x,y)+Ixu+Iyv=I(x,y)+[IxIy][uv]\begin{aligned} I(x + u, y + v) &\approx I(x, y) + I_x \cdot u + I_y \cdot v \\[1em] &= I(x, y) + \begin{bmatrix}I_x & I_y\end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix} \end{aligned}
  • IxI_xIyI_y:图像在点(x,y)(x, y)的水平和垂直方向的梯度

所以:

E(u,v)x,y([IxIy][uv])2=x,y([IxIy][uv])T([IxIy][uv])=x,y[uv][Ix2IxIyIxIyIy2][uv]\begin{aligned} E(u, v) &\approx \sum_{x, y} \left (\begin{bmatrix}I_x & I_y\end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix}\right )^2 \\[1em] &= \sum_{x, y} \left(\begin{bmatrix}I_x & I_y\end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix} \right )^T \left(\begin{bmatrix}I_x & I_y\end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix} \right ) \\[1em] &= \sum_{x, y} \begin{bmatrix}u & v\end{bmatrix} \begin{bmatrix}I_x^2 & I_x I_y \\ I_x I_y & I_y^2\end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix} \\[1em] \end{aligned}

给中间矩阵取个名字:

H=[Ix2IxIyIxIyIy2]H = \begin{bmatrix}I_x^2 & I_x I_y \\ I_x I_y & I_y^2\end{bmatrix}

为了防止解出u=v=0u=v=0的平凡解,所以设置约束d2=u2+v2=1\Vert \mathbf{d}\Vert^2 = u^2 + v^2 = 1,所以就转化为求解如下问题:

mind2=1dTHd\underset{\Vert \mathbf{d} \Vert^2 = 1}{\text{min}} \quad \mathbf{d}^T H \mathbf{d}

构造拉格朗日函数#

L(d,λ)=dTHdλ(dTd1)=u2H11+2uvH12+v2H22λ(u2+v21)\begin{aligned} \mathcal{L}(\mathbf{d}, \lambda) &= \mathbf{d}^T H \mathbf{d} - \lambda (\mathbf{d}^T \mathbf{d} - 1) \\[1em] &= u^2 H_{11} + 2 u v H_{12} + v^2 H_{22} - \lambda (u^2 + v^2 - 1) \end{aligned}

uu求导并设置为零:

Lu=2uH11+2vH122λu=0uH11+vH12=λu\begin{aligned} \frac{\partial \mathcal{L}}{\partial u} = 2 u H_{11} + 2 v H_{12} - 2 \lambda u &= 0 \\[1em] u H_{11} + v H_{12} &= \lambda u \end{aligned}

vv求导并设置为零:

Lv=2uH12+2vH222λv=0uH12+vH22=λv\begin{aligned} \frac{\partial \mathcal{L}}{\partial v} = 2 u H_{12} + 2 v H_{22} - 2 \lambda v &= 0 \\[1em] u H_{12} + v H_{22} &= \lambda v \end{aligned}

得到方程组:

{uH11+vH12=λuuH12+vH22=λv\begin{cases} u H_{11} + v H_{12} = \lambda u \\ u H_{12} + v H_{22} = \lambda v \end{cases}

可以写成矩阵形式:

[H11H12H12H22][uv]=λ[uv]Hd=λd\begin{aligned} \begin{bmatrix} H_{11} & H_{12} \\ H_{12} & H_{22} \end{bmatrix} \begin{bmatrix}u \\ v\end{bmatrix} &= \lambda \begin{bmatrix}u \\ v\end{bmatrix} \\[1em] H \mathbf{d} &= \lambda \mathbf{d} \end{aligned}

后续步骤跟单应矩阵那块类似,先同左乘dTd^T,得到:

dTHd=λdTd=λ(约束d2=1)\mathbf{d}^T H \mathbf{d} = \lambda \mathbf{d}^T \mathbf{d} = \lambda \qquad (\text{约束}\Vert \mathbf{d} \Vert^2 = 1)

所以最小化dTHd\mathbf{d}^T H \mathbf{d}等价于最小化λ\lambda,如果这个最小特征值大于一个阈值,就认为这个点是一个角点,但是这种方法需要计算特征值,比较麻烦,所以Harris提出了一个角点响应函数来避免计算特征值

角点响应函数#

R=det(H)ktrace(H)2R = \text{det}(H) - k \cdot \text{trace}(H)^2
  • λ1,λ2\lambda_1,\lambda_2HH的两个特征值
  • det(H)=λ1λ2\text{det}(H) = \lambda_1 \lambda_2:特征值的乘积,表示窗口内像素值变化的程度
  • trace(H)=λ1+λ2\text{trace}(H) = \lambda_1 + \lambda_2:特征值的和,表示窗口内像素值变化的总量
  • kk:经验参数,通常取0.04到0.06之间

当处于角点,λ1\lambda_1λ2\lambda_2都较大且相当,此时乘积会远大于和的平方,所以RR为很大的正值;当处于边缘,λ1\lambda_1λ2\lambda_2其中一个较大的另一个较小,此时乘积会小于和的平方,所以RR为很小的负值;当平坦区域,λ1\lambda_1λ2\lambda_2其中一个较大另一个较小,此时乘积和和的平方相差不大,所以RR会接近于零

{R0角点R0边缘R0平坦区域\begin{cases} R \gg 0 & \text{角点} \\ R \ll 0 & \text{边缘} \\ R \approx 0 & \text{平坦区域} \end{cases}
[计算机视觉] Harris哈里斯角点检测
https://alkaid114.github.io/posts/cv/harris/
作者
Alkaid114
发布于
2026-06-06
许可协议
CC BY-NC-SA 4.0