本文结构
为了看懂ORB特征提取算法,来看了BRIEF算法的原文,并查看了OpenCV中BRIEF的相关实现,来验证论文的解读正确与否。
BRIEF论文解读
摘要
用二进制串描述局部特征,好处有二:一是很少的bit就能描述独特的性质;二是可以用汉明距离计算两个二进制串之间的特征,计算速度快。在实际应用中的好处是:算的准;算的快;省内存。
BRIEF特征的建立和用于匹配,都很快。性能测试表明,BRIEF比SURF和U-SURF快,准确度差不多。
Introduction
经验表明,用256甚至128个bit表示一个BRIEF特征就够用了。算的快,省内存,适合实时计算的应用,比如SLAM(省计算)或者三维重建(省存储)。
先前一些算法,先计算浮点型特征描述向量,再转化为二进制表示。这样的算法,匹配很快,但是前期还是慢。
BRIEF是在keypoint周边随机取点对进行灰度计算,直接得到二进制特征描述向量。
Method
图像patch先做平滑操作,再根据检验结果(response of test,比如t检验,即t-test)生成二进制描述符。
创建这样的特征向量,需要考虑的是高斯模糊的模糊核kernel(即\(\sigma\))值的选取,以及点对\((\vecx_1, \vecx_2)\)的选取,其中\(\vec x_1=(u,v)^T\)_
模糊的作用是消噪。
识别率的实验表明,sigma取2的效果最好,对应的高斯窗口为9x9规格。
论文提出了5种选择[x,y]的方式,并根据识别率进行实验,发现第二种性能最好:(X, Y) ∼ i.i.d. Gaussian(0, (1/25)S^2)
注意:这里的高斯分布容易引起混淆,详细讲是:每次t-检验中,要选取的两个点为(X,Y),其中X=(u1,v1)^T,Y=(u2,v2)^T,(X,Y)~N(0, (1/25)S^2)
实际测试发现sigma^2=(1/25)S^2能有最高的识别率。
我还是不明白,空域中到底要怎么选点?
看了OpenCV中的实现发现,所谓随机选点,只是最开始的一个patch是随机选点,并且这个选出来的点的顺序要记录下来给后面所有的patch使用。并且,这些选出的点并不是真正的、纯粹的随机,而是服从上述高斯分布的。
为什么patch在t-检验前要做平滑?
因为论文原文提出的t-检验,每次检查的是两个像素点。单个像素点是噪声敏感的。因此要做平滑操作。(而平滑操作比较耗时,这也为后来的优化做了伏笔。Calonder等人又于2011年提出采用盒状滤波器的处理方法来代替高斯平滑处理方法)
实验和结果
在6种图片上,分别使用SURF、U-SURF、BRIEF-16、BRIEF-32、BRIEF-64进行测试,发现BRIEF-32除了在涂鸦(Graffitti)上表现不如SURF和U-SURF好之外,其他图片序列上基本都是最好的。而且显然BRIEF-32也和BRIEF-64差不了太多,并且也基本胜过SURF和U-SURF。
上述比较过程中,keypoint是用的SURF的keypoint。实际上SURF的keypoint会吃掉BRIEF带来的速度提升,一般用其他更快的keypoint检测子,比如CenSurE(Center Surround Extremas Realtime Feature Detector and Matching这篇论文提出。也可以考虑FAST等算法,FAST:Rosten, E., Drummond, T.: Machine Learning for High-Speed Corner Detection. In: European Conference on Computer Vision)。但是,换用了更快的检测子,能保证识别率吗?
同样的测试图片,对比分别用SURF和CenSurE检测的keypoint然后接上BREIF描述符,测量匹配的准确度,CenSurE在大多数情况下比SURF准确率还高;个别情况稍低于SURF。
旋转角的讨论
BRIEF没有专门考虑旋转的问题。那么就从0°~360°进行旋转测试吧。
发现小范围(0-15°)内,BRIEF识别率最高,其次是U-SURF,然后是SURF和o-BRIEF;
角度再大一点(15°~30°),BRIEF和U-SURF准确率迅速下降到0,角度再大,则这两个算法的识别率保持为0.而SURF和o-BRIEF这两个考虑旋转方向的算法,始终能保持大于60%的准确率,而且在90°的倍数角度处,识别率有极大值。
这里的o-BRIEF是:用SURF算出旋转角度,然后用BRIEF按照这个角度旋转再进行描述的一个算法。
这里的BRIEF都是BRIEF-32。
o-BRIEF和SURF的识别率,在旋转角度从0到180度变化时,几乎是重合的。
实验中还测量了SURF和BRIEF在description和matching两个阶段的对比,发现特征描述的计算时间上相差35-40倍,精确邻近匹配的计算时间上相差3~10倍。
通常U-SURF比SURF快上3倍左右。
当前BRIEF的大多数时间消耗在高斯模糊操作上。基于积分图像的近似平滑操作,能加速。
结论
BRIEF算的快(二进制描述,汉明距离匹配),算的准(这很重要),省内存(远少于SIFT和SURF的描述符位数)。
下一步考虑方向和尺度。使用快速的方向估测子(fast orientation estimators),没理由不相信速度不快!
OpenCV中的实现
对一个keypoint(及其所在区域,称为patch),在生成其描述符之前,BRIEF要先对patch做高斯平滑,这会消耗时间。
OpenCV在具体的实现上,结合了平滑和积分图像的思想,将t-检验中原本的两个点p1、p2,替换成p1、p2各自一个模板区域内的像素之和,这个模板区域以p1或p2为左上角定点。也就是,从原来的单独两个点的像素值比较,换成了两个模板区域内的像素和的比较,参与比较的点多了,降低了噪声的影响。但是计算效率呢?没关系,因为使用了积分图像,因此计算时间是O(4)=O(1)的:
inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x)
{
static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2;
int img_y = (int)(pt.pt.y + 0.5) + y;
int img_x = (int)(pt.pt.x + 0.5) + x;
return sum.at<int>(img_y + HALF_KERNEL + 1, img_x + HALF_KERNEL + 1)
- sum.at<int>(img_y + HALF_KERNEL + 1, img_x - HALF_KERNEL)
- sum.at<int>(img_y - HALF_KERNEL, img_x + HALF_KERNEL + 1)
+ sum.at<int>(img_y - HALF_KERNEL, img_x - HALF_KERNEL);
}
这里的积分图像的使用,其实也就是盒状滤波器:指定区域内的像素和,或者像素和的归一化结果;也就是一个元素全为1,再乘以一个系数的矩阵。
当然,盒状滤波器在实现的过程中可以有更快的实现方式,即分别指定一维的行内滤波器和列内滤波器,每个滤波器都是计算整个行或列的元素和:先逐列扫描,每列计算元素和,并存储到临时数组中;再对临时数组使用行滤波器进行求和,这样就得到一个区域的盒状滤波结果了。