Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/cpp/3calibration.cpp
16337 views
1
/*
2
* 3calibration.cpp -- Calibrate 3 cameras in a horizontal line together.
3
*/
4
5
#include "opencv2/calib3d.hpp"
6
#include "opencv2/imgproc.hpp"
7
#include "opencv2/imgcodecs.hpp"
8
#include "opencv2/highgui.hpp"
9
#include "opencv2/core/utility.hpp"
10
11
#include <stdio.h>
12
#include <string.h>
13
#include <time.h>
14
15
using namespace cv;
16
using namespace std;
17
18
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
19
20
static void help()
21
{
22
printf( "\nThis is a camera calibration sample that calibrates 3 horizontally placed cameras together.\n"
23
"Usage: 3calibration\n"
24
" -w=<board_width> # the number of inner corners per one of board dimension\n"
25
" -h=<board_height> # the number of inner corners per another board dimension\n"
26
" [-s=<squareSize>] # square size in some user-defined units (1 by default)\n"
27
" [-o=<out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n"
28
" [-zt] # assume zero tangential distortion\n"
29
" [-a=<aspectRatio>] # fix aspect ratio (fx/fy)\n"
30
" [-p] # fix the principal point at the center\n"
31
" [input_data] # input data - text file with a list of the images of the board\n"
32
"\n" );
33
34
}
35
36
static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners)
37
{
38
corners.resize(0);
39
40
for( int i = 0; i < boardSize.height; i++ )
41
for( int j = 0; j < boardSize.width; j++ )
42
corners.push_back(Point3f(float(j*squareSize),
43
float(i*squareSize), 0));
44
}
45
46
static bool run3Calibration(vector<vector<Point2f> > imagePoints1,
47
vector<vector<Point2f> > imagePoints2,
48
vector<vector<Point2f> > imagePoints3,
49
Size imageSize, Size boardSize,
50
float squareSize, float aspectRatio,
51
int flags,
52
Mat& cameraMatrix1, Mat& distCoeffs1,
53
Mat& cameraMatrix2, Mat& distCoeffs2,
54
Mat& cameraMatrix3, Mat& distCoeffs3,
55
Mat& R12, Mat& T12, Mat& R13, Mat& T13)
56
{
57
int c, i;
58
59
// step 1: calibrate each camera individually
60
vector<vector<Point3f> > objpt(1);
61
vector<vector<Point2f> > imgpt;
62
calcChessboardCorners(boardSize, squareSize, objpt[0]);
63
vector<Mat> rvecs, tvecs;
64
65
for( c = 1; c <= 3; c++ )
66
{
67
const vector<vector<Point2f> >& imgpt0 = c == 1 ? imagePoints1 : c == 2 ? imagePoints2 : imagePoints3;
68
imgpt.clear();
69
int N = 0;
70
for( i = 0; i < (int)imgpt0.size(); i++ )
71
if( !imgpt0[i].empty() )
72
{
73
imgpt.push_back(imgpt0[i]);
74
N += (int)imgpt0[i].size();
75
}
76
77
if( imgpt.size() < 3 )
78
{
79
printf("Error: not enough views for camera %d\n", c);
80
return false;
81
}
82
83
objpt.resize(imgpt.size(),objpt[0]);
84
85
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
86
if( flags & CALIB_FIX_ASPECT_RATIO )
87
cameraMatrix.at<double>(0,0) = aspectRatio;
88
89
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
90
91
double err = calibrateCamera(objpt, imgpt, imageSize, cameraMatrix,
92
distCoeffs, rvecs, tvecs,
93
flags|CALIB_FIX_K3/*|CALIB_FIX_K4|CALIB_FIX_K5|CALIB_FIX_K6*/);
94
bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs);
95
if(!ok)
96
{
97
printf("Error: camera %d was not calibrated\n", c);
98
return false;
99
}
100
printf("Camera %d calibration reprojection error = %g\n", c, sqrt(err/N));
101
102
if( c == 1 )
103
cameraMatrix1 = cameraMatrix, distCoeffs1 = distCoeffs;
104
else if( c == 2 )
105
cameraMatrix2 = cameraMatrix, distCoeffs2 = distCoeffs;
106
else
107
cameraMatrix3 = cameraMatrix, distCoeffs3 = distCoeffs;
108
}
109
110
vector<vector<Point2f> > imgpt_right;
111
112
// step 2: calibrate (1,2) and (3,2) pairs
113
for( c = 2; c <= 3; c++ )
114
{
115
const vector<vector<Point2f> >& imgpt0 = c == 2 ? imagePoints2 : imagePoints3;
116
117
imgpt.clear();
118
imgpt_right.clear();
119
int N = 0;
120
121
for( i = 0; i < (int)std::min(imagePoints1.size(), imgpt0.size()); i++ )
122
if( !imagePoints1.empty() && !imgpt0[i].empty() )
123
{
124
imgpt.push_back(imagePoints1[i]);
125
imgpt_right.push_back(imgpt0[i]);
126
N += (int)imgpt0[i].size();
127
}
128
129
if( imgpt.size() < 3 )
130
{
131
printf("Error: not enough shared views for cameras 1 and %d\n", c);
132
return false;
133
}
134
135
objpt.resize(imgpt.size(),objpt[0]);
136
Mat cameraMatrix = c == 2 ? cameraMatrix2 : cameraMatrix3;
137
Mat distCoeffs = c == 2 ? distCoeffs2 : distCoeffs3;
138
Mat R, T, E, F;
139
double err = stereoCalibrate(objpt, imgpt, imgpt_right, cameraMatrix1, distCoeffs1,
140
cameraMatrix, distCoeffs,
141
imageSize, R, T, E, F,
142
CALIB_FIX_INTRINSIC,
143
TermCriteria(TermCriteria::COUNT, 30, 0));
144
printf("Pair (1,%d) calibration reprojection error = %g\n", c, sqrt(err/(N*2)));
145
if( c == 2 )
146
{
147
cameraMatrix2 = cameraMatrix;
148
distCoeffs2 = distCoeffs;
149
R12 = R; T12 = T;
150
}
151
else
152
{
153
R13 = R; T13 = T;
154
}
155
}
156
157
return true;
158
}
159
160
static bool readStringList( const string& filename, vector<string>& l )
161
{
162
l.resize(0);
163
FileStorage fs(filename, FileStorage::READ);
164
if( !fs.isOpened() )
165
return false;
166
FileNode n = fs.getFirstTopLevelNode();
167
if( n.type() != FileNode::SEQ )
168
return false;
169
FileNodeIterator it = n.begin(), it_end = n.end();
170
for( ; it != it_end; ++it )
171
l.push_back((string)*it);
172
return true;
173
}
174
175
176
int main( int argc, char** argv )
177
{
178
int i, k;
179
int flags = 0;
180
Size boardSize, imageSize;
181
float squareSize, aspectRatio;
182
string outputFilename;
183
string inputFilename = "";
184
185
vector<vector<Point2f> > imgpt[3];
186
vector<string> imageList;
187
188
cv::CommandLineParser parser(argc, argv,
189
"{help ||}{w||}{h||}{s|1|}{o|out_camera_data.yml|}"
190
"{zt||}{a|1|}{p||}{@input||}");
191
if (parser.has("help"))
192
{
193
help();
194
return 0;
195
}
196
boardSize.width = parser.get<int>("w");
197
boardSize.height = parser.get<int>("h");
198
squareSize = parser.get<float>("s");
199
aspectRatio = parser.get<float>("a");
200
if (parser.has("a"))
201
flags |= CALIB_FIX_ASPECT_RATIO;
202
if (parser.has("zt"))
203
flags |= CALIB_ZERO_TANGENT_DIST;
204
if (parser.has("p"))
205
flags |= CALIB_FIX_PRINCIPAL_POINT;
206
outputFilename = parser.get<string>("o");
207
inputFilename = parser.get<string>("@input");
208
if (!parser.check())
209
{
210
help();
211
parser.printErrors();
212
return -1;
213
}
214
if (boardSize.width <= 0)
215
return fprintf( stderr, "Invalid board width\n" ), -1;
216
if (boardSize.height <= 0)
217
return fprintf( stderr, "Invalid board height\n" ), -1;
218
if (squareSize <= 0)
219
return fprintf( stderr, "Invalid board square width\n" ), -1;
220
if (aspectRatio <= 0)
221
return printf("Invalid aspect ratio\n" ), -1;
222
if( inputFilename.empty() ||
223
!readStringList(inputFilename, imageList) ||
224
imageList.size() == 0 || imageList.size() % 3 != 0 )
225
{
226
printf("Error: the input image list is not specified, or can not be read, or the number of files is not divisible by 3\n");
227
return -1;
228
}
229
230
Mat view, viewGray;
231
Mat cameraMatrix[3], distCoeffs[3], R[3], P[3], R12, T12;
232
for( k = 0; k < 3; k++ )
233
{
234
cameraMatrix[k] = Mat_<double>::eye(3,3);
235
cameraMatrix[k].at<double>(0,0) = aspectRatio;
236
cameraMatrix[k].at<double>(1,1) = 1;
237
distCoeffs[k] = Mat_<double>::zeros(5,1);
238
}
239
Mat R13=Mat_<double>::eye(3,3), T13=Mat_<double>::zeros(3,1);
240
241
FileStorage fs;
242
namedWindow( "Image View", 0 );
243
244
for( k = 0; k < 3; k++ )
245
imgpt[k].resize(imageList.size()/3);
246
247
for( i = 0; i < (int)(imageList.size()/3); i++ )
248
{
249
for( k = 0; k < 3; k++ )
250
{
251
int k1 = k == 0 ? 2 : k == 1 ? 0 : 1;
252
printf("%s\n", imageList[i*3+k].c_str());
253
view = imread(imageList[i*3+k], 1);
254
255
if(!view.empty())
256
{
257
vector<Point2f> ptvec;
258
imageSize = view.size();
259
cvtColor(view, viewGray, COLOR_BGR2GRAY);
260
bool found = findChessboardCorners( view, boardSize, ptvec, CALIB_CB_ADAPTIVE_THRESH );
261
262
drawChessboardCorners( view, boardSize, Mat(ptvec), found );
263
if( found )
264
{
265
imgpt[k1][i].resize(ptvec.size());
266
std::copy(ptvec.begin(), ptvec.end(), imgpt[k1][i].begin());
267
}
268
//imshow("view", view);
269
//int c = waitKey(0) & 255;
270
//if( c == 27 || c == 'q' || c == 'Q' )
271
// return -1;
272
}
273
}
274
}
275
276
printf("Running calibration ...\n");
277
278
run3Calibration(imgpt[0], imgpt[1], imgpt[2], imageSize,
279
boardSize, squareSize, aspectRatio, flags|CALIB_FIX_K4|CALIB_FIX_K5,
280
cameraMatrix[0], distCoeffs[0],
281
cameraMatrix[1], distCoeffs[1],
282
cameraMatrix[2], distCoeffs[2],
283
R12, T12, R13, T13);
284
285
fs.open(outputFilename, FileStorage::WRITE);
286
287
fs << "cameraMatrix1" << cameraMatrix[0];
288
fs << "cameraMatrix2" << cameraMatrix[1];
289
fs << "cameraMatrix3" << cameraMatrix[2];
290
291
fs << "distCoeffs1" << distCoeffs[0];
292
fs << "distCoeffs2" << distCoeffs[1];
293
fs << "distCoeffs3" << distCoeffs[2];
294
295
fs << "R12" << R12;
296
fs << "T12" << T12;
297
fs << "R13" << R13;
298
fs << "T13" << T13;
299
300
fs << "imageWidth" << imageSize.width;
301
fs << "imageHeight" << imageSize.height;
302
303
Mat Q;
304
305
// step 3: find rectification transforms
306
double ratio = rectify3Collinear(cameraMatrix[0], distCoeffs[0], cameraMatrix[1],
307
distCoeffs[1], cameraMatrix[2], distCoeffs[2],
308
imgpt[0], imgpt[2],
309
imageSize, R12, T12, R13, T13,
310
R[0], R[1], R[2], P[0], P[1], P[2], Q, -1.,
311
imageSize, 0, 0, CALIB_ZERO_DISPARITY);
312
Mat map1[3], map2[3];
313
314
fs << "R1" << R[0];
315
fs << "R2" << R[1];
316
fs << "R3" << R[2];
317
318
fs << "P1" << P[0];
319
fs << "P2" << P[1];
320
fs << "P3" << P[2];
321
322
fs << "disparityRatio" << ratio;
323
fs.release();
324
325
printf("Disparity ratio = %g\n", ratio);
326
327
for( k = 0; k < 3; k++ )
328
initUndistortRectifyMap(cameraMatrix[k], distCoeffs[k], R[k], P[k], imageSize, CV_16SC2, map1[k], map2[k]);
329
330
Mat canvas(imageSize.height, imageSize.width*3, CV_8UC3), small_canvas;
331
destroyWindow("view");
332
canvas = Scalar::all(0);
333
334
for( i = 0; i < (int)(imageList.size()/3); i++ )
335
{
336
canvas = Scalar::all(0);
337
for( k = 0; k < 3; k++ )
338
{
339
int k1 = k == 0 ? 2 : k == 1 ? 0 : 1;
340
int k2 = k == 0 ? 1 : k == 1 ? 0 : 2;
341
view = imread(imageList[i*3+k], 1);
342
343
if(view.empty())
344
continue;
345
346
Mat rview = canvas.colRange(k2*imageSize.width, (k2+1)*imageSize.width);
347
remap(view, rview, map1[k1], map2[k1], INTER_LINEAR);
348
}
349
printf("%s %s %s\n", imageList[i*3].c_str(), imageList[i*3+1].c_str(), imageList[i*3+2].c_str());
350
resize( canvas, small_canvas, Size(1500, 1500/3), 0, 0, INTER_LINEAR_EXACT );
351
for( k = 0; k < small_canvas.rows; k += 16 )
352
line(small_canvas, Point(0, k), Point(small_canvas.cols, k), Scalar(0,255,0), 1);
353
imshow("rectified", small_canvas);
354
char c = (char)waitKey(0);
355
if( c == 27 || c == 'q' || c == 'Q' )
356
break;
357
}
358
359
return 0;
360
}
361
362