c++实现基于sift匹配后的控制点按照均匀分布、方向、尺度筛选
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
1、均匀性筛选
2、尺度和方向性筛选
前言
在基于大图片进行控制点提取时,我们经常会进行分块处理,既有效的提高处理效率,减少内存,也可以加速点的提取和匹配。切片时需要注意不同大小的图片对提点和匹配的影响,因为图片的旋转和偏移程度不同,如果我们切成1000*1000大小进行提点和匹配,在提点和点匹配会有几万,甚至几十万个点的输出和进一步转换处理,最后输出可能也有几千、几万个点,对后续校正或者别的使用可能不太友好,可以通过均匀性进行筛选保留一些点即可,实现方案如下面文章。
提示:以下是本篇文章正文内容,下面案例可供参考
一、均匀性筛选
这里涉及到按照待处理窗口大小进行筛选,例如:我们选择10001000的大小按照200200进行筛选,每个窗口内保留1个点,即筛选完一个1000*1000大小图片点数<=25个点;代码如下:
main里使用方式如下:
//点筛选
/*img1:图片1
RR_keypoint01:图片1上的控制点
img2:图片2
RR_keypoint02:图片2上的控制点
RRR_matches:图片1和2匹配上的控制点*/
vector<DMatch> RRR_matches;
RRR_matches = filterMatchesByGrid(RR_keypoint01, RR_keypoint02, RR_matches, 200);
cout << "控制点均匀性筛选后个数:" << RRR_matches.size() << endl;
// 绘制匹配结果
cv::Mat imgMatchesss;
cv::drawMatches(img1, RR_keypoint01, img2, RR_keypoint02, RRR_matches, imgMatchesss, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
string dstImg1ss = "E:\\BaiduNetdiskDownload\\out\\均匀性2.png";
// 显示图像
printf("保存结果为png\n");
cv::imwrite(dstImg1ss, imgMatchesss); //0000000000000000000
filterMatchesByGrid函数如下:
vector<DMatch> filterMatchesByGrid(vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2, vector<DMatch>& matches, int gridSize) {
// 假设keypoints1和keypoints2是匹配点对应的关键点,matches是它们之间的匹配
map<pair<int, int>, vector<DMatch>> grid; // 用来按网格存储匹配点
for (const DMatch& match : matches) {
// 获取匹配点在第一幅图像中的位置
Point2f pt = keypoints1[match.queryIdx].pt; //以待校正影像的行列号作为均匀性分布条件
// 计算网格索引
int gridX = pt.x / gridSize;
int gridY = pt.y / gridSize;
// 将匹配添加到对应的网格中
grid[make_pair(gridX, gridY)].push_back(match);
}
vector<DMatch> filteredMatches; // 用于存储筛选后的匹配
for (auto& entry : grid) {
// 这里简单地选择每个网格中的第一个匹配作为代表
filteredMatches.push_back(entry.second[0]);
}
// 现在filteredMatches包含了筛选后的匹配,可以进一步使用
return filteredMatches;
}
二、尺度和旋转一致性筛选
代码如下:
// 尺度和旋转一致性检查
const double scaleThreshold = 1.5; // 尺度比阈值 1.5
const double rotationThreshold = 10.0; // 旋转差异阈值(度) 10.0
std::vector<cv::DMatch> goodMatches;
for (size_t i = 0; i < RRR_matches.size(); i++) {
cv::DMatch& match = RRR_matches[i];
// 计算尺度比
double scaleRatio = RR_keypoint01[match.queryIdx].size / RR_keypoint02[match.trainIdx].size;
// 计算旋转差异
double rotationDiff = std::abs(RR_keypoint01[match.queryIdx].angle - RR_keypoint02[match.trainIdx].angle);
rotationDiff = rotationDiff > 180.0 ? 360.0 - rotationDiff : rotationDiff; // 调整旋转差异到[0, 180]
/*if (scaleRatio <= scaleThreshold && rotationDiff <= rotationThreshold) {
goodMatches.push_back(match);
}*/
if (rotationDiff <= rotationThreshold) {
goodMatches.push_back(match);
}
}
cout << "尺度转换一致性检查后控制点个数:" << goodMatches.size() << endl;
// 绘制匹配结果
cv::Mat imgMatches;
cv::drawMatches(img1, RR_keypoint01, img2, RR_keypoint02, goodMatches, imgMatches, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
string dstImg1 = "E:\\BaiduNetdiskDownload\\out\\1.png";
// 显示图像
printf("保存结果为png\n");
cv::imwrite(dstImg1, imgMatches); //0000000000000000000
总结
大家正确使用即可,效果还是很好的,这里就不给大家看结果了。