参考 KeyPoint 特征提取与匹配—SURF;SIFT;ORB;FAST;Harris角点 opencv中DMatch解释
1. 特征提取及描述
这一部分opencv 都是有现成的,首先是初始化关键点和描述子变量。
vector<Keypoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
关键点为<Keypoint>元素组成的向量,其中<Keypoint>类内容如下:
class KeyPoint
{
Point2f pt;
float size;
float angle;
float response;
int octave;
int class_id;
}
描述子就是一个数字矩阵。
随后要设置特征点,比如SIFT ,ORB 。
Ptr<ORB> orb = ORB::create();
然后就是常规操作,特征提取描述,直接写就行。
orb->detect(img1, keypoints1);
orb->detect(img2, keypoints2);
orb->compute(img1, keypoints1, descriptors1);
orb->compute(img2, keypoints2, descriptors2);
2. 特征匹配
同样直接调用指令,但在此之前需要确定一下特征匹配的算法,比如暴力匹配BFMatch ,Flann 最近邻匹配FlannBasedMatcher 等等。下面以暴力匹配为例。
BFMatcher bfMatcher(NORM_HAMMING);
vector<DMatch> matches;
bfMatcher.match(descriptors1, descriptors2, matches);
首先定义一个容器bfMatcher,然后定义一下保存匹配结果的容器matches,获得匹配结果的语句就一句话。下面说一下匹配结果保存的容器matches,它是<DMatch>类型元素组成的向量,<DMatch>内容如下:
struct CV_EXPORTS_W_SIMPLE DMatch
{
CV_WRAP DMatch() : queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(FLT_MAX) {}
CV_WRAP DMatch( int _queryIdx, int _trainIdx, float _distance ) :
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {}
CV_WRAP DMatch( int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) :
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx), distance(_distance) {}
CV_PROP_RW int queryIdx;
CV_PROP_RW int trainIdx;
CV_PROP_RW int imgIdx;
CV_PROP_RW float distance;
bool operator<( const DMatch &m ) const
{
return distance < m.distance;
}
};
简单解释一下,就是说,两幅图像的匹配结果matches中含有一对对的特征点信息,其中每个特征点信息都保存在<DMatch>中;而每个<DMatch>类型数据共有n行,每一行保存一对匹配特征点相关信息;每一行数据含有4个参数,第一个参数是左图第i个特征点的索引(就是说在特征提取之后,会对每张图像中的特征点进行排序,序号就对应索引号),第二个参数是与左图第i个特征点相匹配的右图第j个特征点索引,第三个参数是图像索引,第四个参数是匹配的特征点之间的距离(不是整数)。
非常冗杂的解释,附一张大佬的图就好理解了。
3. 类型转换
特征点一般就保存在Vector<Keypoint> 类型里,但在求解基础矩阵(RANSAC 需要)或单应性矩阵的时候,需要转换为vector<Point2f> ,有时候甚至要转换为Mat 类型。前者还好说,一句指令就可以,后者就需要自己写代码一步步转换了,不过其实就是把点的坐标提取出来,也就还好。 刚才说的那句指令是
KeyPoint::convert(参数1,参数2);
可以实现<Point2f>和<Keypoint>之间的相互转换,将参数1转换为参数2格式。
下面说一下vector<Point2f> 类型的数据,vector<Point2f> 内容很简单,n 行对应n 个特征点,每行2 个参数,就是特征点在图像中的x 、y 像素坐标,名字也是x 、y 。
Vector<Keypoint> 转换Mat 类型,贴在下面。
Mat p1(keypoints1.size(),2,CV_32F);
Mat p2(keypoints1.size(),2,CV_32F);
vector<Point2f> ps1, ps2;
for(int i=0;i<keypoints1.size();i++)
{
ps1=keypoints1[matches[i].queryIdx].pt;
p1.at<float>(i,0)=ps1.x;
p1.at<float>(i,1)=ps1.y;
ps2=keypoints2[matches[i].trainIdx].pt;
p2.at<float>(i,0)=ps2.x;
p2.at<float>(i,1)=ps2.y;
}
4. 单应性矩阵求解
等等吧,懒得写。 参考findFundamentalMat和findHomography的比较
其他参考opencv_C++ FlannBasedMatcher() FLANN特征匹配、OpenCV2:特征匹配及其优化。
|