两个图片匹配:OpenCV, C++
两个图片匹配:OpenCV, C++
·
- 代码
#include <opencv2/opencv.hpp>
#include <opencv2/features2d.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
static void printH(Mat& H)
{
cout << "Homography Matrix:\n" << H << endl;
float scale = sqrt(H.at<double>(0, 0)*H.at<double>(0, 0)
+H.at<double>(1, 0)*H.at<double>(1, 0));
float rotation_rad = atan2(H.at<double>(1, 0), H.at<double>(0, 0));
float rotation_deg = (rotation_rad*180/3.1415926);
float x_offset = H.at<double>(0, 2);
float y_offset = H.at<double>(1, 2);
printf("transform: scale=%.2f, rotation_rad=%.2f, rotation_deg=%.2f, x_offset=%.2f, y_offset=%.2f\n", scale, rotation_rad, rotation_deg, x_offset, y_offset);
}
int main() {
// 1. 读取图像
Mat img1 = imread("../images/map-00.jpg");
Mat img2 = imread("../images/map-03.jpg");
if (img1.empty() || img2.empty()) {
cout << "Could not open or find the images!" << endl;
return -1;
}
// 2. 初始化ORB检测器
Ptr<ORB> orb = ORB::create(
#if 1
1000
#else
1000, // 最大特征点数量
1.2f, // 金字塔层级缩放因子
8, // 金字塔层数
31, // 边缘阈值
0, // 第一层金字塔尺度
2, // WTA_K
ORB::HARRIS_SCORE, // 评分类型
31, // 补丁大小
20 // 快速阈值
#endif
);
// 3. 检测关键点和计算描述符
vector<KeyPoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
Mat gray1;
cvtColor(img1, gray1, COLOR_BGR2GRAY);
orb->detectAndCompute(gray1, noArray(), keypoints1, descriptors1);
Mat gray2;
cvtColor(img2, gray2, COLOR_BGR2GRAY);
orb->detectAndCompute(gray2, noArray(), keypoints2, descriptors2);
cout << "Keypoints in image1: " << keypoints1.size() << endl;
cout << "Keypoints in image2: " << keypoints2.size() << endl;
// 4. 使用BFMatcher进行特征匹配
BFMatcher matcher(NORM_HAMMING, true); // crossCheck=true 双向检查
vector<DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
cout << "Raw matches: " << matches.size() << endl;
// 5. 筛选匹配点(根据距离筛选)
double min_dist = 100, max_dist = 0;
// 找到最小和最大距离
for (int i = 0; i < matches.size(); i++) {
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
cout << "Min distance: " << min_dist << endl;
cout << "Max distance: " << max_dist << endl;
// 筛选:距离小于最小距离的2倍,但至少为30
vector<DMatch> good_matches;
for (int i = 0; i < matches.size(); i++) {
if (matches[i].distance <= max(2 * min_dist, 30.0)) {
good_matches.push_back(matches[i]);
}
}
good_matches = matches;
cout << "Good matches: " << good_matches.size() << endl;
// 6. 准备findHomography的输入数据
vector<Point2f> points1, points2;
for (size_t i = 0; i < good_matches.size(); i++) {
// queryIdx -> 第一张图,trainIdx -> 第二张图
points1.push_back(keypoints1[good_matches[i].queryIdx].pt);
points2.push_back(keypoints2[good_matches[i].trainIdx].pt);
}
printf("%ld ? %ld\n", points1.size(), points2.size());
// 7. 计算单应性矩阵
// 至少需要4个点
if (points1.size() < 4) {
printf("points too few! \n");
return 0;
}
// 计算内点(inliers)
/*
内点:符合估计模型的数据点(在误差阈值内)
外点(Outliers):不符合模型的数据点
例如:直线拟合中,靠近直线的点是内点,远离的是外点
*/
vector<char> inliers_mask;
Mat H = findHomography(points1, points2, RANSAC, 3.0, inliers_mask);
//# 如果无法计算,使用恒等变换
if (H.empty()) {
double data[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
H = Mat(3, 3, CV_32FC1, data);
}
printH(H);
int inliers_count = 0;
for (size_t i = 0; i < inliers_mask.size(); i++) {
if (inliers_mask[i]) inliers_count++;
}
cout << "Inliers: " << inliers_count << "/" << points1.size() << endl;
// 筛选出内点对应的匹配
vector<DMatch> inlier_matches;
for (size_t i = 0; i < good_matches.size(); i++) {
if (inliers_mask[i]) {
inlier_matches.push_back(good_matches[i]);
}
}
good_matches = inlier_matches; // 用内点匹配替换
// 8. 可视化结果
Mat img_matches;
drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches,
Scalar::all(-1), Scalar::all(-1), vector<char>(),
DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
// 9. 绘制匹配线并显示单应性矩阵
// 绘制图像1的边界框到图像2
vector<Point2f> obj_corners(4);
obj_corners[0] = Point2f(0, 0);
obj_corners[1] = Point2f(img1.cols, 0);
obj_corners[2] = Point2f(img1.cols, img1.rows);
obj_corners[3] = Point2f(0, img1.rows);
vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);
// 在匹配图像上绘制边界框(偏移到第二张图位置)
for (int i = 0; i < 4; i++) {
scene_corners[i].x += img1.cols;
}
line(img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[1], scene_corners[2], Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[2], scene_corners[3], Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[3], scene_corners[0], Scalar(0, 255, 0), 4);
// 在图像上显示单应性矩阵信息
string text = "Homography OK - Inliers: " + to_string(good_matches.size());
putText(img_matches, text, Point(10, 30), FONT_HERSHEY_SIMPLEX,
0.7, Scalar(0, 0, 255), 2);
// 调整显示大小
resize(img_matches, img_matches, Size(), 0.5, 0.5);
imshow("ORB Feature Matching with Homography", img_matches);
waitKey(0);
return 0;
}
- 输出
Keypoints in image1: 1000
Keypoints in image2: 1000
Raw matches: 395
Min distance: 4
Max distance: 78
Good matches: 395
395 ? 395
Homography Matrix:
[-0.001391554065311245, -1.378545795047761, 1019.57072265872;
1.382060224050579, 0.002564058962468651, -258.1363688421563;
1.332517474036688e-06, 1.855481209039565e-06, 0.9999999999999999]
transform: scale=1.38, rotation_rad=1.57, rotation_deg=90.06, x_offset=1019.57, y_offset=-258.14
Inliers: 215/395
更多推荐
所有评论(0)