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 }
原图像:

畸变校准后的图像:


浙公网安备 33010602011771号