• Matlab 摄像机标定+畸变校正


    博客转载自:http://blog.csdn.net/Loser__Wang/article/details/51811347

    本文目的在于记录如何使用MATLAB做摄像机标定,并通过opencv进行校正后的显示。

    首先关于校正的基本知识通过OpenCV官网的介绍即可简单了解:

    http://docs.opencv.org/2.4/doc/tutorials/calib3d/camera_calibration/camera_calibration.html

    对于摄像机我们所关心的主要参数为摄像机内参,以及几个畸变系数。上面的连接中后半部分也给了如何标定,然而OpenCV自带的标定程序稍显繁琐。因而在本文中我主推使用MATLAB的工具箱。下面让我们开始标定过程。

    标定板

    标定的最开始阶段最需要的肯定是标定板。两种方法,直接从opencv官网上能下载到: 
    http://docs.opencv.org/2.4/_downloads/pattern.png

    方法二:逼格满满(MATLAB)

    J = (checkerboard(300,4,5)>0.5);
    figure, imshow(J);

    采集数据

    那么有了棋盘格之后自然是需要进行照片了。不多说,直接上程序。按q键即可保存图像,尽量把镜头的各个角度都覆盖好。

    #include "opencv2/opencv.hpp"
    #include <string>
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
        VideoCapture inputVideo(0);
        //inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 320);
        //inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
        if (!inputVideo.isOpened())
        {
            cout << "Could not open the input video " << endl;
            return -1;
        }
        Mat frame;
        string imgname;
        int f = 1;
        while (1) //Show the image captured in the window and repeat
        {
            inputVideo >> frame;              // read
            if (frame.empty()) break;         // check if at end
            imshow("Camera", frame);
            char key = waitKey(1);
            if (key == 27)break;
            if (key == 'q' || key == 'Q')
            {
                imgname = to_string(f++) + ".jpg";
                imwrite(imgname, frame);
            }
        }
        cout << "Finished writing" << endl;
        return 0;
    }

    保存大约15到20张即可。大家可以看到我的方法,直接对着实验室的屏幕拍摄的。这个阶段有个注意事项就是测量好屏幕上每个方格的大小,这个标定的时候会用到。

    进行标定

    直接而在MATLAB的Command Window里面输入cameraCalibrator即可调用标定应用。 

    首先先把之前照好的图像添加进去,这是出现: 

    这就是之前让你记录的标定板中每个方格的大小。 输入无误后就涉及到最关键的一步了(MATLAB的这个实在太方便了,都是傻瓜式操作),选择参数。

    为什么说他关键呢,因为如果你仔细阅读了OpenCV的说明之后你会大概明白畸变参数,总共有五个,径向畸变3个(k1,k2,k3)和切向畸变2个(p1,p2)。 
    径向畸变

    切向畸变

    以及在OpenCV中的畸变系数的排列(这点一定要注意k1,k2,p1,p2,k3),千万不要以为k是连着的。

    并且通过实验表明,三个参数的时候由于k3所对应的非线性较为剧烈。估计的不好,容易产生极大的扭曲,所以我们在MATLAB中选择使用两参数,并且选择错切和桶形畸变。 

    点击开始后等待一段时间即可完成标定。并且MATLAB给出的可视化还是很不错的,可以对比校正前后的样子

    点击show Undistorted即可看到无畸变的图像

    到这为止,你已经完成了标定过程。选择导出参数,即可把参数进行保存。

    保存后可以退出标定应用,在MATLAB主界面中将保存的Mat文件打开

    第二行就是参数 

    里面的RadialDistortion对应k1,k2,k3设置为0了。 
    TangentialDistortion对应p1,p2。 
    IntrinsicMatrix对应内参,注意这个和OpenCV中是转置的关系,注意不要搞错。 

    对应 

    OpenCV中查看标定的结果

    #include "opencv2/opencv.hpp"
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
        VideoCapture inputVideo(0);
        if (!inputVideo.isOpened())
        {
            cout << "Could not open the input video: " << endl;
            return -1;
        }
        Mat frame;
        Mat frameCalibration;
    
        inputVideo >> frame;
        Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
        cameraMatrix.at<double>(0, 0) = 4.450537506243416e+02;
        cameraMatrix.at<double>(0, 1) = 0.192095145445498;
        cameraMatrix.at<double>(0, 2) = 3.271489590204837e+02;
        cameraMatrix.at<double>(1, 1) = 4.473690628394497e+02;
        cameraMatrix.at<double>(1, 2) = 2.442734958206504e+02;
    
        Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
        distCoeffs.at<double>(0, 0) = -0.320311439187776;
        distCoeffs.at<double>(1, 0) = 0.117708464407889;
        distCoeffs.at<double>(2, 0) = -0.00548954846049678;
        distCoeffs.at<double>(3, 0) = 0.00141925006352090;
        distCoeffs.at<double>(4, 0) = 0;
    
        Mat view, rview, map1, map2;
        Size imageSize;
        imageSize = frame.size();
        initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
            getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
            imageSize, CV_16SC2, map1, map2);
    
    
        while (1) //Show the image captured in the window and repeat
        {
            inputVideo >> frame;              // read
            if (frame.empty()) break;         // check if at end
            remap(frame, frameCalibration, map1, map2, INTER_LINEAR);
            imshow("Origianl", frame);
            imshow("Calibration", frameCalibration);
            char key = waitKey(1);
            if (key == 27 || key == 'q' || key == 'Q')break;
        }
        return 0;
    }

    修复之前和之后的结果对比

    还有就是之前讨论的为什么选2系数而不是3系数。因为。。。。。。。 下面是三系数的修正结果,惨不忍睹啊

  • 相关阅读:
    SpringBoot使用Swagger2实现Restful API
    SpringBoot返回json和xml
    SpringBoot定时任务
    SpringBoot+Jpa+MySql学习
    SpringBoot+Mybatis+MySql学习
    linux安装jdk
    linux下安装mysql
    利用nginx,腾讯云免费证书制作https
    SpringBoot使用数据库
    SpringBoot的国际化使用
  • 原文地址:https://www.cnblogs.com/flyinggod/p/8470407.html
Copyright © 2020-2023  润新知