opencv对相机进行畸变矫正,及矫正前后的坐标对应

这篇具有很好参考价值的文章主要介绍了opencv对相机进行畸变矫正,及矫正前后的坐标对应。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.背景

目前有个项目,需要用到热成像相机。但是这个热成像相机它的畸变比较厉害,因此需要用标定板进行标定,从而消除镜头畸变。
同时需要实现用户用鼠标点击校正后的画面后,显示用户点击位置的像素所代表的温度。
另外热成像sdk中还有个功能:选定一个rect,可以返回这个rect中的最高最低温度以及其各自的位置。假如我们需要这个功能,那么又需要知道从src到dst的关系了。

2.需求分析

消除镜头畸变后,就不能直接使用热成像sdk提供的函数来查询像素对应的温度。
因为在查询函数中,有个像素坐标的形参,要求传入原来的热成像图像A的像素坐标,函数返回此像素位置的温度。
而我们经过畸变消除后,得到画面B。B上面的特定像素所处的坐标和原图不一定一样。
因此,假如用户想查询画面B上的某个像素点的有效温度,就必须要取得此像素点在原图A上的位置坐标。
而在知道原图的最高最低温度点的位置后,需要知道其在校正后的画面中的位置,才能准确绘制出来。
总结一下,需要实现以下功能:
a、镜头畸变校正
b、知道校正后的画面坐标(x,y),求其在原画面的坐标(x’,y’)
c、知道原画面坐标(x1,y1),求其在校正后的画面坐标(x2,y2)

3.解决方案

其实很简单,opencv本身就提供了。

3.1.镜头畸变校正

在经过 findChessboardCorners、calibrateCamera之后,我们就已经获得了相机矩阵cameraMatrix、畸变矩阵distCoeffs。
然后,我们利用getOptimalNewCameraMatrix,获得了一个相对容易控制画面取舍的新相机矩阵newCamMatrix。
接下来,就有两种方式对画面进行校正:
a、直接undistort。
b、先利用initUndistortRectifyMap得到map1、map2,然后再利用remap进行画面校正。
后面的代码把两种都演示了。

3.2.知道校正后的画面坐标(x, y),求其在原画面的坐标(x’, y’)

其实,我们真正需要的是第二种。
关键就在于map1、map2。
这两个矩阵是什么玩意呢?
其实你先看看他们的尺寸、通道数,再查阅一下资料就知道了:
map1、map2的尺寸与目标图像(校正后的图像)的尺寸一致,而通道数为1(这个其实不一定,与其他参数有关,暂时先这样认为)。我们假设,最终图像(x,y)处的像素来源于源图像(x’,y’)处,那么,map1中存储了坐标(x’,y’)中的x’,而map2中存储了y’。
虽然我描述得很混乱,但是你配合代码应该明白我在说什么。😁
所以,我们直接利用这个map1、map2就可以实现从消除畸变后的画面坐标转换到原画面的坐标了。

    initUndistortRectifyMap(cameraMatrix, distCoeffs, cv::Mat(), newCamMatrix, imageSize, CV_32FC1, map1, map2);
    
    ......
   
    Point dstPt(400, 109);
    double pt_x = map1.at<float>(dstPt);
    double pt_y = map2.at<float>(dstPt);

3.2.知道原画面坐标(x1, y1),求其在校正后的画面坐标(x2, y2)

这个可以利用opencv的undistortPoints函数进行求解。
假如你是单目相机标定,需要注意第三个参数使用相机矩阵、第五个参数使用空矩阵、第六个参数使用新相机矩阵。这些参数需要和initUndistortRectifyMap的相对应起来。

    vector<Point2f> srcPts;
    srcPts.push_back(Point2f(300, 145));
    vector<Point2f> dstPts;
    undistortPoints(srcPts, dstPts, cameraMatrix, distCoeffs, Mat(), newCamMatrix);

假如你用的是立体相机标定的话【opencv/samples/cpp/stereo_calib.cpp】,可以直接把得到的R、P填上去:

  stereoRectify(cameraMatrix[0], distCoeffs[0],
            cameraMatrix[1], distCoeffs[1],
            imageSize, R, T, R1, R2, P1, P2, Q,
            CALIB_ZERO_DISPARITY, 1, imageSize, &validRoi[0], &validRoi[1]);
......
  vector<Point2f> srcPts;
  srcPts.push_back(Point2f(110, 205));
  vector<Point2f> dstPts;
  undistortPoints(srcPts, dstPts, cameraMatrix[0], distCoeffs[0], R1, P1);

4.效果

由于一些原因,我不能直接展示我的效果图。这里用opencv自带的图像来演示吧。
opencv对相机进行畸变矫正,及矫正前后的坐标对应,opencv,opencv,数码相机,人工智能

5.代码

int cameraCalibration()
{
    Size boardSize = {9, 6};
    float squareSize = 0.05;
    bool displayCorners = false;

    vector<string> imageList;
    for(int i = 0; i < 9; i++)
    {
        QString leftImgFile = QString("../data/left%1.jpg").arg(i + 1, 2, 10, QLatin1Char('0'));
        imageList.push_back(leftImgFile.toStdString());
    }

    // 存放相机的图像的角点位置
    vector<vector<Point2f>> imagePoints;
    // 存放实际的物体坐标
    vector<vector<Point3f>> objectPoints;

    Size imageSize;

    int i, j, nimages = imageList.size();

    imagePoints.resize(nimages);

    // 存放能够顺利找到角点的图像的路径
    vector<string> goodImageList;

    for(i = 0, j = 0; i < nimages; i++ )
    {
        const string& filename = imageList[i];
        Mat img = imread(filename, IMREAD_GRAYSCALE);

        // 检查图像是否为空
        if(img.empty())
            continue;

        imageSize = img.size();

        // 找角点
        bool found = false;
        vector<Point2f>& corners = imagePoints[j];
        found = findChessboardCorners(img, boardSize, corners,
                                      CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
        if(found == false)
        {
            continue;
        }

        // 再进行一次亚像素查找
        cornerSubPix(img, corners, Size(11,11), Size(-1,-1),
                     TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,
                                  30, 0.01));


        // 显示查找的结果
        if(displayCorners)
        {
            cout << "found:" << filename.c_str() << endl;
            Mat cimg;
            cvtColor(img, cimg, COLOR_GRAY2BGR);
            drawChessboardCorners(cimg, boardSize, corners, found);
            imshow("corners", cimg);
            char c = (char)waitKey(100);
        }

        goodImageList.push_back(imageList[i]);
        j++;
    }

    nimages = j;
    if( nimages < 2 )
    {
        cout << "Error: too little data to run the calibration\n";
        return -1;
    }

    // 截取长度,保留有用的数据
    imagePoints.resize(nimages);

    // 填充3d数据
    objectPoints.resize(nimages);
    for(int i = 0; i < nimages; i++ )
    {
        for(int j = 0; j < boardSize.height; j++ )
            for(int k = 0; k < boardSize.width; k++ )
                objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));
    }

    cv::Mat cameraMatrix(3, 3, CV_32FC1, cv::Scalar::all(0));  //内参矩阵3*3
    cv::Mat distCoeffs(1, 5, CV_32FC1, cv::Scalar::all(0));    //畸变矩阵1*5
    vector<cv::Mat> rotationMat;                               //旋转矩阵
    vector<cv::Mat> translationMat;                            //平移矩阵

    //!标定
    /**
     * points3D_all_images: 真实三维坐标
     * points_all_images: 提取的角点
     * image_size: 图像尺寸
     * camera_K : 内参矩阵K
     * distCoeffs: 畸变参数
     * rotationMat: 每个图片的旋转向量
     * translationMat: 每个图片的平移向量
     * */
    calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rotationMat, translationMat, 0);


    Mat testImg = imread(imageList[0], IMREAD_COLOR);


    cv::Rect validROI;
    Mat newCamMatrix = getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1.0, imageSize, &validROI);

//    Mat undistortedImg;
//    undistort(testImg, undistortedImg, cameraMatrix, distCoeffs, newCamMatrix);

//    cv::rectangle(undistortedImg, validROI, Scalar(255, 0, 0));
//    imshow("undistorted image", undistortedImg);


    Mat undistortedImg2;
    Mat map1, map2;
    initUndistortRectifyMap(cameraMatrix, distCoeffs, cv::Mat(), newCamMatrix, imageSize, CV_32FC1, map1, map2);

    //    cout << "map1 size" << map1.size() << "," << map1.channels() << endl;
    //    cout << "map2 size" << map2.size() << "," << map2.channels() << endl;

    remap(testImg, undistortedImg2, map1, map2, INTER_LINEAR);
    cv::rectangle(undistortedImg2, validROI, Scalar(255, 0, 0));
    cout << "calibration completed\r\n";

    // map1 map2中存储的分别是最终图像对应像素的x,y坐标
    // 知道dst的坐标,求src的相应坐标
    Point dstPt(400, 109);
    double pt_x = map1.at<float>(dstPt);
    double pt_y = map2.at<float>(dstPt);
    cout << "dstPt:" << dstPt << "; " << "origin pt:" << pt_x << ", "<< pt_y << endl;
    cv::circle(testImg, Point(pt_x, pt_y), 5, Scalar(255, 0, 0), 2);
    cv::circle(undistortedImg2, dstPt, 5, Scalar(255,0, 0), 2);


    // 知道src的坐标,求dst的相应坐标
    vector<Point2f> srcPts;
    srcPts.push_back(Point2f(300, 145));
    vector<Point2f> dstPts;
    undistortPoints(srcPts, dstPts, cameraMatrix, distCoeffs, Mat(), newCamMatrix);
    cout << "the dst:" << dstPts << endl;
    circle(testImg, srcPts[0], 8, Scalar(0, 255, 0));
    circle(undistortedImg2, dstPts[0], 8, Scalar(0, 255, 0));
    imshow("src to dst: src", testImg);
    imshow("src to dst: dst", undistortedImg2);
}


参考:
【关于OpenCV中的去畸变】
【用OpenCV进行相机标定(张正友标定,有代码)】
【《opencv学习笔记》-- 重映射】文章来源地址https://www.toymoban.com/news/detail-613491.html

到了这里,关于opencv对相机进行畸变矫正,及矫正前后的坐标对应的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像

    OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/136616551 各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究 红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、

    2024年03月13日
    浏览(16)
  • 使用python-opencv对双目摄像头进行立体视觉图像矫正,去畸变

    使用python-opencv对双目摄像头进行立体视觉图像矫正,去畸变

            1、一张棋盘图         可以直接从opencv官方github下载,这是一个拥有10*7个格子的棋盘,共有 9*6个角点,每个格子24mm ,本文所使用的就是这一个棋盘。你需要将它打印在A4纸上用于后续使用。(也可以根据官方教程自行设置棋盘大小OpenCV: Create calibration pattern)

    2024年02月10日
    浏览(15)
  • 学习笔记:利用usb_cam进行单目标定与畸变矫正(笔记本摄像头 or usb相机)

    学习笔记:利用usb_cam进行单目标定与畸变矫正(笔记本摄像头 or usb相机)

    一个刚入门视觉的学习笔记,怕哪天系统崩了找不回笔记了,故上传到博客方便保留。 1、准备工作(安装usb_cam) 1)创建文件夹 2)下载编译安装usb_cam包(该包能将摄像头的图像通过sensor_msgs::Image消息发布)    2、可以通过ls/dev/video*来查看电脑的设备号来选择外接或笔记本

    2024年02月07日
    浏览(9)
  • 无人机红外相机的畸变矫正

    无人机红外相机的畸变矫正

    在项目开展过程中,发现大疆M30T的红外相机存在比较明显的畸变问题,因此需要对红外图像进行畸变矫正。在资料检索过程中,发现对红外无人机影像矫正的资料较少,对此,我从相机的成像原理角度出发,探索出一种效果尚可的解决思路,遂以本文记录如下。 目前采用的

    2024年02月04日
    浏览(9)
  • 相机的内外参数标定和畸变矫正原理和代码

    相机的内外参数标定和畸变矫正原理和代码

    相机的成像过程实质上是坐标系转换。首先空间中的点坐标由世界坐标系转换到相机坐标系,然后将其投影到成像平面(图像物理坐标系),最后再将成像平面上的数据转换到图像像素坐标系。但是由于透镜制造精度及组装工艺的差别会引入畸变,导致原始图像的失真。镜头

    2024年04月16日
    浏览(8)
  • opencv图像畸变矫正:源码学习

    opencv图像畸变矫正:源码学习

    参考资料:相机标定(4) 矫正畸变 undistort()和initUndistortRectifyMap() 背景: opencv提供了直接进行畸变矫正的代码,因在项目中需要使用畸变矫正,因此研究一下opencv中畸变矫正的相关接口与代码,便于学习提升与二次开发。 opencv在文档中对相机标定与畸变矫正的原理做了简单

    2024年02月10日
    浏览(17)
  • python opencv多路视频畸变矫正与显示

    python opencv多路视频畸变矫正与显示

    用于测试的计算机配置如下: 计算机为八核Intel(R) Xeon(R) CPU E3-1230 V2 @ 3.30GHz 注意:文中所说的cpu使用率是指该算法占用的cpu使用率 测试用的视频规格为1920*1080 做一路视频的去除畸变 cpu的使用率为126.9% 多路视频去除畸变显示 三路视频去除畸变显示代码如下: import cv2 import numpy

    2023年04月09日
    浏览(10)
  • python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)

    python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)

    今天的低价单孔摄像机(照相机)会给图像带来很多畸变。畸变主要有两 种:径向畸变和切想畸变。如下图所示,用红色直线将棋盘的两个边标注出来, 但是你会发现棋盘的边界并不和红线重合。所有我们认为应该是直线的也都凸 出来了。 在 3D 相关应用中,必须要先校正这些畸变

    2024年02月06日
    浏览(10)
  • OpenCvSharp (C# OpenCV) 二维码畸变矫正--基于透视变换(附源码)

        本文主要介绍如何使用OpenCvSharp中的透视变换来实现二维码的畸变矫正。     由于CSDN文章中贴二维码会导致显示失败,大家可以直接点下面链接查看图片:     C# OpenCV实现二维码畸变矫正--基于透视变换 (详细步骤 + 代码)      讲解实现步骤之前先看下效果(左边是原图

    2024年02月15日
    浏览(13)
  • 【相机标定】opencv python 标定相机内参时不计算 k3 畸变参数

    畸变参数 k3 通常用于描述径向畸变的更高阶效应,即在需要高精度的应用中可以用到,一般的应用中 k1, k2 足矣。 常见的应用中, orbslam3 中是否传入 k3 是可选的,而 kalibr 标定中则只需要传入 k1, k2 。但计算 k3 时的 k1, k2 不等于不计算 k3 时的 k1, k2 ,因此需要学会两种场景下

    2024年02月09日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包