(一)BRIEF描述子
0 ; A<=B
4)分别对已经选取的点对进行T操作,将得到的结果进行组合。如下所示:
那么,这个关键点最终的描述子为:1011
(二)理想特征点的描述子应该具备哪些属性呢?
当我们以理想的方式计算图像中关键点的描述子的时候,同样的特征点,在不同的图像中应该具有相同的结果。即描述子对于光照、旋转、尺度具有一定的鲁棒性。
上面我们用BRIEF算法得到的描述子并不具备以上这些性质。因此,我们得想办法改进我们的算法。ORB并没有解决尺度一致性的问题,OpenCv中实现的ORB算法采用图像金字塔来改善这方面的性能。ORB算法主要解决了BRIEF描述子不具有旋转不变性的问题。
回顾一下BRIEF描述子的计算过程:在当前关键点P的周围以一定方式选取N个点对,组合这N个点对的T操作的结果,这个组合结果就为这个关键点最终的描述子。当我们选取点对的时候,是以当前关键点为原点,以水平方向为X轴,以垂直方向为Y轴建立坐标系。当图片发生旋转时,坐标系不变,同样的取点模式,取出来的点却不一样,计算得到的描述子也不一样,这是不符合我们要求的。因此,我们需要重新建立坐标系,使新的坐标系可以随着图片的旋转而旋转。这样我们以相同的取点模式取出来的点就具有一致性。
打个比方,我们有一个印章,上面刻着一些直线。用这个印章在一张图片上盖一个章子,图片上的某个点被取出来。印章不变动的情况下,转动下图片,再盖一个章子,但是这次取出来的点对就和之前的不一样。为了使2次取出来的点一样,我们需要将章子也旋转同一个角度,再盖章。ORB在计算BRIEF描述子的时候,建立的坐标系是以关键点为圆心,以关键点和取点区域的形心的连线为X轴建立的2维坐标系 。在下图中,P为关键点。圆内为取点的区域,每个小格子代表一个像素。现在我们把这块圆心看做一块木板,木板上每个点的质量等于其对应的像素值。根据积分学的知识,我们可以求出这个密度不均匀木板的质心Q。计算公式如下所示,其中R为圆的半径。我们知道圆心是固定的,而且随着物体的旋转而旋转,当我们以PQ为坐标时,在不同的旋转角度下,我们以同一取点模式取出来的点是一致的,这就解决了旋转一致性的问题。
(三)特征点的匹配
(四)ORB在OpenCv中的示例程序
/********************************************************************************************************
文件说明:
ORB的特征检测与匹配
开发环境:
Win7 + OpenCv2.4.8 + VS2012
时间地点:
陕西师范大学 2017.3.17
作 者:
九 月
*********************************************************************************************************/
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
using namespace cv;
using namespace std;
/********************************************************************************************************
函数描述:
计算图像中的ORB特征及其特征点的匹配
*********************************************************************************************************/
bool cacORBFeatureAndCompare(cv::Mat srcImg_1,cv::Mat srcImg_2)
{
//【1】图像中ORB关键点的检测
std::vector<cv::KeyPoint> keyPoints_1;
std::vector<cv::KeyPoint> keyPoints_2;
cv::ORB orb;
orb.detect(srcImg_1,keyPoints_1); //【1】图像1中ORB关键点的检测
orb.detect(srcImg_2,keyPoints_2); //【2】图像2中ORB关键点的检测
//【2】计算特征向量(特征点的描述子)
cv::Mat descriptorMat_1; //【1】图像1的特征点描述子
cv::Mat descriptorMat_2; //【2】图像1的特征点描述子
orb.compute(srcImg_1,keyPoints_1,descriptorMat_1); //【1】计算图像1的特征向量
orb.compute(srcImg_2,keyPoints_2,descriptorMat_2); //【2】计算图像2的特征向量
//【3】特征点的匹配
cv::BFMatcher matcher(NORM_HAMMING);
std::vector<DMatch> matches;
matcher.match(descriptorMat_1,descriptorMat_2,matches);
//【4】绘制匹配点集
cv::Mat matchMat;
cv::drawMatches(srcImg_1,keyPoints_1,srcImg_2,keyPoints_2,matches,matchMat);
cv::imshow("matchMat",matchMat);
cv::waitKey(0);
return true;
}
int main(int argc, char** argv)
{
cv::Mat srcImg_1 = imread("temp.jpg");
if(srcImg_1.empty())
{
std::cout<<"【NOTICE】NO valid inout image_1 was given,please check the inoput image! "<<std::endl;
std::system("pause");
return -1;
}
cv::Mat srcImg_2 = imread("temp.jpg");
if(srcImg_1.empty())
{
std::cout<<"【NOTICE】NO valid inout image_2 was given,please check the inoput image! "<<std::endl;
std::system("pause");
return -1;
}
//ORB特征点的检测和匹配
cacORBFeatureAndCompare(srcImg_1,srcImg_2);
return 0;
}