在图像处理与计算机视觉邻域,特征点(Feature points),也被称为关键点(Key points)、兴趣点(Interset points),是三大图像特征之一。在传统CV图像处理过程中,被大量用于物体识别、图像识别、视觉跟踪、三维重建等领域。利用提取的特征点不仅可以有效表现图像的属性和行为,而且减小了内存,提高了图像处理的效率。常用的特征点检测算子有Harris角点检测、SIFT特征点检测、SURF特征点检测等。其中Harris角点是最为基础的图像特征,本文通过python-opencv实现Harris角点检测来理解图像特征检测的相关知识。
图像三种特征类型:
概念:如果图像某一点在任意方向的一个微小变动都会引起灰度的较大变化,该店就被称为角点。
举个例子:
由此可知,从直观视角上,角点是图像的锐点,其邻域在图像上代表图像独一无二的一个特征或模式(Pattern);从客观视角上,角点又是图像代表像素点,其邻域像素值在图像上沿各个方向均有不同变化。
根据角点的定义,可对角点做出如下具体描述:
Chris_Harris 和 Mike_Stephens 在 1988 年的文章《A Combined Corner and Edge Detector》中就提出了Harris角点检测的方法。
假设中心位置为 ( x , y ) (x,y) (x,y)的滤波窗口为 w ( x , y ) w(x,y) w(x,y) ,让该窗口的中心对准灰度图像 ( x , y ) (x,y) (x,y)处,这个位置的像素灰度值为 I ( x , y ) I(x,y) I(x,y) ,如果这个窗口分别向 x x x 和 y y y 方向移动一个小的位移 u u u和 v v v,到一个新的位置 ( x + u , y + v ) (x+u,y+v) (x+u,y+v) ,新位置的像素灰度值就是 I ( x + u , y + v ) I(x+u,y+v) I(x+u,y+v) 。
则数学表达式为:
E ( u , v ) = ∑ x , y w ( x , y ) [ I ( x + u , y + v ) − I ( x , y ) ] 2 E(u,v)=\sum_{x,y}^{}w(x,y)[I(x+u,y+v)-I(x,y)]^{^{2}} E(u,v)=x,y∑w(x,y)[I(x+u,y+v)−I(x,y)]2
窗口函数可以是正常的矩形窗口,也可以是加权高斯窗口。
角点的检测中要使得 E ( u , v ) E(u,v) E(u,v)的值最大化,即使得 [ I ( x + u , y + v ) − I ( x , y ) ] 2 [I(x+u,y+v)-I(x,y)]^{^{2}} [I(x+u,y+v)−I(x,y)]2最大,对上式进行泰勒展开在换算(这里不做探讨只是了解)可得以下等式:
E ( u , v ) ≈ [ u v ] M [ u v ] E(u,v)\approx [u \ v]M \begin{bmatrix} u\\ v \end{bmatrix} E(u,v)≈[u v]M[uv]
其中,
M = ∑ w ( x , y ) [ I x I x I x I y I x I y I y I y ] M=\sum_{w(x,y)}^{}\begin{bmatrix} IxIx & IxIy\\ IxIy & IyIy \end{bmatrix} M=w(x,y)∑[IxIxIxIyIxIyIyIy]
这里 I x Ix Ix和 I y Iy Iy表示图像在 x x x, y y y方向的导数(可以通过函数cv.Soble()计算得到)。
为了找到那些窗口会引起灰度值的较大变换,我们需要对协方差矩阵M进行处理,这里通过引入角点响应函数R来判定像素点 ( x , y ) (x,y) (x,y)是否为角点,定义如下:
R = d e t ( M ) − k ( t r a c e ( M ) ) 2 R=det(M)-k(trace(M))^{^{2}} R=det(M)−k(trace(M))2
其中
通过以上特征可以判断一个区域是否为角点、边界还是平面。
如下图所示:
Harris 角点检测的结果是带有这些分数 R 的灰度图像,设定一个阈值,分数大于这个阈值的像素就对应角点。
python-OpenCV中的函数cv2.cornerHarris() 可以用来进行角点检测。参数如下:
• img:数据类型为 float32 的输入图像。
• blockSize:角点检测中要考虑的领域大小。
• ksize - Sobel:求导中使用的窗口大小
• k - Harris:角点检测方程中的自由参数,取值参数为 [0,04,0.06]
代码如下:
import cv2
import numpy as np
# 定义Harris检测参数
block_size = 3
sobel_size = 3
k=0.04 # 0.04-0.06
filename = r"C:\Users\CleMints\Desktop/lena.jpg"
img = cv2.imread(filename)
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray_img = np.float32(gray_img) # 输入图像必须是 float32 类型灰度图
# Harris角点检测
dst = cv2.cornerHarris(gray_img,block_size,sobel_size,k)
# 角点标记
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
dst = cv2.dilate(dst,kernel)
img[dst>0.05*dst.max()] = [255,0,0]
# for r in range(img.shape[0]):
# for c in range(img.shape[1]):
# pix = dst[r,c]
# if pix>0.05*dst.max():
# cv2.circle(img,(c,r),5,(0,0,255),0)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("HarrisCorner",img)
cv2.waitKey()
运行一张Lena图,灰度化后角点用红色像素点标记,运行结果为:
参考资料:
1、Harris角点算法
2、角点检测:Harris 与 Shi-Tomasi
3、Datawhale 计算机视觉基础-图像处理(下)- Task01 Harris特征点检测