FAST特征
FAST特征的提出主要是针对工程中对于特征点提取的高实时性的要求,提高特征点提取的速度。全称为:Features From Accelerated Segment Test。FAST角点的定义为:若某像素与其周围领域内足够多的像素点处于不同的区域,则该像素点可能是角点。例如,考虑灰度图像,若该点的灰度值比其周围领域内足够多的像素点的灰度值大或者小,则该点可能为角点。
- 图片中选择一个像素 p p p,将其亮度值设为 I p I_p Ip;
- 设定一个合适的阈值 T T T;
- 考虑以该像素点为中心的一个半径等于3个像素的离散化的圆,该圆形的边界上有16个像素;
- 如果在这个圆上有 n n n个连续的像素点,它们的像素值符合都比 I p + t I_p+t Ip+t大或者都比 I p − t I_p-t Ip−t小,那么它就是一个角点。 n n n的值可以设置为12或者9,实验证明9更好一点。
为了提高角点检测的速度,上述步骤中 n n n个连续像素点的判断优化为:判断16个像素点中第1,5,9,13个点的阈值特点,先看1,9是否同时大于或者小于阈值,然后再判断5或13;如果一个点是角点,则必须有至少3个都大于或者小于阈值。使用该方法对角点进行初步筛选(避免所有的点进行整圆检测,提高了效率),然后再进行整个圆上的检测。高效的同时,也存在缺点:
- n < 12 n<12 n<12时不能使用快速过滤非角点;
- 角点可能不是最优的,取决于问题的排序与角点的分布;
- 对于角点分析的结果被丢弃;
- 多个特征点挤在一起。
对于缺点1-3:使用决策树实现一个角点分类器——具体实现的时候是用的决策树么?
对于缺点4,相邻位置取得多个特征点,使用非极大值抑制解决:为每一个检测到的特征点计算它的响应大小
V
V
V,这里的
V
V
V定义为
p
p
p和周围16个像素的绝对偏差的和。比较相邻的特征点的
V
V
V值,并删除
V
V
V值小的特征点。
BRIEF特征描述符
该描述符提供一个计算二值串的捷径
- 平滑图像。
- 在特征点周围选择一个块,在块内选择 n d n_d nd个点对。
- 对于每一个点对
(
p
,
q
)
(p,q)
(p,q),比较两个点的亮度值,如果
I
(
p
)
>
I
(
q
)
I(p)>I(q)
I(p)>I(q),生成二值串中的1,若
I
(
p
)
<
I
(
q
)
I(p)<I(q)
I(p)<I(q),二值串对应为-1,否则就为0。比较完所有的
n
d
n_d
nd个点对后,就获得了一个长度为
n
d
n_d
nd的二值串。
BRIEF是一个高效的提取特征描述子的方法,具有较好地识别率。
Harris角点
在图片中各个方向上移动一个小窗口,若窗口内区域的灰度发生了较大的变化,那么就认为在窗口内遇到了角点。反之,窗口内就不存在角点。如果窗口在某一个方向上移动,灰度发生了较大的变化,而在另外一些方向上没有发生变化,那么,窗口内的图像可能是一条直线。
根据上述描述可知,Harris角点的可以根据窗口滑动后的区域与滑动前的区域的相似性进行判断,而自相似性可以由自相关函数量化,自相关函数越大,则自相似行越高,反之越低。
根据泰勒公式对平移后的窗口内图像进行一阶展开,得到:
则:
且:
因此,平移后的自相关函数可近似为:
其中,
根据
M
(
x
,
y
)
M(x,y)
M(x,y)计算一个角点的响应值
R
R
R来判断角点,且
R
=
d
e
t
(
M
)
−
α
(
t
r
a
c
e
(
M
)
)
R=det(M)-\alpha(trace(M))
R=det(M)−α(trace(M)),
d
e
t
(
M
)
=
λ
1
λ
2
=
A
C
−
B
2
det(M)=\lambda_1\lambda_2=AC-B^2
det(M)=λ1λ2=AC−B2是矩阵
M
M
M的行列式,
t
r
a
c
e
(
M
)
=
λ
1
+
λ
2
=
A
+
C
trace(M)=\lambda_1+\lambda_2=A+C
trace(M)=λ1+λ2=A+C是矩阵
M
M
M的直迹,
α
\alpha
α为常数,取值范围一般为0.04-0.06。
Harris角点实现:
- 计算不同方向下的梯度, I x , I y I_x,I_y Ix,Iy——梯度计算就直接使用卷积核进行差分计算,卷积核分别为 ( − 1 , 0 , 1 ) , ( − 1 , 0 , 1 ) T (-1,0,1),(-1,0,1)^T (−1,0,1),(−1,0,1)T;
- 计算两个方向梯度的乘积,得到 I x 2 = I x ∗ I x , I x y = I x ∗ I y , I y 2 = I y ∗ I y I_x^2=I_x*I_x,I_{xy}=I_x*I_y,I_y^2=I_y*I_y Ix2=Ix∗Ix,Ixy=Ix∗Iy,Iy2=Iy∗Iy;
- 使用高斯核函数对 I x 2 , I x y , I y 2 I_x^2,I_{xy},I_y^2 Ix2,Ixy,Iy2进行加权,得到矩阵 M M M的元素 A , B , C A,B,C A,B,C;
- 根据3中计算出来的 A , B , C A,B,C A,B,C,计算 R = d e t ( M ) − α ( t r a c e ( M ) ) R=det(M)-\alpha(trace(M)) R=det(M)−α(trace(M)),并保存在相应的矩阵中;
- 根据阈值保留相应像素作为角点候选值,阈值一般为计算出的 R R R的0.01倍;
- 使用非极大值抑制,筛选角点。
基于opencv实现的代码(参考了这个):
void detectHarris(const cv::Mat imgSrc, cv::Mat &imgDst, double alpha)
{
//Harris特征点检测
Mat gray;
if (imgSrc.channels() > 1)
{
cvtColor(imgSrc, gray, COLOR_BGR2GRAY);
}
else gray=imgSrc.clone();
gray.convertTo(gray, CV_64F);
Mat Ix, Iy,Ix2,Iy2,Ixy,A,B,C;
Mat kernelx= (Mat_<double>(1, 3) << -1, 0, 1);
Mat kernely = (Mat_<double>(3, 1) << -1, 0, 1);
Mat GaussianKernel = getGaussianKernel(7, 1);//kernel_size=7,sigma=1
filter2D(gray,Ix, CV_64F, kernelx);
filter2D(gray,Iy, CV_64F, kernely);//求梯度完成
Ix2 = Ix.mul(Ix);
Iy2 = Iy.mul(Iy);
Ixy = Ix.mul(Iy);//求梯度的乘积完成
filter2D(Ix2, A,CV_64F, GaussianKernel);
filter2D(Iy2, C, CV_64F, GaussianKernel);
filter2D(Ixy, B, CV_64F, GaussianKernel);//对梯度的乘积进行滤波
Mat Conner_Strength(gray.size(),gray.type());
for (int i = 0; i < gray.rows; i++)
{
for (int j = 0; j < gray.cols; j++)
{
double det_m = A.at<double>(i, j)*C.at<double>(i, j)
- B.at<double>(i, j)*B.at<double>(i, j);
double trace_m = A.at<double>(i, j) +C.at<double>(i, j);
Conner_Strength.at<double>(i, j) = det_m - alpha * trace_m*trace_m;
}
}///计算每一个Harris响应值,并保存到Conner_Strength矩阵里边
double maxStrength;
minMaxLoc(Conner_Strength, NULL, &maxStrength, NULL, NULL);//获得最大值maxStrength
Mat dilated, localMax;
dilate(Conner_Strength, dilated, Mat());
compare(Conner_Strength, dilated, localMax, CMP_EQ);
Mat cornerMap;
double qualityLevel = 0.01;
double thres = qualityLevel * maxStrength; //这是公式中的t
cornerMap = Conner_Strength > thres; //保留大于阈值的点作为备选角点
bitwise_and(cornerMap, localMax, cornerMap);//这里是非极大值抑制吧
imgDst = cornerMap.clone();
}
OpenCV实现图片卷积很方便,无论是高斯滤波还是横纵坐标的差分,只需要确定卷积核,调用相应的filter2D函数即可。
α
\alpha
α的取值增大,角点检测灵敏度降低,减少角点的数量,减小
α
\alpha
α会得到相反的效果。
==Harris对于亮度和对比度变化不敏感,具有旋转不变性,但是不具有尺寸不变性。==将Harris与高斯尺度空间结合,可以使Harris具有尺寸不变性。别人的代码,多尺度Harris的实现
ORB
ORB将FAST特征点检测方法结合BRIEF特征描述子,并在原来的基础上进行了优化:
- 首先,使用FAST特征点检测方法检测到特征点
- 然后利用Harris角点度量方法,从FAST特征点中挑选出Harris角点相应值最大的N个特征点。
旋转不变性
FAST没有尺度不变性,可以通过建立高斯金字塔,在每一层金字塔图像上检测角点,来实现尺度不变性。但是对于局部不变性,FAST特征点不具有方向,ORB提出利用灰度质心法来解决这个问题。灰度质心假设角点的灰度与质心之间存在一个偏移,这个偏移向量用于表示一个方向。对于任意一个特征点
p
p
p来说,定义
p
p
p的邻域像素的矩为:
m
p
q
=
∑
x
,
y
x
p
y
q
I
(
x
,
y
)
m_{pq}=\sum_{x,y}{x^py^qI(x,y)}
mpq=x,y∑xpyqI(x,y)
I
(
x
,
y
)
I(x,y)
I(x,y)为点
(
x
,
y
)
(x,y)
(x,y)处的灰度值,那么图像的质心为
C
=
(
m
10
m
00
,
m
01
m
00
)
C=(\frac{m_{10}}{m_{00}},\frac{m_{01}}{m_{00}})
C=(m00m10,m00m01),那么特征点与质心的夹角可以定义为FAST特征点的方向
θ
=
s
r
c
t
a
n
(
m
01
,
m
10
)
\theta=srctan(m_{01},m_{10})
θ=srctan(m01,m10),为了提高方法的旋转不变性,需要确保
x
,
y
x,y
x,y在邻域的圆形区域内,
x
,
y
∈
[
−
r
,
r
]
x,y\in[-r,r]
x,y∈[−r,r],
r
r
r等于邻域半径。
特征点的描述与旋转不变性
ORB选择BRIEF作为特征描述的方法,但是BRIEF没有旋转不变性,BRIEF是通过特征点邻域内的点对生成的二进制码流。因此ORB通过上述灰度质心法获得的角度
θ
\theta
θ对现有的特征点邻域内的点对进行旋转,旋转矩阵为
描述子的区分性
检测到特征点之后,需要对特征点进行描述,以便后续的特征点匹配。BRIEF特征描述符,具有良好的区分性,但是在上述为FAST特征点添加旋转不变的特性时,由于对点对进行了旋转,所以导致了BRIEF的区分性变弱,为了减少二进制码串之间的相关性,增大区分性,ORB使用一种学习的方法选择一个较小的点对集合。可以在这里看看解释。
我理解的点对的筛选学习:在一个比较大的特征点集中,对这些特征点我们都可以提取出一个二进制串,将这些二进制串以均值为标准进行排序,然后根据贪心策略,结合二进制串的相关性对这些点集进行筛选,筛选后的结果就是一组相关性比较小的点对集合。