iCub-main
Loading...
Searching...
No Matches
CalibrationTypes.h
Go to the documentation of this file.
1#ifndef ICUB_STEREOCALIB_CALIBRATION_TYPES_H
2#define ICUB_STEREOCALIB_CALIBRATION_TYPES_H
3
4#include <cstddef>
5#include <cstdint>
6#include <cmath>
7#include <string>
8#include <vector>
9
10#include <opencv2/calib3d.hpp>
11#include <opencv2/core.hpp>
12
13namespace stereo_calib
14{
15
16 enum class CameraSide
17 {
18 Left,
19 Right
20 };
21
22 enum class CalibrationMode
23 {
24 MonocularLeft, // validate obs -> calibrate left -> populate result.leftCamera -> no call to stereo calib
25 MonocularRight, // validate obs -> calibrate right -> populate result.rightCamera -> no call to stereo calib
26 MonocularBoth, // validate obs -> calibrate left and right -> estimate intrinsics -> no estimation of R and T
27 StereoFull, // validate obs -> calibrate left and right -> stereo calib with fixed intrinsics -> evaluate stereo quality -> populate result with all fields
28 Invalid = 255
29 };
30
31 enum class CameraModel
32 {
33 Pinhole,
34 Fisheye,
35 Invalid = 255
36 };
37
39 {
40 int cornersX{0};
41 int cornersY{0};
42
43 // Physical side length of one chessboard square
44 double squareSizeMeters{0.0};
45
46 cv::Size patternSize() const
47 {
48 return cv::Size(cornersX, cornersY);
49 }
50
51 std::size_t cornersCount() const
52 {
53 if(!isValid())
54 {
55 return 0;
56 }
57 return static_cast<std::size_t>(cornersX)*static_cast<std::size_t>(cornersY);
58 }
59
60 bool isValid() const
61 {
62 return (cornersX > 1 && cornersY > 1 && squareSizeMeters > 0.0);
63 }
64
65 std::vector<cv::Point3f> createObjectPoints() const
66 {
67 std::vector<cv::Point3f> points;
68
69 if(!isValid())
70 {
71 return points;
72 }
73
74 points.reserve(cornersCount());
75
76 for (int r = 0; r < cornersY; ++r)
77 {
78 for(int c = 0; c < cornersX; ++c)
79 {
80 points.emplace_back(
81 static_cast<float>(c * squareSizeMeters),
82 static_cast<float>(r * squareSizeMeters),
83 0.0F
84 );
85 }
86 }
87
88 return points;
89 }
90 };
91
93 {
94 cv::Size imageSize;
95
96 std::vector<cv::Point3f> objectPoints;
97 std::vector<cv::Point2f> leftImagePoints;
98 std::vector<cv::Point2f> rightImagePoints;
99
103
104 int64_t leftSequenceNumber {-1};
106
107 // Relative filenames of the raw images saved for this accepted
108 // observation. They are intentionally part of the observation so
109 // that the point data and the dataset images can be joined without
110 // relying on directory iteration.
111 std::string leftImageFilename;
113
114 bool isValid() const
115 {
116 if(imageSize.width <= 0 ||
117 imageSize.height <= 0)
118 {
119 return false;
120 }
121
122 if(objectPoints.empty())
123 return false;
124
125 return (objectPoints.size() == leftImagePoints.size() &&
126 objectPoints.size() == rightImagePoints.size() &&
128 }
129 };
130
136
138 {
141
143 // cv::CALIB_USE_INTRINSIC_GUESS | to be added later if performance is not good enough
144 // cv::CALIB_FIX_PRINCIPAL_POINT |
145 // cv::CALIB_FIX_TANGENT_DIST |
146 // camCalib uses the legacy four-coefficient pinhole model, so the
147 // OpenCV-only fifth coefficient must remain fixed at zero.
148 cv::CALIB_FIX_K3
149 };
150
152 cv::CALIB_FIX_ASPECT_RATIO |
153 cv::CALIB_FIX_INTRINSIC |
154 cv::CALIB_FIX_K3
155 };
156
157 cv::TermCriteria criteria{
158 cv::TermCriteria::COUNT |
159 cv::TermCriteria::EPS,
160 100,
161 1e-5
162 };
163
164 bool isValid() const
165 {
166 return (common.imageSize.width > 0 &&
167 common.imageSize.height > 0 &&
168 (!(criteria.type & cv::TermCriteria::COUNT) || criteria.maxCount > 0) &&
169 (!(criteria.type & cv::TermCriteria::EPS) ||
170 (std::isfinite(criteria.epsilon) && criteria.epsilon > 0.0)));
171 }
172 };
173
175 {
178
180 cv::fisheye::CALIB_USE_INTRINSIC_GUESS |
181 cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC |
182 cv::fisheye::CALIB_CHECK_COND |
183 cv::fisheye::CALIB_FIX_SKEW
184 };
185
187 cv::fisheye::CALIB_FIX_INTRINSIC |
188 cv::fisheye::CALIB_CHECK_COND |
189 cv::fisheye::CALIB_FIX_SKEW
190 };
191
192 cv::TermCriteria criteria{
193 cv::TermCriteria::COUNT |
194 cv::TermCriteria::EPS,
195 100,
196 1e-5
197 };
198
199 bool isValid() const
200 {
201 return (common.imageSize.width > 0 &&
202 common.imageSize.height > 0 &&
203 (!(criteria.type & cv::TermCriteria::COUNT) || criteria.maxCount > 0) &&
204 (!(criteria.type & cv::TermCriteria::EPS) ||
205 (std::isfinite(criteria.epsilon) && criteria.epsilon > 0.0)));
206 }
207 };
208
210 {
212 cv::Size imageSize;
213
214 // 3x3 intrinsic camera matrix
215 cv::Mat K;
216
217 // Pinhole distortion coefficients: [k1, k2, p1, p2]
218 // Fisheye distortion coefficients: [k1, k2, k3, k4]
219 cv::Mat D;
220
221 // Board pose for each accepted observation
222 std::vector<cv::Mat> rotationVectors;
223 std::vector<cv::Mat> translationVectors;
224
225 // Reprojection RMS for every accepted calibration observation.
226 std::vector<double> perViewRms;
227
228 double rms{-1.0};
229
230 bool isValid() const
231 {
234 return false;
235
236 if(imageSize.width <=0 || imageSize.height <= 0)
237 return false;
238
239 if(K.empty() ||
240 K.rows != 3 ||
241 K.cols != 3 ||
242 K.type() != CV_64F ||
243 !cv::checkRange(K, true))
244 return false;
245
246 if(D.empty() ||
247 D.total() != 4 ||
248 D.type() != CV_64F ||
249 !cv::checkRange(D, true))
250 return false;
251
252 if(K.at<double>(0, 0) <= 0.0 ||
253 K.at<double>(1,1) <= 0.0)
254 return false;
255
256 if(!std::isfinite(rms) || rms < 0.0)
257 return false;
258
259 if(rotationVectors.size() != translationVectors.size() ||
260 rotationVectors.size() != perViewRms.size())
261 return false;
262
263 for (size_t i = 0; i < rotationVectors.size(); i++)
264 {
265 const cv::Mat& rotation = rotationVectors[i];
266 const cv::Mat& translation = translationVectors[i];
267
268 if(rotation.empty() ||
269 rotation.total() != 3 ||
270 rotation.type() != CV_64F ||
271 !cv::checkRange(rotation, true))
272 return false;
273
274 if(translation.empty() ||
275 translation.total() != 3 ||
276 translation.type() != CV_64F ||
277 !cv::checkRange(translation, true))
278 return false;
279
280 if(!std::isfinite(perViewRms[i]) ||
281 perViewRms[i] < 0.0)
282 return false;
283 }
284
285 return true;
286 }
287 };
288
290 {
291 // Transform convention:
292 //
293 // X_right = R * X_left + T
294 //
295 // R: 3x3 rotation matrix
296 // T: 3x1 translation vector.
297 cv::Mat R;
298 cv::Mat T;
299
300 double rms{-1.0};
301
302 bool isValid() const
303 {
304 if(R.empty() ||
305 R.rows != 3 ||
306 R.cols != 3 ||
307 R.type() != CV_64F ||
308 !cv::checkRange(R, true)
309 )
310 return false;
311
312 if(T.empty() ||
313 T.total() != 3 ||
314 T.type() != CV_64F ||
315 !cv::checkRange(T, true))
316 return false;
317
318 if(!std::isfinite(rms) ||
319 rms < 0.0 )
320 return false;
321
322 const cv::Mat identity = cv::Mat::eye(3,3,CV_64F);
323 if(std::abs(cv::determinant(R) - 1.0) >= 1e-3 ||
324 cv::norm(R.t() * R - identity, cv::NORM_INF) >= 1e-3 ||
325 cv::norm(T) <= 1e-9)
326 return false;
327
328 return true;
329 }
330 };
331
333 {
334 std::size_t synchronizedPairs{0};
335 std::size_t acceptedObservations{0};
336 std::size_t rejectedDetections{0};
337
340
341 // Baseline expressed in the same unit as StereoCalibrationResult::T.
342 // It is calculated by the calibration engine, not by persistence.
343 double baseline{-1.0};
344 };
345
347 {
350
353
355
357
358 bool isValid() const
359 {
360 const auto validCamera =
361 [this](const CameraCalibrationResult& camera)
362 {
363 return camera.model == model &&
364 camera.isValid();
365 };
366
367 switch (mode)
368 {
370 return validCamera(leftCamera);
372 return validCamera(rightCamera);
374 return (validCamera(leftCamera) && validCamera(rightCamera));
376 return (validCamera(leftCamera) &&
377 validCamera(rightCamera) &&
378 stereo.isValid());
379 }
380 return false;
381 }
382 };
383
384} // namespace stereo_calib
385
386#endif
CameraCalibrationResult leftCamera
StereoCalibrationResult stereo
CameraCalibrationResult rightCamera
CalibrationQualityMetrics quality
std::vector< cv::Point3f > createObjectPoints() const
std::vector< cv::Point2f > leftImagePoints
std::vector< cv::Point3f > objectPoints
std::vector< cv::Point2f > rightImagePoints