透视变换 c++实现

一. 场景说明

已知某个物体的四个角点(比如:车牌、表格等)坐标和对应的图片,如何通过透视变换获得矫正的图片。
原理解析:

  1. 对四个点进行排序(四个点可能是乱序的);
  2. 获得透视变换矩阵;
  3. 获得矫正的图片;

二. 代码实现

#include <iostream>
#include <string>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

int sort_points(cv::Point2f points[])
{
    cv::Point2f tempPoint;
    // 按照x轴坐标从小到大排序
    for(int i=0; i<3; i++)
    {
        for(int j=i+1; j<4; j++)
        {
            if(points[i].x > points[j].x)
            {
                tempPoint = points[i];
                points[i] = points[j];
                points[j] = tempPoint;
            }
        }
    }

    // 按照纵坐标排序,坐标顺序为:0左下角 1左上角 2右上角 3右下角
    if(points[0].y < points[1].y)
    {
        tempPoint = points[0];
        points[0] = points[1];
        points[1] = tempPoint;
    }
    if(points[2].y > points[3].y)
    {
        tempPoint = points[2];
        points[2] = points[3];
        points[3] = tempPoint;
    }
    return 0;
}

cv::Mat warp_img(cv::Point2f points[], const cv::Mat image)
{
    cv::Point2f pts_src[4] = {points[0], points[1], points[2], points[3]};
    int img_crop_height = int(sqrt(pow(pts_src[0].x - pts_src[1].x, 2) +
                                   pow(pts_src[0].y - pts_src[1].y, 2)));
    int img_crop_width = int(sqrt(pow(pts_src[1].x - pts_src[2].x, 2) +
                                  pow(pts_src[1].y - pts_src[2].y, 2)));
    cv::Point2f pts_dst[4];
    pts_dst[0] = cv::Point2f(0, img_crop_height - 1);
    pts_dst[1] = cv::Point2f(0, 0);
    pts_dst[2] = cv::Point2f(img_crop_width - 1, 0);
    pts_dst[3] = cv::Point2f(img_crop_width - 1, img_crop_height - 1);
    cv::Mat M = cv::getPerspectiveTransform(pts_src, pts_dst);
    cv::Mat crop_image;
    cv::warpPerspective(image, crop_image, M,
                        cv::Size(img_crop_width, img_crop_height),
                        cv::BORDER_REPLICATE);
    return crop_image;
}

int main()
{
    std::string img_path = "../test.jpg";
    cv::Mat image = cv::imread(img_path);
    cv::Mat image2 = image.clone();

    cv::Point2f points[4];
    points[0] = cv::Point2f(464, 2862);
    points[1] = cv::Point2f(2697, 2925);
    points[2] = cv::Point2f(2706, 3566);
    points[3] = cv::Point2f(431, 3487);
    sort_points(points);

    for(int i=0; i<4; i++)
    {
        cv::circle(image, points[i], 20, cv::Scalar(0,0,255), cv::FILLED, 0);
        std::cout << "points:" << points[i] << std::endl;
    }
    cv::imwrite("../result.jpg", image);

    cv::Mat crop_img = warp_img(points, image2);
    cv::imwrite("../crop_img.jpg", crop_img);
    return 0;
}

三. 效果展示

原图:
在这里插入图片描述
坐标显示:
在这里插入图片描述
透视变换后的图:
在这里插入图片描述

欢迎技术交流:
在这里插入图片描述

### C++实现SIFT算法与透视变换的结合 在C++环境中,利用OpenCV库可以高效地实现SIFT算法以及透视变换的操作。以下是具体的实现方式: #### 1. 使用OpenCV加载图像并检测SIFT特征点 通过调用`cv::xfeatures2d::SIFT`类来完成SIFT特征点的提取和描述符生成。需要注意的是,由于SIFT专利保护的原因,在某些版本的OpenCV中可能需要手动启用非自由模块。 ```cpp #include <opencv2/core.hpp> #include <opencv2/features2d.hpp> #include <opencv2/highgui.hpp> #include <opencv2/xfeatures2d.hpp> // 需要安装 opencv_contrib 模块 using namespace cv; using namespace cv::xfeatures2d; int main() { Mat img = imread("image.jpg", IMREAD_GRAYSCALE); if (img.empty()) { cout << "Could not read the image." << endl; return -1; } Ptr<SIFT> sift = SIFT::create(); vector<KeyPoint> keypoints; Mat descriptors; sift->detectAndCompute(img, noArray(), keypoints, descriptors); Mat outputImg; drawKeypoints(img, keypoints, outputImg, Scalar::all(-1), DrawMatchesFlags::DEFAULT); imshow("SIFT Keypoints", outputImg); waitKey(0); } ``` 上述代码实现了从输入灰度图中提取SIFT特征点及其对应的描述符[^1]。 --- #### 2. 特征点匹配 为了将两幅图像中的特征点进行匹配,通常会使用暴力匹配器(Brute Force Matcher)或者FLANN匹配器。以下是一个简单的特征点匹配示例: ```cpp Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE_L2); vector<DMatch> matches; matcher->match(descriptors1, descriptors2, matches); // 假设已有两个描述符矩阵 // 绘制前10个最佳匹配 Mat img_matches; drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); imshow("Best Matches", img_matches); waitKey(0); ``` 此部分完成了两张图片之间的特征点匹配过程[^2]。 --- #### 3. 计算单应性矩阵并执行透视变换 一旦获得了足够的匹配对,就可以通过RANSAC算法估计出单应性矩阵(Homography Matrix),从而实现透视变换。 ```cpp std::vector<Point2f> srcPoints(matches.size()), dstPoints(matches.size()); for(int i = 0; i < matches.size(); ++i){ srcPoints[i] = keypoints1[matches[i].queryIdx].pt; dstPoints[i] = keypoints2[matches[i].trainIdx].pt; } Mat H = findHomography(srcPoints, dstPoints, RANSAC, 3.0); if(!H.empty()){ Mat result; warpPerspective(img1, result, H, Size(img2.cols + img1.cols, max(img1.rows, img2.rows))); rectangle(result, Point_<>(img1.cols, 0), Point_<>(result.cols, result.rows), Scalar(0, 0, 255)); imshow("Warped Image", result); } else{ cerr << "Error calculating homography matrix!" << endl; } ``` 以上代码片段展示了如何基于匹配好的特征点计算单应性矩阵,并应用到原始图像上以生成最终的全景拼接效果[^3]。 --- #### 性能评估 可以通过记录程序运行时间的方式衡量整个流程效率: ```cpp time_t begin_time = clock(); // ... 执行主要逻辑 ... time_t end_time = clock(); cout << "Runtime: " << static_cast<double>(end_time - begin_time) / CLOCKS_PER_SEC << " seconds" << endl; ``` 性能测试有助于优化实际应用场景下的处理速度[^4]。 --- ### 注意事项 - **依赖项**:确保已正确配置 `opencv-contrib-python` 或者对应平台上的贡献模块。 - **版权问题**:考虑到SIFT可能存在知识产权争议,请谨慎用于商业项目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值