单目+双目标定(模拟单目+投影仪)+基于PNP+RANSAC+BA的双目相对位姿求解

数以及相关文件:

链接: https://pan.baidu.com/s/1BPdMGlLzLJl5HuVpci840w 提取码: p2cc

 Note:这里标定“单目+投影仪”的算法并非调用 stereoCalibration,除非二者焦距、成像分辨率一致。

mian.cpp

  1 #include"MonoCamCalibration.h"
  2 
  3 
  4 // 构建PNP world -> right camera -> left camera -> left image plane
  5 int computeRT( const vector<vector<Point3f> >& objectPoints,
  6     const vector<vector<Point2f> >& imagePoints,
  7     const vector<Mat>& rvecsR,
  8     const vector<Mat>& tvecsR,
  9     const Mat& cameraMatrixL,
 10     const Mat& distCoeffsL)
 11 {
 12    /* if ( !(objectPoints.size() == imagePoints.size() == rvecsR.size() == tvecsR.size()) ||
 13          objectPoints.empty()  ||
 14          cameraMatrixL.empty() ||
 15          distCoeffsL.empty())
 16     {
 17         return -1;
 18     }*/
 19 
 20     vector<Point3f> objectPointsCam;
 21     vector<Point2f> imagePoints_;
 22 
 23     objectPointsCam.reserve(objectPoints.size() * objectPoints[0].size()); // resize is more efficient
 24     imagePoints_.reserve(imagePoints.size() * imagePoints[0].size());
 25 
 26     for (size_t i = 0; i < objectPoints.size(); i++)
 27     {
 28         Mat R;
 29         Rodrigues(rvecsR[i], R);
 30         Mat t = tvecsR[i];
 31 
 32         // T = (R|t) 这里只能用Affine3d 、 double, float会导致点溢出,可能是Mat 仅支持 double 的原因
 33         cv::Affine3d T(cv::Affine3d::Mat3(R),
 34             cv::Affine3d::Vec3(t.at<double>(0, 0), t.at<double>(1, 0), t.at<double>(2, 0)));
 35 
 36         for (size_t j = 0; j < objectPoints[0].size(); j++)
 37         {
 38             objectPointsCam.push_back(T * objectPoints[i][j]); // world ->  camera
 39             imagePoints_.push_back(imagePoints[i][j]);
 40         }
 41     }
 42 
 43     // optimize the R|t
 44     Mat rvec1, t1, inliers;
 45     float errThreshold = 0.f; // for getting the outliers and inliers
 46     float inliersRatio = 0.f; // num of points in line /num of all the points 
 47     for (; inliersRatio < 0.5f; errThreshold += 0.02f)
 48     {
 49         solvePnPRansac(objectPointsCam, imagePoints_, cameraMatrixL, distCoeffsL, rvec1, t1, false, 1000, errThreshold, 0.99, inliers);
 50         inliersRatio = (float)inliers.rows / (int)imagePoints_.size();
 51     }
 52     cout << "inliersRatio = " << inliersRatio << ";  num of samples = " << inliers.rows << endl;
 53 
 54     // copy the inliers 
 55     vector<Point3f> objectPointsCamInliers;
 56     vector<Point2f> imagePointsInliers;
 57     objectPointsCamInliers.resize((size_t)inliers.rows);
 58     imagePointsInliers.resize((size_t)inliers.rows);
 59 
 60     for (int i = 0; i < inliers.rows; i++)
 61     {
 62         size_t idx = (size_t)inliers.at<__int32>(i, 0);
 63 
 64         objectPointsCamInliers[i] = objectPointsCam[idx];
 65         imagePointsInliers[i]     = imagePoints_[idx];
 66     }
 67 
 68     solvePnPRefineLM(objectPointsCamInliers, imagePointsInliers, cameraMatrixL, distCoeffsL, rvec1, t1, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 1000, FLT_EPSILON));
 69     
 70     Mat R1;
 71     Rodrigues(rvec1, R1);
 72 
 73     vector<Point2f> imagePoints_RePro;
 74     double errs = 0.;
 75     projectPoints(objectPointsCamInliers, rvec1, t1, cameraMatrixL, distCoeffsL, imagePoints_RePro);
 76     for (size_t i = 0; i < imagePointsInliers.size(); i++)
 77     {
 78         errs += norm(Mat(imagePointsInliers[i]), Mat(imagePoints_RePro[i]), NORM_L2);
 79     }
 80     
 81     cout << "the err of PNP:" << errs / (int)imagePointsInliers.size() << " ";
 82 
 83     return 0;
 84 }
 85 
 86 void test1()
 87 {
 88     // 1、棋盘
 89     Size boardSize(9, 6);                                   //角点size(w, h)
 90     Pattern pattern = CHESSBOARD;                         // 默认棋盘
 91     int nframes = 14;                                       // num of images
 92     float squareSize = 0.02f;                            // 格子实际宽度(m)
 93 
 94     // Left
 95     string outputFilenameL = "parameters_imgs1_chessboard_left.yml";  // xml of parameters
 96     string inputFilenameL = "imgs1_chessboard_left.xml";              // 图片集路径
 97     MonoCamCalibration monoCaliChessBoardL(boardSize, pattern, nframes, squareSize, outputFilenameL, inputFilenameL);
 98     if (monoCaliChessBoardL.compute() == 0)
 99     {
100         cout << " Left successfully!" << endl;
101     }
102 
103     Mat cameraMatrixL = monoCaliChessBoardL.getCameraMatrix();
104     Mat distCoeffsL = monoCaliChessBoardL.getDistCoeffs();
105     vector<vector<Point2f> > imagePointsL = monoCaliChessBoardL.getImagePoints();
106     vector<vector<Point3f> > objectPoints = monoCaliChessBoardL.getObjectPoints();
107     vector<Mat> rvecsL = monoCaliChessBoardL.getVecs();
108     vector<Mat> tvecsL = monoCaliChessBoardL.getTvecs();
109 
110     // Right
111     string outputFilenameR = "parameters_imgs1_chessboard_right.yml";  // xml of parameters
112     string inputFilenameR = "imgs1_chessboard_right.xml";              // 图片集路径
113     MonoCamCalibration monoCaliChessBoardR(boardSize, pattern, nframes, squareSize, outputFilenameR, inputFilenameR);
114     if (monoCaliChessBoardR.compute() == 0)
115     {
116         cout << "Right successfully!" << endl;
117     }
118 
119     Mat cameraMatrixR = monoCaliChessBoardR.getCameraMatrix();
120     Mat distCoeffsR = monoCaliChessBoardR.getDistCoeffs();
121     vector<vector<Point2f> > imagePointsR = monoCaliChessBoardR.getImagePoints();
122     /*vector<vector<Point3f> > objectPoints = monoCaliChessBoardR.getObjectPoints();*/
123     vector<Mat> rvecsR = monoCaliChessBoardR.getVecs();
124     vector<Mat> tvecsR = monoCaliChessBoardR.getTvecs();
125 
126     // 构建PNP world -> right camera -> left camera -> left image plane
127    /* if (computeRT(objectPoints, imagePointsL, rvecsR, tvecsR, cameraMatrixL, distCoeffsL) == 0)
128     {
129 
130     }*/
131 
132     if (computeRT(objectPoints, imagePointsR, rvecsL, tvecsL, cameraMatrixR, distCoeffsR) == 0)
133     {
134 
135     }
136     cv::Mat M1 = cv::Mat::eye(3, 3, CV_64F);
137     cv::Mat M2 = cv::Mat::eye(3, 3, CV_64F);
138     cv::Mat D1, D2, R, T, E, F;
139     cout << "\nRunning stereo calibration ...\n";
140     cout << cv::stereoCalibrate(
141         objectPoints, imagePointsL, imagePointsR, cameraMatrixL, distCoeffsL, cameraMatrixR, distCoeffsR, Size(640, 480), R, T, E, F,
142         cv::CALIB_FIX_ASPECT_RATIO,
143         cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 1000,
144             1e-5)) << endl;
145 }
146 
147 void test2()
148 {
149     // 2、圆(左)
150     Size boardSize(7, 7);                                   //角点size(w, h)
151     Pattern pattern = CIRCLES_GRID;                         //
152     int nframes = 15;                                       // num of images
153     float squareSize = 0.00375f;                            // 格子实际宽度(m)
154 
155     string outputFilenameL = "parameters_imgs2_circle_left.yml";  // xml of parameters
156     string inputFilenameL = "imgs2_circle_left.xml";              // 图片集路径
157     MonoCamCalibration monoCaliCircleL(boardSize, pattern, nframes, squareSize, outputFilenameL, inputFilenameL);
158     if (monoCaliCircleL.compute() == 0)
159     {
160         cout << "successfully!" << endl;
161     }
162     
163     Mat cameraMatrixL = monoCaliCircleL.getCameraMatrix();
164     Mat distCoeffsL = monoCaliCircleL.getDistCoeffs();
165     vector<vector<Point2f> > imagePointsL = monoCaliCircleL.getImagePoints();
166     vector<vector<Point3f> > objectPoints = monoCaliCircleL.getObjectPoints();
167     vector<Mat> rvecsL = monoCaliCircleL.getVecs();
168     vector<Mat> tvecsL = monoCaliCircleL.getTvecs();
169 
170     // 2、圆(右)
171 
172     string outputFilenameR = "parameters_imgs2_circle_right.yml";  // xml of parameters
173     string inputFilenameR = "imgs2_circle_right.xml";              // 图片集路径
174     MonoCamCalibration monoCaliCircleR(boardSize, pattern, nframes, squareSize, outputFilenameR, inputFilenameR);
175     if (monoCaliCircleR.compute() == 0)
176     {
177         cout << "successfully!" << endl;
178     }
179 
180     Mat cameraMatrixR = monoCaliCircleR.getCameraMatrix();
181     Mat distCoeffsR = monoCaliCircleR.getDistCoeffs();
182     vector<vector<Point2f> > imagePointsR = monoCaliCircleR.getImagePoints();
183     /*vector<vector<Point3f> > objectPoints = monoCaliCircleR.getObjectPoints();*/
184     vector<Mat> rvecsR = monoCaliCircleR.getVecs();
185     vector<Mat> tvecsR = monoCaliCircleR.getTvecs();
186 
187     // 构建PNP world -> right camera -> left camera -> left image plane
188     /*if (computeRT(objectPoints, imagePointsL, rvecsR, tvecsR, cameraMatrixL, distCoeffsL) == 0)
189     {
190 
191     }*/
192     if (computeRT(objectPoints, imagePointsR, rvecsL, tvecsL, cameraMatrixR, distCoeffsR) == 0)
193     {
194 
195     }
196 
197     cv::Mat M1 = cv::Mat::eye(3, 3, CV_64F);
198     cv::Mat M2 = cv::Mat::eye(3, 3, CV_64F);
199     cv::Mat D1, D2, R, T, E, F;
200     cout << "\nRunning stereo calibration ...\n";
201     cout << cv::stereoCalibrate(
202         objectPoints, imagePointsL, imagePointsR, M1, D1, M2, D2, Size(320, 240), R, T, E, F,
203         cv::CALIB_FIX_ASPECT_RATIO ,
204         cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 1000,
205             1e-5)) << endl;
206 }
207 
208 void test3()
209 {
210     // 3、圆(左)
211     Size boardSize(7, 7);                                   //角点size(w, h)
212     Pattern pattern = CIRCLES_GRID;                         //
213     int nframes = 11;                                       // num of images
214     float squareSize = 0.00375f;                            // 格子实际宽度(m)
215 
216     string outputFilenameL = "parameters_imgs3_circle_left.yml";  // xml of parameters
217     string inputFilenameL = "imgs3_circle_left.xml";              // 图片集路径
218     MonoCamCalibration monoCaliCircleL(boardSize, pattern, nframes, squareSize, outputFilenameL, inputFilenameL);
219     if (monoCaliCircleL.compute() == 0)
220     {
221         cout << "successfully!" << endl;
222     }
223 
224     Mat cameraMatrixL                     = monoCaliCircleL.getCameraMatrix();
225     Mat distCoeffsL                       = monoCaliCircleL.getDistCoeffs();
226     vector<vector<Point2f> > imagePointsL = monoCaliCircleL.getImagePoints();
227     vector<vector<Point3f> > objectPoints = monoCaliCircleL.getObjectPoints();
228     vector<Mat> rvecsL                    = monoCaliCircleL.getVecs();
229     vector<Mat> tvecsL                    = monoCaliCircleL.getTvecs();
230 
231     // 2、圆(右)
232 
233     string outputFilenameR = "parameters_imgs3_circle_right.yml";  // xml of parameters
234     string inputFilenameR = "imgs3_circle_right.xml";              // 图片集路径
235     MonoCamCalibration monoCaliCircleR(boardSize, pattern, nframes, squareSize, outputFilenameR, inputFilenameR);
236     if (monoCaliCircleR.compute() == 0)
237     {
238         cout << "successfully!" << endl;
239     }  
240 
241     Mat cameraMatrixR                     = monoCaliCircleR.getCameraMatrix();
242     Mat distCoeffsR                       = monoCaliCircleR.getDistCoeffs();
243     vector<vector<Point2f> > imagePointsR = monoCaliCircleR.getImagePoints();
244     /*vector<vector<Point3f> > objectPoints = monoCaliCircleR.getObjectPoints();*/
245     vector<Mat> rvecsR                    = monoCaliCircleR.getVecs();
246     vector<Mat> tvecsR                    = monoCaliCircleR.getTvecs();
247 
248     // 构建PNP world -> right camera -> left camera -> left image plane
249    /* if (computeRT(objectPoints, imagePointsL, rvecsR, tvecsR, cameraMatrixL, distCoeffsL) == 0)
250     {
251 
252     }*/
253     if (computeRT(objectPoints, imagePointsR, rvecsL, tvecsL, cameraMatrixR, distCoeffsR) == 0)
254     {
255 
256     }
257 
258      cv::Mat M1 = cv::Mat::eye(3, 3, CV_64F);
259      cv::Mat M2 = cv::Mat::eye(3, 3, CV_64F);
260      cv::Mat D1, D2, R, T, E, F;
261      cout << "\nRunning stereo calibration ...\n";
262      cout << cv::stereoCalibrate(
263          objectPoints, imagePointsL, imagePointsR, cameraMatrixL, distCoeffsL, cameraMatrixR, distCoeffsR, Size(640, 480), R, T, E, F,
264          cv::CALIB_FIX_ASPECT_RATIO,
265          cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 1000,
266              1e-5)) << endl;
267     /* cout << -1 * R.t() * T << endl;*/
268 }
269 // 单目标定
270 void test4()
271 {
272     Size boardSize(8, 11);                                   //角点size(w, h)
273     Pattern pattern = CHESSBOARD;                         //
274     int nframes = 6;                                       // num of images
275     float squareSize = 0.03f;                            // 格子实际宽度(m)
276 
277     string outputFilenameL = "parameters_imgs_chessBoard.yml";  // xml of parameters
278     string inputFilenameL = "imgs_chessBoard.xml";              // 图片集路径
279     MonoCamCalibration monoCaliCircleL(boardSize, pattern, nframes, squareSize, outputFilenameL, inputFilenameL);
280     if (monoCaliCircleL.compute() == 0)
281     {
282         cout << "successfully!" << endl;
283     }
284 
285     Mat cameraMatrixL = monoCaliCircleL.getCameraMatrix();
286     Mat distCoeffsL = monoCaliCircleL.getDistCoeffs();
287     vector<vector<Point2f> > imagePointsL = monoCaliCircleL.getImagePoints();
288     vector<vector<Point3f> > objectPoints = monoCaliCircleL.getObjectPoints();
289     vector<Mat> rvecsL = monoCaliCircleL.getVecs();
290     vector<Mat> tvecsL = monoCaliCircleL.getTvecs();
291 
292     
293 }
294 
295 int main(int argc, char** argv)
296 {
297     test1();
298     test2();
299     test3();
300     test4();
301     return 0;
302 }

 

MonoCamCalibration.h

  1 #pragma once
  2 #define _CRT_SECURE_NO_WARNINGS
  3 
  4 #ifndef MONOCAMCALIBRATION_H
  5 #define MONOCAMCALIBRATION_H
  6 
  7 #include "opencv2/core.hpp"
  8 #include <opencv2/core/utility.hpp>
  9 #include "opencv2/imgproc.hpp"
 10 #include "opencv2/calib3d.hpp"
 11 #include "opencv2/imgcodecs.hpp"
 12 #include "opencv2/videoio.hpp"
 13 #include "opencv2/highgui.hpp"
 14 
 15 #include<iostream>
 16 #include <cctype>
 17 #include <stdio.h>
 18 #include <string.h>
 19 #include <time.h>
 20 
 21 using namespace cv;
 22 using namespace std;
 23 
 24 enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
 25 enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
 26 
 27 class MonoCamCalibration
 28 {
 29 public:
 30     MonoCamCalibration(const Size&    boardSize,     
 31                     const Pattern& pattern,        
 32                     const int&     nframes,        
 33                     const float&   squareSize,      
 34                     const string&  outputFilename,  
 35                     const string&  inputFilename);
 36 
 37     // 输出重投影误差
 38         double computeReprojectionErrors(
 39         const vector<vector<Point3f> >& objectPoints,
 40         const vector<vector<Point2f> >& imagePoints,
 41         const vector<Mat>& rvecs, const vector<Mat>& tvecs,
 42         const Mat& cameraMatrix, const Mat& distCoeffs,
 43         vector<float>& perViewErrors);
 44     // 标定板类型判定、设定3D角点
 45     void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD);
 46 
 47     // 执行标定
 48     bool runCalibration(vector<vector<Point2f> > imagePoints,
 49         Size imageSize, Size boardSize, Pattern patternType,
 50         float squareSize, float aspectRatio,
 51         int flags, Mat& cameraMatrix, Mat& distCoeffs,
 52         vector<Mat>& rvecs, vector<Mat>& tvecs,
 53         vector<float>& reprojErrs,
 54         double& totalAvgErr);
 55 
 56     // 保存操作
 57     void saveCameraParams(const string& filename,
 58         Size imageSize, Size boardSize,
 59         float squareSize, float aspectRatio, int flags,
 60         const Mat& cameraMatrix, const Mat& distCoeffs,
 61         const vector<Mat>& rvecs, const vector<Mat>& tvecs,
 62         const vector<float>& reprojErrs,
 63         const vector<vector<Point2f> >& imagePoints,
 64         double totalAvgErr);
 65 
 66     // 从xml/yaml 文件读取文件路径
 67     bool readStringList(const string& filename, vector<string>& l);
 68 
 69     // 执行保存操作
 70     bool runAndSave(const string& outputFilename,
 71         const vector<vector<Point2f> >& imagePoints,
 72         Size imageSize, Size boardSize, Pattern patternType, float squareSize,
 73         float aspectRatio, int flags, Mat& cameraMatrix,
 74         Mat& distCoeffs, bool writeExtrinsics, bool writePoints);
 75 
 76     // 执行整个流程
 77     // 以下是输入参数
 78     //Size boardSize,  //角点size(w, h)
 79     //Pattern pattern, // 默认棋盘
 80     //int nframes,     // num of images
 81     //float squareSize,// 格子实际宽度(m)
 82     //string outputFilename,// xml of parameters              
 83     //string inputFilename
 84     int compute();
 85 
 86     // 
 87     Mat getCameraMatrix() const
 88     {
 89         return this->cameraMatrix;
 90     }
 91     Mat getDistCoeffs() const
 92     {
 93         return this->distCoeffs;
 94     }
 95     vector<Mat> getVecs() const
 96     {
 97         return this->rvecs;
 98     }
 99 
100     vector<Mat> getTvecs() const
101     {
102         return this->tvecs;
103     }
104     vector<vector<Point2f> > getImagePoints() const
105     {
106         return this->imagePoints;
107     }
108     vector<vector<Point3f> > getObjectPoints() const
109     {
110         return this->objectPoints;
111     }
112 
113     vector<size_t> getGoodPaternIdx() const
114     {
115         return this->goodPaternIdx;
116     }
117 
118 private:
119     Size    boardSize;       // 角点size(w, h)
120     Pattern pattern;         // 默认棋盘
121     int     nframes;         // num of images
122     float   squareSize;      // 格子实际宽度(m)
123     string  outputFilename;  // xml of parameters
124     string  inputFilename;   // 图片集路径
125 
126 private:
127     Mat cameraMatrix, distCoeffs;
128     vector<Mat> rvecs, tvecs;
129     vector<vector<Point2f> > imagePoints;
130     vector<vector<Point3f> > objectPoints;
131     vector<size_t> goodPaternIdx;
132     
133 };
134 
135 #endif

MonoCamCalibration.cpp

  1 #include "MonoCamCalibration.h"
  2 
  3 
  4 MonoCamCalibration::MonoCamCalibration(   const Size& boardSize,
  5                                     const Pattern& pattern,
  6                                     const int& nframes,
  7                                     const float& squareSize,
  8                                     const string& outputFilename,
  9                                     const string& inputFilename   ):
 10                                     boardSize(boardSize),
 11                                     pattern(pattern),
 12                                     nframes(nframes),
 13                                     squareSize(squareSize),
 14                                     outputFilename(outputFilename),
 15                                     inputFilename(inputFilename)
 16 {
 17     objectPoints.resize(1);
 18 }
 19 
 20 
 21 
 22 // 输出重投影误差
 23 double MonoCamCalibration::computeReprojectionErrors(
 24     const vector<vector<Point3f> >& objectPoints,
 25     const vector<vector<Point2f> >& imagePoints,
 26     const vector<Mat>& rvecs, const vector<Mat>& tvecs,
 27     const Mat& cameraMatrix, const Mat& distCoeffs,
 28     vector<float>& perViewErrors)
 29 {
 30     vector<Point2f> imagePoints2;
 31     int i, totalPoints = 0;
 32     double totalErr = 0, err;
 33     perViewErrors.resize(objectPoints.size());
 34 
 35     for (i = 0; i < (int)objectPoints.size(); i++)
 36     {
 37         projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2);
 38         err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2);
 39         int n = (int)objectPoints[i].size();
 40         perViewErrors[i] = (float)std::sqrt(err * err / n);
 41         totalErr += err * err;
 42         totalPoints += n;
 43     }
 44 
 45     return std::sqrt(totalErr / totalPoints);
 46 }
 47 
 48 // 标定板类型判定、设定3D角点
 49 void MonoCamCalibration::calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType)
 50 {
 51     corners.resize(0);
 52 
 53     switch (patternType)
 54     {
 55     case CHESSBOARD:
 56     case CIRCLES_GRID: // 对称圆环
 57       // 世界坐标系点
 58         for (int i = 0; i < boardSize.height; i++)
 59             for (int j = 0; j < boardSize.width; j++)
 60                 corners.push_back(Point3f(float(j * squareSize), float(i * squareSize), 0));
 61         break;
 62 
 63     case ASYMMETRIC_CIRCLES_GRID: // 不对称圆环
 64       // 世界坐标系点
 65         for (int i = 0; i < boardSize.height; i++)
 66             for (int j = 0; j < boardSize.width; j++)
 67                 corners.push_back(Point3f(float((2 * j + i % 2) * squareSize), float(i * squareSize), 0));
 68         break;
 69 
 70     default:
 71         CV_Error(Error::StsBadArg, "Unknown pattern type\n");
 72     }
 73 }
 74 
 75 // 执行标定流程
 76 bool MonoCamCalibration::runCalibration(vector<vector<Point2f> > imagePoints,
 77     Size imageSize, Size boardSize, Pattern patternType,
 78     float squareSize, float aspectRatio,
 79     int flags, Mat& cameraMatrix, Mat& distCoeffs,
 80     vector<Mat>& rvecs, vector<Mat>& tvecs,
 81     vector<float>& reprojErrs,
 82     double& totalAvgErr)
 83 {
 84     cameraMatrix = Mat::eye(3, 3, CV_64F);
 85     if (flags & CALIB_FIX_ASPECT_RATIO)
 86         cameraMatrix.at<double>(0, 0) = aspectRatio;
 87 
 88     distCoeffs = Mat::zeros(8, 1, CV_64F);
 89 
 90     
 91     calcChessboardCorners(boardSize, squareSize, objectPoints[0], patternType);
 92 
 93     objectPoints.resize(imagePoints.size(), objectPoints[0]);// 每一张棋盘对应世界坐标系角点3D坐标不变,直接拷贝
 94 
 95     double rms = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags | CALIB_FIX_K4 | CALIB_FIX_K5);
 96     ///*|CALIB_FIX_K3*/|CALIB_FIX_K4|CALIB_FIX_K5);
 97     printf("RMS error reported by calibrateCamera: %g\n", rms);
 98 
 99     bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs); // 检测是否有无穷大 or 无穷小
100 
101     totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs);
102 
103     return ok;
104 }
105 
106 // 保存操作
107 void MonoCamCalibration::saveCameraParams(const string& filename,
108     Size imageSize, Size boardSize,
109     float squareSize, float aspectRatio, int flags,
110     const Mat& cameraMatrix, const Mat& distCoeffs,
111     const vector<Mat>& rvecs, const vector<Mat>& tvecs,
112     const vector<float>& reprojErrs,
113     const vector<vector<Point2f> >& imagePoints,
114     double totalAvgErr)
115 {
116     FileStorage fs(filename, FileStorage::WRITE);
117 
118     time_t tt;
119     time(&tt);
120     struct tm* t2 = localtime(&tt);
121     char buf[1024];
122     strftime(buf, sizeof(buf) - 1, "%c", t2);
123 
124     fs << "calibration_time" << buf;
125 
126     if (!rvecs.empty() || !reprojErrs.empty())
127         fs << "nframes" << (int)std::max(rvecs.size(), reprojErrs.size());
128     fs << "image_width" << imageSize.width;
129     fs << "image_height" << imageSize.height;
130     fs << "board_width" << boardSize.width;
131     fs << "board_height" << boardSize.height;
132     fs << "square_size" << squareSize;
133 
134     if (flags & CALIB_FIX_ASPECT_RATIO)
135         fs << "aspectRatio" << aspectRatio;
136 
137     if (flags != 0)
138     {
139         sprintf(buf, "flags: %s%s%s%s",
140             flags & CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "",
141             flags & CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
142             flags & CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "",
143             flags & CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "");
144         //cvWriteComment( *fs, buf, 0 );
145     }
146 
147     fs << "flags" << flags;
148 
149     fs << "camera_matrix" << cameraMatrix;
150     fs << "distortion_coefficients" << distCoeffs;
151 
152     fs << "avg_reprojection_error" << totalAvgErr;
153     if (!reprojErrs.empty())
154         fs << "per_view_reprojection_errors" << Mat(reprojErrs);
155 
156     if (!rvecs.empty() && !tvecs.empty())
157     {
158         CV_Assert(rvecs[0].type() == tvecs[0].type());
159         Mat bigmat((int)rvecs.size(), 6, rvecs[0].type());
160         for (int i = 0; i < (int)rvecs.size(); i++)
161         {
162             Mat r = bigmat(Range(i, i + 1), Range(0, 3));
163             Mat t = bigmat(Range(i, i + 1), Range(3, 6));
164 
165             CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
166             CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
167             //*.t() is MatExpr (not Mat) so we can use assignment operator
168             r = rvecs[i].t();
169             t = tvecs[i].t();
170         }
171         //cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
172         fs << "extrinsic_parameters" << bigmat;
173     }
174 
175     if (!imagePoints.empty())
176     {
177         Mat imagePtMat((int)imagePoints.size(), (int)imagePoints[0].size(), CV_32FC2);
178         for (int i = 0; i < (int)imagePoints.size(); i++)
179         {
180             Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols);
181             Mat imgpti(imagePoints[i]);
182             imgpti.copyTo(r);
183         }
184         fs << "image_points" << imagePtMat;
185     }
186 }
187 
188 // 从xml/yaml 文件读取文件路径
189 bool MonoCamCalibration::readStringList(const string& filename, vector<string>& l)
190 {
191     l.resize(0);
192     FileStorage fs(filename, FileStorage::READ);
193     if (!fs.isOpened())
194         return false;
195     size_t dir_pos = filename.rfind('/');
196     if (dir_pos == string::npos)
197         dir_pos = filename.rfind('\\');
198     FileNode n = fs.getFirstTopLevelNode();
199     if (n.type() != FileNode::SEQ)
200         return false;
201     FileNodeIterator it = n.begin(), it_end = n.end();
202     for (; it != it_end; ++it)
203     {
204         string fname = (string)*it;
205         if (dir_pos != string::npos)
206         {
207             string fpath = samples::findFile(filename.substr(0, dir_pos + 1) + fname, false);
208             if (fpath.empty())
209             {
210                 fpath = samples::findFile(fname);
211             }
212             fname = fpath;
213         }
214         else
215         {
216             fname = samples::findFile(fname);
217         }
218         l.push_back(fname);
219     }
220     return true;
221 }
222 
223 // 执行保存操作
224 bool MonoCamCalibration::runAndSave(const string& outputFilename,
225     const vector<vector<Point2f> >& imagePoints,
226     Size imageSize, Size boardSize, Pattern patternType, float squareSize,
227     float aspectRatio, int flags, Mat& cameraMatrix,
228     Mat& distCoeffs, bool writeExtrinsics, bool writePoints)
229 {
230     vector<float> reprojErrs;
231     double totalAvgErr = 0;
232 
233     bool ok = runCalibration(imagePoints, imageSize, boardSize, patternType, squareSize, aspectRatio, flags, cameraMatrix, distCoeffs, rvecs, tvecs, reprojErrs, totalAvgErr);
234     printf("%s. avg reprojection error = %.2f\n", ok ? "Calibration succeeded" : "Calibration failed", totalAvgErr);
235     return ok;
236 }
237 
238 int MonoCamCalibration::compute()// 图片集路径
239 {
240     // 优化参数设置
241     // aspectRatio + flags !!!
242     float aspectRatio = 1.0f;                               // fx/fy
243     int flags = 2;                                              // 优化参数
244     //flags |= CALIB_FIX_ASPECT_RATIO;                        // 固定fx/fy
245 
246 
247     // <1>、参数检查
248     if (boardSize.width <= 0)
249         return fprintf(stderr, "Invalid board width\n"), -1;
250     if (boardSize.height <= 0)
251         return fprintf(stderr, "Invalid board height\n"), -1;
252     if (nframes <= 0)
253         return fprintf(stderr, "Invalid  nframes\n"), -1;
254     if (squareSize <= 0)
255         return fprintf(stderr, "Invalid squareSize\n"), -1;
256     if (outputFilename.empty())
257         return fprintf(stderr, "Invalid outputFilename\n"), -1;
258     if (inputFilename.empty())
259         return fprintf(stderr, "Invalid inputFilename\n"), -1;
260 
261     // <2>、读取数据
262     int mode = DETECTION;
263     vector<string> imageList;
264 
265     if (!inputFilename.empty())
266     {
267         if (readStringList(samples::findFile(inputFilename), imageList))
268             mode = CAPTURING;
269     }
270 
271     if (!imageList.empty())
272     {
273         nframes = (int)imageList.size();
274     }
275     else
276     {
277         return -2;
278     }
279 
280     namedWindow("Image View", 1);
281     // <3>、开始检测
282     Size imageSize;
283     int i;
284     for (i = 0;; i++)
285     {
286         Mat view, viewGray;
287 
288         if (i < (int)imageList.size())
289             view = imread(imageList[i], 1);
290 
291         if (view.empty())
292         {
293             cout << i << endl;
294             if (imagePoints.size() > 0)
295                 runAndSave(outputFilename, imagePoints, imageSize, boardSize, pattern, squareSize, aspectRatio, flags, cameraMatrix, distCoeffs, false, false);
296             break;
297 
298         }
299 
300         imageSize = view.size();
301         vector<Point2f> pointbuf;
302         cvtColor(view, viewGray, COLOR_BGR2GRAY);
303         // 检测角点 -> pointbuf
304         bool found;
305         switch (pattern)
306         {
307         case CHESSBOARD:
308             found = findChessboardCorners(view, boardSize, pointbuf, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);
309             break;
310         case CIRCLES_GRID:
311             found = findCirclesGrid(view, boardSize, pointbuf);
312             break;
313         case ASYMMETRIC_CIRCLES_GRID:
314             found = findCirclesGrid(view, boardSize, pointbuf, CALIB_CB_ASYMMETRIC_GRID);
315             break;
316         default:
317             return fprintf(stderr, "Unknown pattern type\n"), -1;
318         }
319 
320         // 提取棋盘亚像素角点
321         if (pattern == CHESSBOARD && found)
322             cornerSubPix(viewGray, pointbuf, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
323 
324         if (mode == CAPTURING && found)
325         {
326             imagePoints.push_back(pointbuf);
327         }
328 
329         if (found)
330             drawChessboardCorners(view, boardSize, Mat(pointbuf), found);
331 
332         string msg = mode == CAPTURING ? "100/100" : mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
333         int baseLine = 0;
334         Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
335         Point textOrigin(view.cols - 2 * textSize.width - 10, view.rows - 2 * baseLine - 10);
336 
337         if (mode == CAPTURING)
338         {
339             msg = format("%d/%d", (int)imagePoints.size(), nframes);
340         }
341 
342         putText(view, msg, textOrigin, 1, 1, mode != CALIBRATED ? Scalar(0, 0, 255) : Scalar(0, 255, 0));
343         imshow("Image View", view);
344         waitKey(10);
345     }
346     return 0;
347 }

 输出结果:

另:对于文件中丢了一堆图,如何获取每一张图的“绝对路径”?这里提供一个方法:

1、新建文本,拷贝以下脚本

DIR /S/B > fileList.txt

保存,修改后缀名为:“.bat”

2、双击该文件,会自动生成 包含所有图片路径的文本文件,如下图:

 1 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_01.png
 2 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_02.png
 3 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_03.png
 4 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_04.png
 5 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_05.png
 6 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_06.png
 7 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_07.png
 8 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_08.png
 9 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_09.png
10 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_10.png
11 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_11.png
12 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_12.png
13 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_13.png
14 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_14.png
15 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\calib_l_15.png
16 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\fileList.txt
17 D:\VS2019_Project\外参数求解\MonoProjectorCalib\calibration2_stereo_circle\left\GetFileList.bat

【记得删除最后两行】

3、注意到上述路径为左斜杠,即:\ ,直接保存到 String中去汇报错,我们将文本文件丢到vs中去,再按Ctrl + F 查找并用“\\”替换 \

 

posted @ 2020-04-24 11:30  佚名12  阅读(93)  评论(0编辑  收藏  举报