参考
KeyPoint
特征提取与匹配—SURF;SIFT;ORB;FAST;Harris角点
opencv中DMatch解释
这一部分opencv
都是有现成的,首先是初始化关键点和描述子变量。
vector<Keypoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
关键点为
class KeyPoint
{
Point2f pt;//在图像中的像素坐标,xy分别对应uv方向
float size;//点的邻域直径
float angle;//点的方向
float response;响应程度,代表该点的强壮程度,也就是该点角点程度,用于后期使用和排序
int octave;//特征点所在的图像金字塔的组
int class_id;//用于聚类的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);
同样直接调用指令,但在此之前需要确定一下特征匹配的算法,比如暴力匹配BFMatch
,Flann
最近邻匹配FlannBasedMatcher
等等。下面以暴力匹配为例。
BFMatcher bfMatcher(NORM_HAMMING);
vector<DMatch> matches;
bfMatcher.match(descriptors1, descriptors2, matches);
首先定义一个容器bfMatcher,然后定义一下保存匹配结果的容器matches,获得匹配结果的语句就一句话。下面说一下匹配结果保存的容器matches,它是
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; // query descriptor index
CV_PROP_RW int trainIdx; // train descriptor index
CV_PROP_RW int imgIdx; // train image index
CV_PROP_RW float distance;
// less is better
bool operator<( const DMatch &m ) const
{
return distance < m.distance;
}
};
简单解释一下,就是说,两幅图像的匹配结果matches中含有一对对的特征点信息,其中每个特征点信息都保存在
特征点一般就保存在Vector
类型里,但在求解基础矩阵(RANSAC
需要)或单应性矩阵的时候,需要转换为vector
,有时候甚至要转换为Mat
类型。前者还好说,一句指令就可以,后者就需要自己写代码一步步转换了,不过其实就是把点的坐标提取出来,也就还好。
刚才说的那句指令是
KeyPoint::convert(参数1,参数2);
可以实现
下面说一下vector
类型的数据,vector
内容很简单,n
行对应n
个特征点,每行2
个参数,就是特征点在图像中的x
、y
像素坐标,名字也是x
、y
。
Vector
转换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;
}
等等吧,懒得写。
参考findFundamentalMat和findHomography的比较
使用cv::findFundamentalMat要注意的几点
上面链接2说使用
cv::findFundamentalMat
的时候前两个参数不要用vector
,而是要自己事先转化为Mat
,且类型使用CV_32F
,参考3
中给出的程序。转换的时候注意匹配的索引和特征点对应。
其他参考opencv_C++ FlannBasedMatcher() FLANN特征匹配、OpenCV2:特征匹配及其优化。