【opencv】教程代码 —features2D(6)透视矫正:读取两个棋盘格图片并进行图像对齐...

perspective_correction.cpp 透视校正

c0142c5f74bb5c10afcd4605746fea53.png

hconcat(img2, img1_warp, img_draw_warp);

51b7f1ab0528d54fb8e70eded1e47285.png

hconcat(img1, img2, img_draw_matches);

20469dffb54bcda2a5fbd5004e8a4712.png

#include <iostream> // 引入iostream库,用于进行标准输入和输出操作
#include <opencv2/core.hpp> // 引入opencv的core库,含有OpenCV的基础结构和操作
#include <opencv2/imgproc.hpp> // 引入opencv的imgproc库,包含了图像处理的各种操作
#include <opencv2/calib3d.hpp> // 引入opencv的calib3d库,包含3D校准相关的功能
#include <opencv2/highgui.hpp> // 引入opencv的highgui库,提供了显示和读写功能


using namespace std; // 使用std标准库的名字空间
using namespace cv; // 使用OpenCV库的名字空间


namespace // 创建匿名名字空间
{
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID }; // 定义Pattern枚举,包含三种模式:CHESSBOARD(棋盘格)、CIRCLES_GRID(圆形网格)、ASYMMETRIC_CIRCLES_GRID(不对称圆形网格)


Scalar randomColor( RNG& rng ) // 函数定义,生成随机颜色 
{
  int icolor = (unsigned int) rng; // 将RNG对象转为unsigned int类型的值
  return Scalar( icolor & 255, (icolor >> 8) & 255, (icolor >> 16) & 255 ); // 创建并返回一个颜色Scalar对象(B、G、R格式)
}


void perspectiveCorrection(const string &img1Path, const string &img2Path, const Size &patternSize, RNG &rng) // 定义透视修正函数,输入参数为两张图片路径、模式尺寸及RNG对象
{
    Mat img1 = imread( samples::findFile(img1Path) ); // 读取图像1
    Mat img2 = imread( samples::findFile(img2Path) ); // 读取图像2


    // 查找棋盘格角点
    vector<Point2f> corners1, corners2; // 创建两个浮点型点向量,存放两张图片的角点
    bool found1 = findChessboardCorners(img1, patternSize, corners1); // 在图像1中查找棋盘格的角点
    bool found2 = findChessboardCorners(img2, patternSize, corners2); // 在图像2中查找棋盘格的角点


    if (!found1 || !found2) // 如果在任何一张图片中都找不到角点
    {
        cout << "Error, cannot find the chessboard corners in both images." << endl; // 输出错误信息
        return; // 返回,结束程序
    }


    Mat H = findHomography(corners1, corners2); // 计算两组点之间的单应性矩阵H
    cout << "H:\n" << H << endl; // 打印出单应性矩阵H


    Mat img1_warp; // 创建一个新的Mat对象,用于存放透视变换后的图像
    warpPerspective(img1, img1_warp, H, img1.size()); // 对图像1进行透视变换


    // 拼接原图和变换后的图像
    Mat img_draw_warp; 
    hconcat(img2, img1_warp, img_draw_warp);
    imshow("Desired chessboard view / Warped source chessboard view", img_draw_warp); // 显示拼接后的图像


    // 绘制匹配的角点之间的线
    Mat img_draw_matches;
    hconcat(img1, img2, img_draw_matches); // 拼接两张原始图像
    for (size_t i = 0; i < corners1.size(); i++) // 遍历角点向量
    {
        Mat pt1 = (Mat_<double>(3,1) << corners1[i].x, corners1[i].y, 1); // 创建一个3x1的双精度浮点类型的矩阵,表示齐次坐标下的点
        Mat pt2 = H * pt1; // 使用单应性矩阵H对点进行转换
        pt2 /= pt2.at<double>(2); // 将转换后的点的坐标进行归一化
         // 计算映射后点的坐标位置
        Point end( (int) (img1.cols + pt2.at<double>(0)), (int) pt2.at<double>(1) );
        // 在图像上绘制代表匹配关系的线
        line(img_draw_matches, corners1[i], end, randomColor(rng), 2); 
    }


    imshow("Draw matches", img_draw_matches); // 显示匹配关系
    waitKey(); // 暂停程序,等待用户按键
}


const char* params
    = "{ help h         |       | print usage }"
      "{ image1         | left02.jpg | path to the source chessboard image }"
      "{ image2         | left01.jpg | path to the desired chessboard image }"
      "{ width bw       | 9     | chessboard width }"
      "{ height bh      | 6     | chessboard height }"; // 定义参数列表,包括帮助、图像路径、棋盘宽度和高度


int main(int argc, char *argv[]) // 主函数
{
    cv::RNG rng( 0xFFFFFFFF ); // 创建RNG对象
    CommandLineParser parser(argc, argv, params); // 创建命令行解析器


    if (parser.has("help")) // 如果用户输入了帮助参数
    {
        parser.about("Code for homography tutorial.\n"
            "Example 2: perspective correction.\n"); // 打印帮助信息
        parser.printMessage(); // 打印所有参数的信息
        return 0; // 程序正常结束
    }


    Size patternSize(parser.get<int>("width"), parser.get<int>("height")); // 从解析器获取棋盘格的宽度和高度,并构造Size对象
    perspectiveCorrection(parser.get<String>("image1"),
                          parser.get<String>("image2"),
                          patternSize, rng); // 执行透视校正操作


    return 0; // 程序正常结束
}

该段代码实现了对基于棋盘格模板的图片进行透视校正的功能。在实际操作中,先分别读取两幅图片,并在图片中找到棋盘角点,然后计算两组点对应的单应性矩阵(Homography),通过该矩阵实现透视变换,使其中一副图片的棋盘格对齐到另一幅图片中对应的位置,最后将变换效果进行显示。其中,代码中将原图与透视校正后的图像进行拼接显示,并绘制了角点匹配的连线,可以辅助观察效果。该代码通常应用于相机标定等领域。

H:
[0.3290339333220099, -1.244138808862929, 536.4769088231476;
 0.6969763913334047, -0.0893590907257152, -80.3406850408241;
 0.0004051172959296097, -0.001079740100565012, 1]

randomColor

783016cd91088d0bc09e66d9f70835fc.png

02a54095557e7ef8de6a477c73f11082.png

Mat H = findHomography(corners1, corners2);

831764504565f95ed04ad1892d644d42.png

Mat pt1 = (Mat_<double>(3,1) << corners1[i].x, corners1[i].y, 1);

11f6111e67375008be4ec94f9e44ece6.png

line(img_draw_matches, corners1[i], end, randomColor(rng), 2);

3787f9b43f93564c72cd63f3f561d184.png

48645d6675ed84201e760530d14f09c8.png

最近更新

  1. leetcode705-Design HashSet

    2024-04-02 18:26:02       8 阅读
  2. Unity发布webgl之后打开streamingAssets中的html文件

    2024-04-02 18:26:02       8 阅读
  3. vue3、vue2中nextTick源码解析

    2024-04-02 18:26:02       8 阅读
  4. 高级IO——React服务器简单实现

    2024-04-02 18:26:02       8 阅读
  5. 将图片数据转换为张量(Go并发处理)

    2024-04-02 18:26:02       7 阅读
  6. go第三方库go.uber.org介绍

    2024-04-02 18:26:02       8 阅读
  7. 前后端AES对称加密 前端TS 后端Go

    2024-04-02 18:26:02       9 阅读

热门阅读

  1. set的一些用法和问题

    2024-04-02 18:26:02       4 阅读
  2. 【Tomcat】Apache Tomcat 8.5正式结束官方支持

    2024-04-02 18:26:02       4 阅读
  3. macad.interaction解析liveactions、panels

    2024-04-02 18:26:02       3 阅读
  4. 从唯一序列码、单例模式到集群的思考

    2024-04-02 18:26:02       4 阅读
  5. promise.race方式使用

    2024-04-02 18:26:02       3 阅读
  6. abc-347

    2024-04-02 18:26:02       4 阅读
  7. Ubuntu 大压缩文件解压工具

    2024-04-02 18:26:02       4 阅读
  8. 生信小白菜之关于mutate函数的一切

    2024-04-02 18:26:02       2 阅读
  9. 什么是App分发?那些分发平台可以选择?

    2024-04-02 18:26:02       2 阅读
  10. Vue tableList:<any>[]介绍

    2024-04-02 18:26:02       2 阅读
  11. python中的浅拷贝和深拷贝

    2024-04-02 18:26:02       5 阅读