本文介绍了特征点检测的一些算法,然后基于OpenCV的ORB,实现了不同尺度和旋转的图像特征点匹配。
本文用到的代码存储在这里。
当我们人在对比两张图片时(例如上面的妙蛙种子),我们可以轻而易举地找到两张图片的相似性,尽管我们很难去刻画这种相似性,但是这种观察力却是天生具备的。而对于计算机来说,必须要用它能够理解的方式才能区分图片。
考虑如下三种区域类型:
可以很明显地看到,角点是最具有“唯一性”的特征(另外两种通过平移方框可以找到很多一样的),而且这种唯一性可以让计算机很容易识别出来。所以我们常常把角点认为是图像中优质的特征点(或关键点,Key Point)。
不仅仅是角点,还有许多方式可以让计算机找到独一无二的特征点,寻找特征点的过程叫做特征点检测(Feature Detection)。有时候还需要在多张图当中寻找特征点的对应关系,因此光有特征点的位置信息还不够,还需要知道特征点描述(Feature Description),才能在多张图中找到同一个特征点。
本文介绍传统(相对于深度学习来说)的图像处理中的特征点检测以及匹配的算法,在我最近的项目中主要用于三维配准的工作。
主要思想是认为特征点具有较大的局部差异性,以某个像素点为中心,取一个窗口,如果这个点周围的梯度较大,那么认为它是一个特征点。用数学的形式描述如下:
对于图像 I I I (的某个像素点),其自相关函数定义为
E ( u , v ) = ∑ x , y w ( x , y ) [ I ( x + u , y + v ) − I ( x , y ) ] 2 , E(u,v)=\sum\limits_{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,
其中 ( u , v ) (u,v) (u,v) 表示某一个小位移, w ( x , y ) w(x,y) w(x,y)是一个窗口函数, I ( x , y ) I(x,y) I(x,y)表示窗口对应图像位置的像素。 E ( u , v ) E(u,v) E(u,v) 可以描述像素点位移 ( u , v ) (u,v) (u,v) 的变化幅度。
根据泰勒公式: I ( x + u , y + v ) ≈ I ( x , y ) + I x u + I y v I(x+u,y+v)\approx I(x,y)+I_xu+I_yv I(x+u,y+v)≈I(x,y)+Ixu+Iyv ,代入可得:
E ( u , v ) = ∑ x , y w ( x , y ) ( I x u + I y v ) 2 = ∑ x , y w ( x , y ) ( I x 2 u 2 + 2 I x I y u v + I y 2 v 2 ) = [ u v ] M [ u v ] \begin{align} E(u,v) = & \sum\limits_{x,y}{w(x,y)(I_xu+I_yv)^2} \\ = & \sum\limits_{x,y}w(x,y)(I_x^2u^2+2I_xI_yuv+I_y^2v^2) \\ = & \left[\begin{matrix}u&v\end{matrix}\right] M \left[\begin{matrix}u\\v\end{matrix}\right] \end{align} E(u,v)===x,y∑w(x,y)(Ixu+Iyv)2x,y∑w(x,y)(Ix2u2+2IxIyuv+Iy2v2)[uv]M[uv]
其中
M = ∑ x , y w ( x , y ) [ I x 2 I x I y I x I y I y 2 ] M=\sum\limits_{x,y}w(x,y) \left[\begin{matrix} I_x^2 & I_xI_y \\ I_xI_y & I_y^2 \end{matrix}\right] M=x,y∑w(x,y)[Ix2IxIyIxIyIy2]
从 E ( u , v ) E(u,v) E(u,v) 可以看出它是一个关于 ( u , v ) (u,v) (u,v) 的二次型,如果令 E ( u , v ) = 1 E(u,v)=1 E(u,v)=1,那么这就是一个椭圆方程(记为椭圆 E E E)
[ u v ] M [ u v ] = 1 , \left[\begin{matrix}u&v\end{matrix}\right] M \left[\begin{matrix}u\\v\end{matrix}\right] =1 , [uv]M[uv]=1,
关于椭圆方程和其二次型矩阵的关系有如下定理:
假设椭圆长短轴分别为 c 1 c_1 c1, c 2 c_2 c2,其对应二次型矩阵的特征值分别为 λ 1 \lambda_1 λ1, λ 2 \lambda_2 λ2,那么满足:
- c 1 = 1 λ 1 c_1=\frac{1}{\sqrt{\lambda_1}} c1=λ11 , c 2 = 1 λ 2 c_2=\frac{1}{\sqrt{\lambda_2}} c2=λ21
- 两个特征向量分别指向长短轴的方向
注意这个椭圆 E ( u , v ) = 1 E(u,v)=1 E(u,v)=1,我们考虑某个轴 c 1 c_1 c1,椭圆方程限定了变化幅度为定值1,所以如果 c 1 c_1 c1越大,就说明原图像在这个像素点沿着这个轴的变化幅度越小。也就是说, M M M的特征值越大,像素点在这个特征向量方向的变化幅度越大。
所以我们可以用特征值去刻画变化幅度,也就是可以用特征值去寻找角点:
用等价的表述方式,可以定义
R = d e t ( M ) − k ( t r a c e ( M ) ) = λ 1 λ 2 − k ( λ 1 + λ 2 ) , \begin{align} R &= det(M)-k(trace(M)) \\ &= \lambda_1\lambda_2-k(\lambda_1+\lambda_2) \end{align}, R=det(M)−k(trace(M))=λ1λ2−k(λ1+λ2),
此时的判别方式为:
实验效果:
Harris角点检测具有旋转不变性,但不具备尺度不变性。
大部分特征点检测的算法都不仅仅是计算出图像的特征点就结束了的,计算特征点可以看做是“寻找图像的标志”,而如果要对两张表示同一物体的图像进行匹配,还需要去描述特征点,使得能够在两组特征点中准确找到相匹配的特征点对。这种“描述特征点”的数据称为描述子(descriptor)。
ORB使用oriented FAST算法来检测特征点,rotated BRIEF算法来计算特征点的描述子。
FAST(Features from Accelerated Segment Test)是一种非常快速的特征点检测算法。计算方法也很简单:
对于图像中的某个像素,如果它和周围的大部分点都不一样,就认为它是一个特征点。具体描述为:
有时会增加非极大值抑制的算法,来避免特征点太过邻近。
单纯的FAST算法有两个问题:
对于第1个问题,oriented FAST用“灰度质心法”(没详细了解)来给每个特征点计算一个方向,这样我们在后面计算描述子时,就可以将特征旋转到同一个规定的方向,使得满足旋转不变性;
对于第2个问题,oriented FAST用图像金字塔(多层降采样)的方式来满足尺度不变性。
BRIEF(Binary Robust Independent Elementary Features)用于对特征点构造描述子,来形容特征点的某些性质。
具体做法是:
图像金字塔的方法已经解决了尺度不变性的问题,而BRIEF是不满足旋转不变性的。
rotated BRIEF注意到,上面提到的选取有序点对的“方法”,对于事实上同一个特征点来说,选取的“区域”和这个特征点的相对位置是固定的,因此我们根据这个相对位置建立坐标系(相当于坐标系随之旋转),就保证了旋转不变性。
用OpenCV的ORB模块得到的特征点如下:
ORB是2011年提出的,主要目的是满足实时性,即计算速度快的要求。更早的算法还有SIFT、SURF等。
没有详细学
在计算出特征点和描述子之后,就可以进行特征点匹配的工作了。对于两幅图像,我们分别计算了它们的特征点,“匹配”的意思就是将两者的特征点一一配对。这里描述子起到了关键的作用:两个描述子的“距离”越小,特征点相似度越高。
这里以ORB的描述子为例,ORB的描述子是一个bit向量,距离的度量方式是汉明距离:不同bit位的数目。
至于匹配的方法,最简单的肯定是暴力, O ( n 2 ) O(n^2) O(n2)就可以完成。其它的方法还有近似最近邻搜索等(例如flann库)。
下图是OpenCV中ORB+暴力匹配的实验结果:
可以看到左右两图的特征点识别有很多不同之处,匹配也有很多不正确的,因此实际我们只使用描述子距离最近的少部分匹配结果。例如如果选择“最好的”20个匹配,得到的结果:
上图这些匹配结果都非常准确。