39 #include <opencv2/calib3d.hpp>
40 #include <opencv2/core.hpp>
41 #include <opencv2/core/utility.hpp>
42 #include <opencv2/highgui.hpp>
43 #include <opencv2/imgcodecs.hpp>
44 #include <opencv2/imgproc.hpp>
45 #include <opencv2/opencv.hpp>
46 #include <opencv2/videoio.hpp>
48 #include "Image/ByteImage.h"
49 #include "Image/ImageProcessor.h"
50 #include "Image/IplImageAdaptor.h"
70 computeReprojectionErrors(
const std::vector<std::vector<cv::Point3f>>& objectPoints,
71 const std::vector<std::vector<cv::Point2f>>& imagePoints,
72 const std::vector<cv::Mat>& rvecs,
73 const std::vector<cv::Mat>& tvecs,
74 const cv::Mat& cameraMatrix,
75 const cv::Mat& distCoeffs,
76 std::vector<float>& perViewErrors)
78 std::vector<cv::Point2f> imagePoints2;
79 size_t totalPoints = 0;
80 double totalErr = 0, err;
81 perViewErrors.resize(objectPoints.size());
83 for (
size_t i = 0; i < objectPoints.size(); ++i)
86 objectPoints[i], rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2);
87 err =
cv::norm(imagePoints[i], imagePoints2, cv::NORM_L2);
89 size_t n = objectPoints[i].size();
91 totalErr += err * err;
99 calcBoardCornerPositions(cv::Size boardSize,
101 std::vector<cv::Point3f>& corners,
110 for (
int i = 0; i < boardSize.height; ++i)
111 for (
int j = 0; j < boardSize.width; ++j)
113 corners.push_back(cv::Point3f(j * squareSize, i * squareSize, 0));
118 for (
int i = 0; i < boardSize.height; i++)
119 for (
int j = 0; j < boardSize.width; j++)
122 cv::Point3f((2 * j + i % 2) * squareSize, i * squareSize, 0));
133 cv::Mat& cameraMatrix,
135 std::vector<std::vector<cv::Point2f>> imagePoints,
136 std::vector<cv::Mat>& rvecs,
137 std::vector<cv::Mat>& tvecs,
138 std::vector<float>& reprojErrs,
142 cameraMatrix = cv::Mat::eye(3, 3, CV_64F);
143 if (
s.flag & cv::CALIB_FIX_ASPECT_RATIO)
145 cameraMatrix.at<
double>(0, 0) =
s.aspectRatio;
148 distCoeffs = cv::Mat::zeros(8, 1, CV_64F);
150 std::vector<std::vector<cv::Point3f>> objectPoints(1);
151 calcBoardCornerPositions(
s.boardSize,
s.squareSize, objectPoints[0],
s.calibrationPattern);
153 objectPoints.resize(imagePoints.size(), objectPoints[0]);
158 rms = cv::calibrateCamera(
159 objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs,
s.flag);
161 ARMARX_INFO <<
"Re-projection error reported by calibrateCamera: " << rms;
163 bool ok = cv::checkRange(cameraMatrix) && cv::checkRange(distCoeffs);
165 totalAvgErr = computeReprojectionErrors(
166 objectPoints, imagePoints, rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs);
174 cv::Mat& cameraMatrix,
176 const std::vector<cv::Mat>& rvecs,
177 const std::vector<cv::Mat>& tvecs,
178 const std::vector<float>& reprojErrs,
179 const std::vector<std::vector<cv::Point2f>>& imagePoints,
182 cv::FileStorage fs(
s.outputFileName, cv::FileStorage::WRITE);
186 struct tm* t2 = localtime(&tm);
188 strftime(buf,
sizeof(buf),
"%c", t2);
190 fs <<
"calibration_time" << buf;
192 if (!rvecs.empty() || !reprojErrs.empty())
194 fs <<
"nr_of_frames" << (int)
std::max(rvecs.size(), reprojErrs.size());
196 fs <<
"image_width" << imageSize.width;
197 fs <<
"image_height" << imageSize.height;
198 fs <<
"board_width" <<
s.boardSize.width;
199 fs <<
"board_height" <<
s.boardSize.height;
200 fs <<
"square_size" <<
s.squareSize;
202 if (
s.flag & cv::CALIB_FIX_ASPECT_RATIO)
204 fs <<
"fix_aspect_ratio" <<
s.aspectRatio;
209 std::stringstream flagsStringStream;
211 flagsStringStream <<
"flags:"
212 << (
s.flag & cv::CALIB_USE_INTRINSIC_GUESS ?
" +use_intrinsic_guess"
214 << (
s.flag & cv::CALIB_FIX_ASPECT_RATIO ?
" +fix_aspectRatio" :
"")
215 << (
s.flag & cv::CALIB_FIX_PRINCIPAL_POINT ?
" +fix_principal_point"
217 << (
s.flag & cv::CALIB_ZERO_TANGENT_DIST ?
" +zero_tangent_dist" :
"")
218 << (
s.flag & cv::CALIB_FIX_K1 ?
" +fix_k1" :
"")
219 << (
s.flag & cv::CALIB_FIX_K2 ?
" +fix_k2" :
"")
220 << (
s.flag & cv::CALIB_FIX_K3 ?
" +fix_k3" :
"")
221 << (
s.flag & cv::CALIB_FIX_K4 ?
" +fix_k4" :
"")
222 << (
s.flag & cv::CALIB_FIX_K5 ?
" +fix_k5" :
"")
223 << (
s.flag & cv::CALIB_FIX_K6 ?
" +fix_k6" :
"");
225 fs.writeComment(flagsStringStream.str());
228 fs <<
"flags" <<
s.flag;
230 fs <<
"camera_matrix" << cameraMatrix;
231 fs <<
"distortion_coefficients" << distCoeffs;
233 fs <<
"avg_reprojection_error" << totalAvgErr;
234 if (
s.writeExtrinsics && !reprojErrs.empty())
236 fs <<
"per_view_reprojection_errors" << cv::Mat(reprojErrs);
239 if (
s.writeExtrinsics && !rvecs.empty() && !tvecs.empty())
241 CV_Assert(rvecs[0].type() == tvecs[0].type());
242 cv::Mat bigmat((
int)rvecs.size(), 6, CV_MAKETYPE(rvecs[0].type(), 1));
243 bool needReshapeR = rvecs[0].depth() != 1 ? true :
false;
244 bool needReshapeT = tvecs[0].depth() != 1 ? true :
false;
246 for (
size_t i = 0; i < rvecs.size(); i++)
248 cv::Mat r = bigmat(cv::Range(
int(i),
int(i + 1)), cv::Range(0, 3));
249 cv::Mat t = bigmat(cv::Range(
int(i),
int(i + 1)), cv::Range(3, 6));
253 rvecs[i].reshape(1, 1).copyTo(r);
258 CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
264 tvecs[i].reshape(1, 1).copyTo(t);
268 CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
273 "a set of 6-tuples (rotation vector + translation vector) for each view");
274 fs <<
"extrinsic_parameters" << bigmat;
277 if (
s.writePoints && !imagePoints.empty())
279 cv::Mat imagePtMat((
int)imagePoints.size(), (
int)imagePoints[0].size(), CV_32FC2);
280 for (
size_t i = 0; i < imagePoints.size(); i++)
282 cv::Mat r = imagePtMat.row(
int(i)).reshape(2, imagePtMat.cols);
283 cv::Mat imgpti(imagePoints[i]);
286 fs <<
"image_points" << imagePtMat;
293 cv::Mat& cameraMatrix,
295 std::vector<std::vector<cv::Point2f>> imagePoints)
297 std::vector<cv::Mat> rvecs, tvecs;
298 std::vector<float> reprojErrs;
299 double totalAvgErr = 0;
301 bool ok = runCalibration(
s,
310 ARMARX_INFO << (
ok ?
"Calibration succeeded" :
"Calibration failed")
311 <<
". avg re projection error = " << totalAvgErr;
336 providerName = getProperty<std::string>(
"ImageProviderAdapterName").getValue();
340 waitingTimeBetweenCaptures =
341 IceUtil::Time::milliSeconds(getProperty<int>(
"WaitingIntervalBetweenImages"));
342 std::string image_side = getProperty<std::string>(
"ImageToUse").getValue();
343 if (image_side ==
"left")
347 else if (image_side ==
"right")
353 throw std::runtime_error(
"ImageToUse must be either left or right");
361 imageProviderPrx = getProxy<ImageProviderInterfacePrx>(providerName);
362 StereoCalibrationInterfacePrx calibrationProvider =
363 StereoCalibrationInterfacePrx::checkedCast(imageProviderInfo.
proxy);
364 auto cam = calibrationProvider->getStereoCalibration();
365 auto calib = imageID == 0 ? cam.calibrationLeft : cam.calibrationRight;
366 auto focal_lengths = calib.cameraParam.focalLength;
368 cameraImages =
new CByteImage*[2];
382 if (getProperty<bool>(
"EnableFixAspectRatio"))
384 m_settings.
aspectRatio = focal_lengths.at(0) / focal_lengths.at(1);
404 throw std::runtime_error(
"Invalid input detected. Application stopping.");
408 << m_settings.
boardSize.height <<
" squares with square size of "
415 delete cameraImages[0];
416 delete cameraImages[1];
417 delete[] cameraImages;
435 if (IceUtil::Time::now() - timeOfLastCapture < waitingTimeBetweenCaptures)
440 ARMARX_INFO <<
"Capturing image for calibration #" << imagePoints.size();
442 timeOfLastCapture = IceUtil::Time::now();
446 if (m_mode == CAPTURING && imagePoints.size() >= (
size_t)m_settings.
nrFrames)
449 if (runCalibrationAndSave(m_settings, imageSize, cameraMatrix, distCoeffs, imagePoints))
456 imageSize = view.size();
459 cv::flip(view, view, 0);
463 std::vector<cv::Point2f> pointBuf;
467 int chessBoardFlags =
468 cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE | cv::CALIB_CB_FAST_CHECK;
474 found = cv::findChessboardCorners(
475 view, m_settings.
boardSize, pointBuf, chessBoardFlags);
478 found = cv::findCirclesGrid(view, m_settings.
boardSize, pointBuf);
481 found = cv::findCirclesGrid(
482 view, m_settings.
boardSize, pointBuf, cv::CALIB_CB_ASYMMETRIC_GRID);
497 cv::cvtColor(view, viewGray, cv::COLOR_BGR2GRAY);
506 if (m_mode == CAPTURING)
508 imagePoints.push_back(pointBuf);
512 cv::drawChessboardCorners(view, m_settings.
boardSize, cv::Mat(pointBuf), found);