opencv——SURF特征点检测并使用Flann算法匹配
程序员文章站
2022-06-11 12:11:23
...
记录一下学习过程,话不多说贴代码:
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/flann/flann.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
int main() {
cv::Mat srcImage1 = cv::imread("img1.png", 1);
cv::Mat srcImage2 = cv::imread("img2.png", 1);
if (!srcImage1.data || !srcImage2.data) {
std::cout << "No images" << std::endl;
}
int minHessian = 400;
cv::Ptr<cv::xfeatures2d::SurfFeatureDetector> detector = cv::xfeatures2d::SurfFeatureDetector::create(minHessian);
//keypoint存储着特征点像素的坐标
std::vector<cv::KeyPoint> keypoint1, keypoint2;
cv::Mat dstImage1, dstImage2;
//特征点检测,并计算特征点的特征向量
detector->detect(srcImage1, keypoint1);
detector->detect(srcImage2, keypoint2);
detector->compute(srcImage1, keypoint1, dstImage1);
detector->compute(srcImage2, keypoint2, dstImage2);
//dstImage里面存储的是SURF特征,64*X,每个SURF特征是一个64维的向量
std::cout << dstImage1.size() << std::endl;
//keypImage是标注了特征点的原图像
cv::Mat keypImage1, keypImage2;
cv::drawKeypoints(srcImage1, keypoint1, keypImage1);
cv::drawKeypoints(srcImage2, keypoint2, keypImage2);
//cv::imshow("keypoint1", keypImage1);
//cv::imshow("keypoint2", keypImage2);
//特征点匹配
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("FlannBased");
std::vector<cv::DMatch> match;
matcher->match(dstImage1, dstImage2, match);
//根据粗匹配的结果筛选(通过比较匹配间的距离)优匹配的特征点
double mindist = 100;
double maxdist = 0;
for (int i = 0; i < dstImage1.rows; i++) {
double dist = match[i].distance;
if (dist < mindist) mindist = dist;
if (dist > maxdist) maxdist = dist;
}
std::cout << mindist << std::endl;
std::cout << maxdist << std::endl;
std::vector<cv::DMatch> goodmatch;
for (int i = 0; i < dstImage1.rows; i++) {
//距离满足的具体条件视情况而定
if (match[i].distance == mindist) {
goodmatch.push_back(match[i]);
std::cout << match[i].queryIdx << "-------" << match[i].trainIdx << std::endl;
}
}
cv::Mat matchImage;
cv::drawMatches(srcImage1, keypoint1, srcImage2, keypoint2, goodmatch, matchImage);
std::cout << goodmatch.size() << std::endl;
cv::imshow("goodmatch", matchImage);
cv::waitKey(0);
return 0;
}
实际运行的效果:
代码中需要了解一下opencv里Dmatch数据结构和detector的数据类型:
//////////////////////////////// DMatch /////////////////////////////////
/** @brief Class for matching keypoint descriptors
query descriptor index, train descriptor index, train image index, and distance between
descriptors.
*/
class CV_EXPORTS_W_SIMPLE DMatch
{
public:
CV_WRAP DMatch();
CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance);
CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _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;
};
template<> class DataType<DMatch>
{
public:
typedef DMatch value_type;
typedef int work_type;
typedef int channel_type;
enum { generic_type = 0,
depth = DataType<channel_type>::depth,
channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 4
fmt = DataType<channel_type>::fmt + ((channels - 1) << 8),
type = CV_MAKETYPE(depth, channels)
};
typedef Vec<channel_type, channels> vec_type;
};
在opencv3.3里,Dmatch定义成了一个类,前三个是构造函数,然后又queryIdx/trainIdx/imgIdx/distance四个值,分别表示查询图像的特征描述子索引/模板图像的特征描述子索引/有多张模板图像时的模板图像索引/匹配对间的距离。