OpenCV 图像特征提取——Harris角点检测

OpenCV 图像特征提取

Harris 角点检测


1、什么是角点

  同角点并列的还有边界点、平面点。看下面的图可以看出来三者之间的位置关系。

从上面的图片我们可以看出来:

  • 平面:A, B
  • 边界:C, D
  • 角点:E, F

简化一点就是下面三种情况:

2、如何区分角点、边界和平面

我们使用肉眼观察很方便,但是输入到计算机里面就需要相应的算法进行识别。

三种基本情况
  • 平面: 之所以叫平面,是因为在图像窗口任意移动过程中,像素值不会发生明显的变化,趋于平滑。

  • 边界: 当图像窗口在边界范围移动时,像素值会沿一个方向基本不变,在垂直的方向发生巨大变化。可以看中间的图片,当沿 y 轴运动时,像素值不会发生大的变化。当沿 x 轴移动时会发生像素值会发生巨大变化。

  • 角点: 不同于平面和边界,图像窗口处于角点位置时,沿任意方向都会发生巨大变化。

利用上面的规则我们就可以区分角点、边界和平面。

3、角点公式推导

我们在实际中主要是观察移动前后像素值的变化情况。
1、 当图像在 ( x , y ) (x, y) (x,y) 处平移 ( Δ x , Δ y ) (\Delta x, \Delta y) (Δx,Δy) 后的自相似性:

c ( x , y ; Δ x , Δ y ) = ∑ u , v ∈ W ( x , y ) w ( u , v ) ( I ( u , v ) − I ( u + Δ x , v + Δ y ) ) 2 c(x,y;\Delta x,\Delta y) = \sum_{u,v\in W(x,y)}w(u,v)(I(u,v)-I(u+\Delta x, v+\Delta y))^2 c(x,y;Δx,Δy)=u,vW(x,y)w(u,v)(I(u,v)I(u+Δx,v+Δy))2

其中 w ( x , y ) w(x,y) w(x,y) 是以点 ( x , y ) (x, y) (x,y) 为中心的窗口,这里既可以取常数,或者是高斯加权的函数(推荐)。

2、 对上面的部分式子进行化简,泰勒展开:

I ( u + Δ x , v + Δ y ) = I ( u , v ) + I x ( u , v ) Δ x + I y ( u , v ) Δ y + O ( Δ x 2 , Δ y 2 ) ≈ I ( u , v ) + I x ( u , v ) Δ x + I y ( u , v ) Δ y I(u+\Delta x, v+\Delta y)=I(u,v)+I_x(u,v)\Delta x + I_y(u,v)\Delta y + O(\Delta x^2, \Delta y^2) \approx I(u,v)+ I_x(u, v)\Delta x + I_y(u,v)\Delta y I(u+Δx,v+Δy)=I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy+O(Δx2,Δy2)I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy

其中 I x , I y I_x,I_y Ix,Iy 分别是 x , y x, y x,y 的偏导数。

3、 进一步化简关于 c 的方程,近似可得:

c ( x , y ; Δ x , Δ y ) ≈ ∑ w ( I x ( u , v ) Δ x + I y ( u , v ) Δ y ) 2 = [ Δ x , Δ y ] M ( x , y ) [ Δ x Δ y ] c(x,y;\Delta x,\Delta y) \approx\sum_w (I_x(u, v)\Delta x + I_y(u,v)\Delta y)^2 = [\Delta x , \Delta y]M(x,y)\begin{bmatrix} \Delta x \\ \Delta y \end{bmatrix} c(x,y;Δx,Δy)w(Ix(u,v)Δx+Iy(u,v)Δy)2=[Δx,Δy]M(x,y)[ΔxΔy]

我们发现上卖弄的式子是一个平方项,我们可以使用二次型对结果进行化简,提取二次型矩阵。

4、二次型矩阵
M ( x , y ) = ∑ w [ I x ( x , y ) 2 I x ( x , y ) I y ( x , y ) I x ( x , y ) I y ( x , y ) I y ( x , y ) 2 ] = [ ∑ w I x ( x , y ) 2 ∑ w I x ( x , y ) I y ( x , y ) ∑ w I x ( x , y ) I y ( x , y ) ∑ w I y ( x , y ) 2 ] = [ A B B C ] M(x, y) = \sum_w\begin{bmatrix} I_x(x,y)^2 & I_x(x, y)I_y(x, y) \\ I_x(x, y)I_y(x, y) & I_y(x, y)^2 \end{bmatrix} = \begin{bmatrix} \sum_w I_x(x,y)^2 & \sum_w I_x(x,y)I_y(x,y)\\ \sum_w I_x(x,y)I_y(x,y) & \sum_w I_y(x,y)^2 \end{bmatrix}=\begin{bmatrix} A & B \\ B & C \end{bmatrix} M(x,y)=w[Ix(x,y)2Ix(x,y)Iy(x,y)Ix(x,y)Iy(x,y)Iy(x,y)2]=[wIx(x,y)2wIx(x,y)Iy(x,y)wIx(x,y)Iy(x,y)wIy(x,y)2]=[ABBC]
化简可得:
c ( x , y ; Δ x , Δ y ) ≈ A Δ x 2 + 2 C Δ x Δ y + B Δ y 2 c(x,y;\Delta x,\Delta y) \approx A\Delta x^2+2C\Delta x \Delta y + B \Delta y^2 c(x,y;Δx,Δy)AΔx2+2CΔxΔy+BΔy2

{ A = I x 2 B = I x I y C = I y 2 \begin{cases} A=I_x^2\\ B=I_x I_y\\ C=I_y^2 \end{cases} A=Ix2B=IxIyC=Iy2

5、 形状估计

我们可以看得出来二次项函数是一个椭圆函数,类似于: x 2 a 2 + y 2 b 2 = c \frac{x^2}{a^2}+\frac{y^2}{b^2} = c a2x2+b2y2=c,只不过是一个不过圆心的椭圆函数。
而且椭圆的大小随着 Δ x , Δ y \Delta x , \Delta y Δx,Δy的变化而变化。类似于一个锥体。

我们最后希望检测角点,我们上面提到,它的变化越大,说明是角点的可能性越大。也就是说在单位 Δ x , Δ y \Delta x , \Delta y Δx,Δy变化中,角点所在位置一般就是$A, B, C $较大值的点。实际中我们并不好利用三个值来进行判断是否是边界,平面还是角点。所以我们根据性质来减少自变量

6、 减少自变量

根据我们之前学的高数,里面有一个定理:

实对称矩阵一定可以对角化

我们的 M M M 矩阵是一个实对称矩阵( M T = M M^T = M MT=M ),那么它一定可以对角化,并且一定存在一组特征值( λ 1 , λ 2 \lambda_1, \lambda_2 λ1,λ2 ),那么就将矩阵对角化。这样自变量由三个变成了两个,我们就方便来区分三者。

从上图我们可以分析出来:

  • 平面: λ 1 , λ 2 \lambda_1,\lambda_2 λ1,λ2均小,也就说梯度不怎么变化
  • 边界: λ 1 ≫ λ 2 , λ 1 ≪ λ 2 \lambda_1 \gg \lambda_2,\lambda_1 \ll \lambda_2 λ1λ2λ1λ2,也就是说梯度只沿一个方向变化快,垂直方向变化慢。
  • 角点: λ 1 , λ 2 \lambda_1,\lambda_2 λ1,λ2 均大,也就是沿任意方向变化均快。

7、 角点响应值

上面我们只是分析了依靠 λ 1 , λ 2 \lambda_1,\lambda_2 λ1,λ2来区分三者,那么需要更加准确的表达式来进行判别。
R = d e t M − α ( t r a c e M ) 2 R=detM - \alpha(traceM)^2 R=detMα(traceM)2
其中 d e t M = λ 1 λ 2 : 行 列 式 的 值 t r a c e M = λ 1 + λ 2 : 迹 detM = \lambda_1\lambda_2:行列式的值 \quad traceM=\lambda_1+\lambda_2:迹 detM=λ1λ2:traceM=λ1+λ2

4、OpenCV相关函数

cv2.cornerHarris(img, blockSize, ksize, k)
  • img:输入图像。类型为float32
  • blockSize:角点检测中指定的区域大小
  • ksize:Soble求导中使用窗口的大小
  • k:取值为[0.04-0.06]

5、角点检测程序实现

程序实现:

def cv_show(src):
    cv2.imshow('',src) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows()

img_copy = img.copy()
img = cv2.imread('Pic/check.jpg')  # 棋盘图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图
dst = cv2.cornerHarris(gray, 2, 3, 0.04)  # 角点检测
img[dst>0.0005*dst.max()]=[0,0,255]  # 标记角点
res = np.hstack((img_copy, img))
cv_show(res)

结果如下:

结果

最后

更多精彩内容,大家可以转到我的主页:曲怪曲怪的主页

或者关注我的微信公众号:TeaUrn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值