• 代码
#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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐