角点检测
在进行图像匹配的时,通常需要对两幅图像中的特征点进行匹配。为了保证匹配的准确性,选择的特征点必须具有其独特性,而图像的角点则经常被看成是一种不错的选择。由观察可知,角点往往是两天边缘的交点,它是两条边缘方向变换的一种表示,因此,其两个方向的梯度变化通常都比较大并且容易检测。人们通过在一个小小的窗口区域内观察像素点的灰度值大小来识别角点,如果向任何方向移动窗口都会引起较大的灰度变化,则该位置往往就是我们要找的角点。
Harris算子
对于角点检测,有很多的算法,其中Harris 算法是最常用的角点检测算法之一,算法依据的正是上图的直观判断。
要衡量在某个方向上的梯度变化大小,可定义图像在某个方向上灰度的变化E(u,v)。
E(u,v)=\Sigma_x_y w(x,y)(I(x+u,y+v)-I(x,y))^{2}\Sigma_x_y w(x,y)(I(x+u,y+v)-I(x,y))^{2}
其中w(x,y)为窗口函数,它可以是如图所示的加权函数,也可以是高斯函数。
向量(u,v)表示某个方向,以及在该方向上的位移。I(x,y)表示像素灰度值强度,范围为0~255,I(x+u,y+v)表示位移强度。由上述公式可知,我们要研究在哪个方向上图像灰度值变化最大,只需令E(u,v)的值最大即可,因为E(u,v)表示的是某个方向上图像灰度的变化。而求解问题,则可通过泰勒展开式:
I(x+u,y+v)=I(x,y)+uIx+vIy+O(x,y)I(x+u,y+v)=I(x,y)+uIx+vIy+O(x,y)
得到:
(I(x+u,y+v)−I(x,y)2)≈(uIx+vIy)2≈([u,v][IxIy])([Ix,Iy][uv])≈[uv][IxIxIyIxIxIyIyIy][uv](I(x+u,y+v)−I(x,y)2)≈(uIx+vIy)2≈([u,v][IxIy])([Ix,Iy][uv])≈[uv][IxIxIxIyIyIxIyIy][uv]
记上式最后结果为ΔΔ,则得到:E(u,v)=\sum _x_yw(x,y)\cdot \Delta =[u,v]M\begin{bmatrix} u\\v \end{bmatrix}E(u,v)=\sum _x_yw(x,y)\cdot \Delta =[u,v]M\begin{bmatrix} u\\v \end{bmatrix}
其中M为2*2的Harris矩阵,Ix和IyIx和Iy分别是x方向和y方向的图像导数(灰度值强度),则可得:M=\sum _x_yw(x,y)\begin{bmatrix} I_x^{2} &I_xI_y \\ I_yI_x & I_y^{2} \end{bmatrix}M=\sum _x_yw(x,y)\begin{bmatrix} I_x^{2} &I_xI_y \\ I_yI_x & I_y^{2} \end{bmatrix}
根据Harris矩阵来计算矩阵特征值λ1λ1,λ2λ2,并通过一个评分函数R来判断一个窗口中是否含有角点:
R=det(M)−k(trace(M)2)R=det(M)−k(trace(M)2)
其中,det(M)=λ1,λ2,trace(M)=λ1+λ2det(M)=λ1,λ2,trace(M)=λ1+λ2。λ1,λ2λ1,λ2皆为M的特征值。上述公式即为:
R=λ1λ2−K(λ1+λ2)2R=λ1λ2−K(λ1+λ2)2.
这些特征值决定了一个区域是否为角点,边缘或平面。
①.当λ1和λ2都很小时,|R|的值也很小,则该区域为平坦区域。
②.当λ1>>λ2,或者λ1<<λ2,则该区域为边缘。
③.当λ都很大时,且λ1≈λ2时,也很大,则该区域为角点。
因此,Harris角点检测可以“R>阈值”作为条件判断一个图像区域是否为为角点。J·西(J·Shi)和C·托马西(C·Tomasi)于1994年在其论文“Good Features to Track”中提出了一种对Harris角点检测算子的改进算法,也就是Shi—Tomasi角点检测算子。我们也可以通过goodFeaturesToTrack算法进行角点检测,它同样定义了评分函数R,也是用R值的大小来判断区域是否为特征点:
R=min(λ1λ2)R=min(λ1λ2)
我们这里就直接使用OPenCV中的角点检测函数。
函数原型:
cv2.cornerHarris(src,blocksize,ksize,k[,dst[,borderTypr]])
参数说明:
(1).src:目标图像。
(2).blocksize:窗口大小。
(3).ksize:Sobel的孔径参数(Aperture Parameter),也就是Sobel核的半径,如1,3,5,7。
(4).k:R公式中的k,默认取0.04。
基于Harris角点检测的示例代码:
import numpy as np import cv2 #将图像导入将其转化为float类型,用于传递给Harris函数 filename='D:\Image\\four.jpg' img=cv2.imread(filename) gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) gray_img=np.float32(gray_img) #对图像进行角点检测 Harris_detector=cv2.cornerHarris(gray_img,2,3,0.04) #对图像进行膨胀处理,将灰度值增大(视觉上比较亮)的区域增强扩展,主要用来连通相似颜色或强度的区域 dst=cv2.dilate(Harris_detector,None) #设置阈值 thres=0.01*dst.max() #对角点进行红色标记 img[dst>thres]=[0,0,255] cv2.imshow('Harris角点检测',img) cv2.waitKey()
代码结果展示:
根据图像我们可以发现,角点的检测有些不太准确,只能检测较为明显的角点,并且存在很多的错误角点标记。于是,opencv便推出了更为精确的算法函数。
goodFeaturesToTrack算子
函数原型:
cv2.goodFeaturesToTack(image,maxCorners,qualityLevel,minDistance,[,corners[,mask[,blocksize[,useHarrisDetector[,k]]]])
参数说明如下:
(1).image:待检测目标图像
(2).maxCorners:最大数目的角点数
(3).qualityLevel:该参数指出最低可接受的角点质量,是一个百分数,实例中给0.01。
(4).minDistance:焦点之间最小的欧拉距离,避免得到相邻特征点。
(5).mask:可选参数,给出ROI。
利用goodFeaturesToTrack算法进行图像检测示例代码:
#goodFeaturesToTrack算法 import numpy as np import cv2 #读入图像 filename='D:\Image\\four.jpg' img=cv2.imread(filename) img2=img #将其转换为float型 img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) img_gray=np.float32(img_gray) #得到角点坐标向量 goodFeatures_corners=cv2.goodFeaturesToTrack(img_gray,25,0.01,10) goodFeatures_corners=np.int0(goodFeatures_corners) for i in goodFeatures_corners: x,y=i.flatten() #用绿点标记角点 cv2.circle(img2,(x,y),3,[0,255,],-1) cv2.imshow('goodFreaturesToTack角点检测',img2) cv2.waitKey()
其中绿点表示角点,从两个算法检测结果来看,对于图像角点的标记,goodFeaturesToTrack算法更为精确,准确性高,但是也有误差。