zoukankan      html  css  js  c++  java
  • 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系数。因为。。。。。。。 下面是三系数的修正结果,惨不忍睹啊

  • 相关阅读:
    第十四周 Leetcode 315. Count of Smaller Numbers After Self(HARD) 主席树
    POJ1050 To the Max 最大子矩阵
    POJ1259 The Picnic 最大空凸包问题 DP
    POJ 3734 Blocks 矩阵递推
    POJ2686 Traveling by Stagecoach 状态压缩DP
    iOS上架ipa上传问题那些事
    深入浅出iOS事件机制
    iOS如何跳到系统设置里的各种设置界面
    坑爹的私有API
    业务层网络请求封装
  • 原文地址:https://www.cnblogs.com/flyinggod/p/8470407.html
Copyright © 2011-2022 走看看