opencv单相机的标定

相机的三维测量离不开相机的标定,本篇不对相机标定原理和相机模型进行介绍,本篇只记录opencv的相机标定代码

注:代码使用的是opencv4,原因是opencv4提供了更快更好的棋盘格角点识别函数

相机标定代码:

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

#include "./fileLoad/fileLoad.hpp"

using namespace std;
using namespace cv;

int main()
{
    const Size szCornerArry = Size(8, 6);       //此处定义角点阵列大小
    const Size szSquareRealSize = Size(35, 35); //此处定义棋盘格的每个方格的尺寸

    Size szImage;       //图片的尺寸
    Mat mChessBoard;    //棋盘格图片
    vector<string> vFiles;  //图片文件列表
    vector<Point2f> vCorner;    //单张图片的棋盘格的角点
    vector<vector<Point2f> > vCornersSeq;   //所有图片的棋盘格的角点

    getFilesFromFolder("../MI8Camera", vFiles); //图片文件名列表获取函数(我的其他博客有相关函数,不想使用的小伙伴们也可以各显神通)

        for (string file : vFiles) {
        mChessBoard = imread(file);
        cvtColor(mChessBoard, mChessBoard,COLOR_RGB2GRAY);  //此处转为灰度图片
        if (mChessBoard.empty()) { 
            cout << file << "is illegal" << endl;
            continue; 
        }
        szImage = mChessBoard.size();
        //if (!cv::findChessboardCorners(mChessBoard, szChessBoard, vCorner))   //此处为以前的角点识别函数(速度较慢,返回的也不是亚像素)
        if (!findChessboardCornersSB(mChessBoard,szCornerArry,vCorner))         //此处为opencv4的角点识别函数
        {
            cout << file << "cannot find right corners"<<endl;
            continue;
        }
        //虽然上面新的焦点识别函数给的是亚像素,但是再次使用亚像素好像得到的效果更好(我只测了一组图片)
        //cv::cornerSubPix(mChessBoard, vCorner, Size(10, 10), Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0.1));
        cvtColor(mChessBoard, mChessBoard, COLOR_GRAY2RGB);
        drawChessboardCorners(mChessBoard, szCornerArry, vCorner,true);
        resize(mChessBoard, mChessBoard, Size(960, 720));
        imshow("corners",mChessBoard);
        waitKey(30);
        vCornersSeq.push_back(vCorner);
        cout << file << "find corners finished" << endl;
    }
    //cv::find4QuadCornerSubpix();

    vector < vector<Point3f> > vWorldPointsSeq;             //幅图像识别到的角点对应的世界坐标点
    Mat mCameraMatrix = Mat(3,3,CV_32FC1,Scalar::all(0));   //相机内参矩阵
    Mat mDistcoeffs = Mat(8,1,CV_32FC1,Scalar::all(0));     //相机畸变系数

    for (int t = 0; t < vCornersSeq.size(); t++)
    {
        vector<Point3f> vWorldPoints;   //每一幅图片的所有角点对应的三维坐标点
        Point3f realPoint;  //三维点坐标
        for (int i = 0; i < szCornerArry.height; i++)
        {
            for (int j = 0; j < szCornerArry.width; j++)
            {
                realPoint.x = i * szSquareRealSize.width;
                realPoint.y = j * szSquareRealSize.height;
                realPoint.z = 0;
                vWorldPoints.push_back(realPoint);
            }
        }
        vWorldPointsSeq.push_back(vWorldPoints);
    }

    vector<Mat> tvecsMat;   //每一幅图像算得的旋转矩阵
    vector<Mat> rvecsMat;   //每一幅图像算得的平移矩阵
    cv::calibrateCamera(vWorldPointsSeq,vCornersSeq, szImage,mCameraMatrix,mDistcoeffs,rvecsMat,tvecsMat);
    cout << "标定完成!\n";
    cout<<"相机内参:"<<mCameraMatrix<<endl;
    cout<<"畸变系数:"<<mDistcoeffs<<endl;

    //对标定结果进行评价  
    cout << "开始评价标定结果………………\n";
    cout << "\t每幅图像的标定误差:\n";
    cout << "每幅图像的标定误差:\n";
    double dTotalErr = 0.0; //所有图片的总误差
    double dErr = 0.0;      //每幅图片的平均误差
    vector<Point2f> image_points2;
    for (int i = 0; i<vCornersSeq.size();i++)
        {
            vector<Point3f> tempPointSet = vWorldPointsSeq[i];
            projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i], mCameraMatrix, mDistcoeffs,image_points2);
            dErr = norm(Mat(vCornersSeq[i]), Mat(image_points2), NORM_L2);
            dTotalErr+= dErr/vWorldPointsSeq[i].size();
            std::cout << vFiles[i]<<"的平均像素误差:" << dTotalErr/vCornersSeq.size()<< std::endl;
        }
    std::cout << "总体平均误差:" << dTotalErr / vCornersSeq.size() << "像素" << std::endl;
    std::cout << "评价完成!" << endl;return 0;
}

 

根据标定结果进行图像的去畸变

 1 void GenerateUndistortImg(Mat img)
 2 {
 3     Mat mCameraMatrix;   //相机内参矩阵
 4     Mat mDistcoeffs;     //相机畸变系数
 5     mCameraMatrix = (Mat_<double>(3,3)<<1394.150188318831, 0, 643.4771005222109, 0, 1395.603286615578, 379.8384205833741, 0, 0, 1);
 6     mDistcoeffs = (Mat_<double>(1,5)<<-0.4556144160999324, 0.4050805253333984, 0.001029998925260306, 0.0007947011845121512, -0.2495583894250177);
 7     Mat mMap1,Map2;
 8     cvtColor(img, img,COLOR_RGB2GRAY);
 9     initUndistortRectifyMap(mCameraMatrix,mDistcoeffs,Mat(),
10                             getOptimalNewCameraMatrix(mCameraMatrix,mDistcoeffs,img.size(),1,img.size(),0),
11                             img.size(),CV_8UC1,mMap1,Map2);
12     imshow("source",img);
13     remap(img, img, mMap1, Map2, INTER_LINEAR);
14     imshow("dest",img);
15 }

原图像:

畸变校准后的图像:

posted @ 2020-06-11 09:35  永驻的青春  阅读(763)  评论(0)    收藏  举报