本文结构

为了看懂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)

实际测试发现sigma2=(1/25)S2能有最高的识别率。

我还是不明白,空域中到底要怎么选点?

看了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,再乘以一个系数的矩阵。

当然,盒状滤波器在实现的过程中可以有更快的实现方式,即分别指定一维的行内滤波器和列内滤波器,每个滤波器都是计算整个行或列的元素和:先逐列扫描,每列计算元素和,并存储到临时数组中;再对临时数组使用行滤波器进行求和,这样就得到一个区域的盒状滤波结果了。

参考:

Opencv2.4.9源码分析——BRIEF

极限优化:Haar特征的另一种的快速计算方法—boxfilter

BRIEF算法的更多相关文章

  1. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  2. 分布式系列文章——Paxos算法原理与推导

    Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...

  3. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  4. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  5. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  6. 虚拟dom与diff算法 分析

    好文集合: 深入浅出React(四):虚拟DOM Diff算法解析 全面理解虚拟DOM,实现虚拟DOM

  7. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  8. 神经网络、logistic回归等分类算法简单实现

    最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...

  9. 46张PPT讲述JVM体系结构、GC算法和调优

    本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...

  10. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

随机推荐

  1. Mango Weekly Training Round #3 解题报告

    A. Codeforces 92A Chips 签到题.. #include <iostream> #include <cstdio> #include <cstring ...

  2. Android Studio系列教程四--Gradle基础

    Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...

  3. js原生捕鱼达人(二)

    昨天写到构造炮弹,有点小bug不知道大家发现没有,今天继续昨天的步骤 7>构造炮弹   思路和前面都是一样一样的   注意构造函数中需要考虑的属性  和  构造函数的原型上面的方法 <sc ...

  4. 33Mybatis------Mapper的编写

    Mapper编写的三种方法 传统的做法: 接口实现类继承SqlSessionDaoSupport 使用此种方法需要编写mapper接口,mapper接口实现类.mapper.xml文件 1.  在sq ...

  5. 【转】【C#】C# 不常用关键字

    1.__arglist 让我们先从__arglist开始. __arglist是用来给方法传送参数.通常我们是通过函数头部指定的参数列表给方法传递参数的.如果我们想要给方法传递一组新的参数,我们需要重 ...

  6. 【快报】基于K2 BPM的新一代协同办公门户实践交流会

    2014年2月28日,“基于BPM的新一代协同办公门户”用户实践交流活动在深圳金茂JW万豪酒店3楼Meet Room IV举办.本次会议由K2携手微软共同举办,邀请到的参会企业都是K2 的BPM老客户 ...

  7. mousewheel 模拟滚动

    div{ box-sizing:border-box; } .father{ width:500px; height:400px; margin:auto; margin-top: 50px; bor ...

  8. 如何在 kernel 和 hal 层读取同一个标志

    很多时候我们需要从 HAL 层(Hardware Abstract Layer)传一个标志给 kernel 层.一般这种传递是不能直接通过定义全局变量来实现的. 此时可以通过读写文件来实现该标志. 譬 ...

  9. Eclipse里面启用genymotion

    E:/Users/zhuxuekui/AppData/Local/Android/sdk as里面的SDK目录 1.打开eclipse并从云仓库里面下载genymotion插件 注意:这里面有一个坑, ...

  10. PHP基础16:多维数组

    <?php //1.PHP-两维数组 $cars=array ( array("Volvo",22,18), array("BMW",15,13), ar ...