29 #include "ui_calibrationDialog.h" 31 #include <opencv2/core/core.hpp> 32 #include <opencv2/imgproc/imgproc.hpp> 33 #include <opencv2/imgproc/imgproc_c.h> 34 #include <opencv2/calib3d/calib3d.hpp> 35 #if CV_MAJOR_VERSION >= 3 36 #include <opencv2/calib3d/calib3d_c.h> 38 #include <opencv2/highgui/highgui.hpp> 39 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 43 #include <QFileDialog> 44 #include <QMessageBox> 45 #include <QCloseEvent> 60 rightSuffix_(
"right"),
61 savingDirectory_(savingDirectory),
62 processingData_(
false),
63 savedCalibration_(
false)
78 qRegisterMetaType<cv::Mat>(
"cv::Mat");
80 ui_ =
new Ui_calibrationDialog();
83 connect(ui_->pushButton_calibrate, SIGNAL(clicked()),
this, SLOT(
calibrate()));
84 connect(ui_->pushButton_restart, SIGNAL(clicked()),
this, SLOT(
restart()));
85 connect(ui_->pushButton_save, SIGNAL(clicked()),
this, SLOT(
save()));
86 connect(ui_->checkBox_switchImages, SIGNAL(stateChanged(
int)),
this, SLOT(
restart()));
87 connect(ui_->checkBox_unlock, SIGNAL(stateChanged(
int)), SLOT(
unlock()));
89 connect(ui_->spinBox_boardWidth, SIGNAL(valueChanged(
int)),
this, SLOT(
setBoardWidth(
int)));
90 connect(ui_->spinBox_boardHeight, SIGNAL(valueChanged(
int)),
this, SLOT(
setBoardHeight(
int)));
91 connect(ui_->doubleSpinBox_squareSize, SIGNAL(valueChanged(
double)),
this, SLOT(
setSquareSize(
double)));
93 connect(ui_->spinBox_maxScale, SIGNAL(valueChanged(
int)),
this, SLOT(
setMaxScale(
int)));
95 connect(ui_->buttonBox, SIGNAL(rejected()),
this, SLOT(close()));
97 ui_->image_view->setFocus();
99 ui_->progressBar_count->setMaximum(
COUNT_MIN);
100 ui_->progressBar_count->setFormat(
"%v");
101 ui_->progressBar_count_2->setMaximum(
COUNT_MIN);
102 ui_->progressBar_count_2->setFormat(
"%v");
104 ui_->radioButton_raw->setChecked(
true);
106 ui_->checkBox_switchImages->setChecked(switchImages);
108 ui_->checkBox_fisheye->setChecked(
false);
123 settings.beginGroup(group);
125 settings.setValue(
"board_width",
ui_->spinBox_boardWidth->value());
126 settings.setValue(
"board_height",
ui_->spinBox_boardHeight->value());
127 settings.setValue(
"board_square_size",
ui_->doubleSpinBox_squareSize->value());
128 settings.setValue(
"max_scale",
ui_->spinBox_maxScale->value());
129 settings.setValue(
"geometry", this->saveGeometry());
140 settings.beginGroup(group);
142 this->
setBoardWidth(settings.value(
"board_width",
ui_->spinBox_boardWidth->value()).toInt());
143 this->
setBoardHeight(settings.value(
"board_height",
ui_->spinBox_boardHeight->value()).toInt());
144 this->
setSquareSize(settings.value(
"board_square_size",
ui_->doubleSpinBox_squareSize->value()).toDouble());
145 this->
setMaxScale(settings.value(
"max_scale",
ui_->spinBox_maxScale->value()).toDouble());
146 QByteArray bytes = settings.value(
"geometry", QByteArray()).toByteArray();
149 this->restoreGeometry(bytes);
171 ui_->groupBox_progress->setVisible(visible);
176 ui_->checkBox_switchImages->setChecked(switched);
181 ui_->checkBox_fisheye->setChecked(enabled);
190 ui_->groupBox_progress->setVisible(
true);
196 ui_->progressBar_count_2->setVisible(
stereo_);
205 ui_->label_baseline_name->setVisible(
stereo_);
210 ui_->radioButton_stereoRectified->setVisible(
stereo_);
211 ui_->checkBox_switchImages->setVisible(
stereo_);
212 ui_->doubleSpinBox_stereoBaseline->setVisible(
stereo_);
213 ui_->label_stereoBaseline->setVisible(
stereo_);
218 return ui_->spinBox_boardWidth->value();
222 return ui_->spinBox_boardHeight->value();
226 return ui_->doubleSpinBox_squareSize->value();
231 if(width !=
ui_->spinBox_boardWidth->value())
233 ui_->spinBox_boardWidth->setValue(width);
240 if(height !=
ui_->spinBox_boardHeight->value())
242 ui_->spinBox_boardHeight->setValue(height);
249 if(size !=
ui_->doubleSpinBox_squareSize->value())
251 ui_->doubleSpinBox_squareSize->setValue(size);
258 if(length !=
ui_->doubleSpinBox_stereoBaseline->value())
260 ui_->doubleSpinBox_stereoBaseline->setValue(length);
266 if(scale !=
ui_->spinBox_maxScale->value())
268 ui_->spinBox_maxScale->setValue(scale);
279 QMessageBox::StandardButton b = QMessageBox::question(
this, tr(
"Save calibration?"),
280 tr(
"The camera is calibrated but you didn't " 281 "save the calibration, do you want to save it?"),
282 QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Yes);
284 if(b == QMessageBox::Yes)
291 else if(b == QMessageBox::Ignore)
300 if(event->isAccepted())
316 QMetaObject::invokeMethod(
this,
"processImages",
319 Q_ARG(QString, QString(e->
cameraName().c_str())));
328 UDEBUG(
"Processing images");
334 else if(cameraName.isEmpty())
344 std::vector<cv::Mat> inputRawImages(2);
345 if(
ui_->checkBox_switchImages->isChecked())
347 inputRawImages[0] = imageRight;
348 inputRawImages[1] = imageLeft;
352 inputRawImages[0] = imageLeft;
353 inputRawImages[1] = imageRight;
356 std::vector<cv::Mat> images(2);
357 images[0] = inputRawImages[0];
358 images[1] = inputRawImages[1];
362 bool boardFound[2] = {
false};
363 bool boardAccepted[2] = {
false};
364 bool readyToCalibrate[2] = {
false};
366 std::vector<std::vector<cv::Point2f> > pointBuf(2);
368 bool depthDetected =
false;
369 for(
int id=0;
id<(
stereo_?2:1); ++id)
372 if(!images[
id].empty())
374 if(images[
id].type() == CV_16UC1)
377 cv::minMaxLoc(images[
id], &min, &max);
378 UDEBUG(
"Camera IR %d: min=%f max=%f",
id, min, max);
388 depthDetected =
true;
391 viewGray = cv::Mat(images[
id].rows, images[
id].cols, CV_8UC1);
392 for(
int i=0; i<images[id].rows; ++i)
394 for(
int j=0; j<images[id].cols; ++j)
396 viewGray.at<
unsigned char>(i, j) = (
unsigned char)
std::min(
float(
std::max(images[
id].at<unsigned short>(i,j) -
minIrs_[
id], 0)) * factor, 255.0
f);
399 cvtColor(viewGray, images[
id], cv::COLOR_GRAY2BGR);
401 else if(images[
id].channels() == 3)
403 cvtColor(images[
id], viewGray, cv::COLOR_BGR2GRAY);
407 viewGray = images[id];
408 cvtColor(viewGray, images[
id], cv::COLOR_GRAY2BGR);
413 UERROR(
"Image %d is empty!! Should not!",
id);
420 if(!
ui_->pushButton_save->isEnabled())
422 cv::Size boardSize(
ui_->spinBox_boardWidth->value(),
ui_->spinBox_boardHeight->value());
423 if(!viewGray.empty())
425 int flags = CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE;
427 if(!viewGray.empty())
429 int maxScale =
ui_->spinBox_maxScale->value();
436 cv::resize(viewGray, timg, cv::Size(),
scale,
scale, CV_INTER_CUBIC);
437 boardFound[id] = cv::findChessboardCorners(timg, boardSize, pointBuf[
id], flags);
442 cv::Mat cornersMat(pointBuf[
id]);
443 cornersMat *= 1./
scale;
454 float minSquareDistance = -1.0f;
455 for(
unsigned int i=0; i<pointBuf[id].size()-1; ++i)
457 float d = cv::norm(pointBuf[
id][i] - pointBuf[
id][i+1]);
458 if(minSquareDistance == -1.0
f || minSquareDistance > d)
460 minSquareDistance = d;
463 float radius = minSquareDistance/2.0f +0.5f;
464 cv::cornerSubPix( viewGray, pointBuf[
id], cv::Size(radius, radius), cv::Size(-1,-1),
465 cv::TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1 ));
468 cv::drawChessboardCorners(images[
id], boardSize, cv::Mat(pointBuf[
id]), boardFound[
id]);
470 std::vector<float>
params(4,0);
471 getParams(pointBuf[
id], boardSize,
imageSize_[
id], params[0], params[1], params[2], params[3]);
473 bool addSample =
true;
486 boardAccepted[id] =
true;
491 UINFO(
"[%d] Added board, total=%d. (x=%f, y=%f, size=%f, skew=%f)",
id, (
int)
imagePoints_[
id].size(), params[0], params[1], params[2], params[3]);
495 std::vector<float> xRange(2,
imageParams_[
id][0].at(0));
496 std::vector<float> yRange(2,
imageParams_[
id][0].at(1));
497 std::vector<float> sizeRange(2,
imageParams_[
id][0].at(2));
498 std::vector<float> skewRange(2,
imageParams_[
id][0].at(3));
517 float xGood = xRange[1] - xRange[0];
518 float yGood = yRange[1] - yRange[0];
519 float sizeGood = sizeRange[1] - sizeRange[0];
520 float skewGood = skewRange[1] - skewRange[0];
524 ui_->progressBar_x->setValue(xGood*100);
525 ui_->progressBar_y->setValue(yGood*100);
526 ui_->progressBar_size->setValue(sizeGood*100);
527 ui_->progressBar_skew->setValue(skewGood*100);
536 ui_->progressBar_x_2->setValue(xGood*100);
537 ui_->progressBar_y_2->setValue(yGood*100);
538 ui_->progressBar_size_2->setValue(sizeGood*100);
539 ui_->progressBar_skew_2->setValue(skewGood*100);
551 (sizeGood > 0.4 || (
ui_->checkBox_fisheye->isChecked() && sizeGood > 0.25)) &&
554 readyToCalibrate[id] =
true;
558 if(inputRawImages[
id].type() == CV_16UC1)
563 for(
size_t i = 0; i < pointBuf[id].size(); ++i)
565 const cv::Point2f &p = pointBuf[id][i];
568 roi.width =
std::min(roi.width, inputRawImages[
id].cols - roi.x);
569 roi.height =
std::min(roi.height, inputRawImages[
id].rows - roi.y);
573 cv::minMaxLoc(inputRawImages[
id](roi), &min, &max);
587 ui_->label_baseline->setVisible(!depthDetected);
588 ui_->label_baseline_name->setVisible(!depthDetected);
590 if(
stereo_ && ((boardAccepted[0] && boardFound[1]) || (boardAccepted[1] && boardFound[0])))
597 if(!
stereo_ && readyToCalibrate[0])
606 if(
ui_->radioButton_rectified->isChecked())
608 if(
models_[0].isValidForRectification())
610 images[0] =
models_[0].rectifyImage(images[0]);
612 if(
models_[1].isValidForRectification())
614 images[1] =
models_[1].rectifyImage(images[1]);
617 else if(
ui_->radioButton_stereoRectified->isChecked() &&
626 if(
ui_->checkBox_showHorizontalLines->isChecked())
628 for(
int id=0;
id<(
stereo_?2:1); ++id)
633 cv::line(images[
id], cv::Point(0, i), cv::Point(
imageSize_[
id].width, i), CV_RGB(0,255,0));
638 ui_->label_left->setText(tr(
"%1x%2").arg(images[0].cols).arg(images[0].rows));
641 ui_->image_view->setImage(
uCvMat2QImage(images[0]).mirrored(
ui_->checkBox_mirror->isChecked(),
false));
644 ui_->label_right->setText(tr(
"%1x%2").arg(images[1].cols).arg(images[1].rows));
645 ui_->image_view_2->setImage(
uCvMat2QImage(images[1]).mirrored(
ui_->checkBox_mirror->isChecked(),
false));
668 ui_->pushButton_calibrate->setEnabled(
ui_->checkBox_unlock->isChecked());
669 ui_->pushButton_save->setEnabled(
false);
670 ui_->radioButton_raw->setChecked(
true);
671 ui_->radioButton_rectified->setEnabled(
false);
672 ui_->radioButton_stereoRectified->setEnabled(
false);
674 ui_->progressBar_count->reset();
676 ui_->progressBar_x->reset();
677 ui_->progressBar_y->reset();
678 ui_->progressBar_size->reset();
679 ui_->progressBar_skew->reset();
681 ui_->progressBar_count_2->reset();
683 ui_->progressBar_x_2->reset();
684 ui_->progressBar_y_2->reset();
685 ui_->progressBar_size_2->reset();
686 ui_->progressBar_skew_2->reset();
688 ui_->label_serial->clear();
689 ui_->label_fx->setNum(0);
690 ui_->label_fy->setNum(0);
691 ui_->label_cx->setNum(0);
692 ui_->label_cy->setNum(0);
693 ui_->label_baseline->setNum(0);
694 ui_->label_error->setNum(0);
695 ui_->lineEdit_K->clear();
696 ui_->lineEdit_D->clear();
697 ui_->lineEdit_R->clear();
698 ui_->lineEdit_P->clear();
699 ui_->label_fx_2->setNum(0);
700 ui_->label_fy_2->setNum(0);
701 ui_->label_cx_2->setNum(0);
702 ui_->label_cy_2->setNum(0);
703 ui_->lineEdit_K_2->clear();
704 ui_->lineEdit_D_2->clear();
705 ui_->lineEdit_R_2->clear();
706 ui_->lineEdit_P_2->clear();
711 ui_->pushButton_calibrate->setEnabled(
true);
719 QMessageBox mb(QMessageBox::Information,
720 tr(
"Calibrating..."),
721 tr(
"Operation in progress..."));
723 QApplication::processEvents();
725 QApplication::processEvents();
727 std::vector<std::vector<cv::Point3f> > objectPoints(1);
728 cv::Size boardSize(
ui_->spinBox_boardWidth->value(),
ui_->spinBox_boardHeight->value());
731 for(
int i = 0; i < boardSize.height; ++i )
732 for(
int j = 0; j < boardSize.width; ++j )
733 objectPoints[0].push_back(cv::Point3f(
float( j*squareSize ),
float( i*squareSize ), 0));
735 for(
int id=0;
id<(
stereo_?2:1); ++id)
739 objectPoints.resize(
imagePoints_[
id].size(), objectPoints[0]);
742 std::vector<cv::Mat> rvecs, tvecs;
743 std::vector<float> reprojErrs;
745 K = cv::Mat::eye(3,3,CV_64FC1);
749 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 750 bool fishEye =
ui_->checkBox_fisheye->isChecked();
763 cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC |
764 cv::fisheye::CALIB_CHECK_COND |
765 cv::fisheye::CALIB_FIX_SKEW);
767 catch(
const cv::Exception &
e)
769 UERROR(
"Error: %s (try restarting the calibration)", e.what());
770 QMessageBox::warning(
this, tr(
"Calibration failed!"), tr(
"Error: %1 (try restarting the calibration)").arg(e.what()));
778 rms = cv::calibrateCamera(objectPoints,
787 UINFO(
"Re-projection error reported by calibrateCamera: %f", rms);
790 std::vector<cv::Point2f> imagePoints2;
791 int i, totalPoints = 0;
792 double totalErr = 0, err;
793 reprojErrs.resize(objectPoints.size());
795 for( i = 0; i < (int)objectPoints.size(); ++i )
797 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 800 cv::fisheye::projectPoints( cv::Mat(objectPoints[i]), imagePoints2, rvecs[i], tvecs[i], K, D);
805 cv::projectPoints( cv::Mat(objectPoints[i]), rvecs[i], tvecs[i], K, D, imagePoints2);
807 err = cv::norm(cv::Mat(
imagePoints_[
id][i]), cv::Mat(imagePoints2), CV_L2);
809 int n = (int)objectPoints[i].size();
810 reprojErrs[i] = (float)
std::sqrt(err*err/n);
815 double totalAvgErr =
std::sqrt(totalErr/totalPoints);
817 UINFO(
"avg re projection error = %f", totalAvgErr);
819 cv::Mat
P(3,4,CV_64FC1);
820 P.at<
double>(2,3) = 1;
821 K.copyTo(P.colRange(0,3).rowRange(0,3));
823 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 827 cv::Mat newD = cv::Mat::zeros(1,6,CV_64FC1);
828 newD.at<
double>(0,0) = D.at<
double>(0,0);
829 newD.at<
double>(0,1) = D.at<
double>(0,1);
830 newD.at<
double>(0,4) = D.at<
double>(0,2);
831 newD.at<
double>(0,5) = D.at<
double>(0,3);
836 std::cout <<
"K = " << K << std::endl;
837 std::cout <<
"D = " << D << std::endl;
838 std::cout <<
"width = " <<
imageSize_[id].width << std::endl;
839 std::cout <<
"height = " <<
imageSize_[id].height << std::endl;
849 ui_->label_error->setNum(totalAvgErr);
851 std::stringstream strK, strD, strR, strP;
856 ui_->lineEdit_K->setText(strK.str().c_str());
857 ui_->lineEdit_D->setText(strD.str().c_str());
858 ui_->lineEdit_R->setText(strR.str().c_str());
859 ui_->lineEdit_P->setText(strP.str().c_str());
867 ui_->label_error_2->setNum(totalAvgErr);
869 std::stringstream strK, strD, strR, strP;
874 ui_->lineEdit_K_2->setText(strK.str().c_str());
875 ui_->lineEdit_D_2->setText(strD.str().c_str());
876 ui_->lineEdit_R_2->setText(strR.str().c_str());
877 ui_->lineEdit_P_2->setText(strP.str().c_str());
886 ui_->doubleSpinBox_stereoBaseline->value() > 0 &&
889 UWARN(
"Expected stereo baseline is set to %f m, but computed baseline is %f m. Rescaling baseline...",
892 P.at<
double>(0,3) = -P.at<
double>(0,0)*
ui_->doubleSpinBox_stereoBaseline->value();
894 UWARN(
"Scale %f (setting square size from %f to %f)", scale,
ui_->doubleSpinBox_squareSize->value(),
ui_->doubleSpinBox_squareSize->value()*
scale);
895 ui_->doubleSpinBox_squareSize->setValue(
ui_->doubleSpinBox_squareSize->value()*
scale);
903 std::stringstream strR1, strP1, strR2, strP2;
908 ui_->lineEdit_R->setText(strR1.str().c_str());
909 ui_->lineEdit_P->setText(strP1.str().c_str());
910 ui_->lineEdit_R_2->setText(strR2.str().c_str());
911 ui_->lineEdit_P_2->setText(strP2.str().c_str());
920 QMessageBox::warning(
this, tr(
"Stereo Calibration"),
921 tr(
"\"fx\" after stereo rectification (%1) is not close from original " 922 "calibration (%2), the difference would have to be under 5. You may " 923 "restart the calibration or keep it as is.")
931 if(
models_[0].isValidForRectification())
933 models_[0].initRectificationMap();
935 if(
models_[1].isValidForRectification())
937 models_[1].initRectificationMap();
939 if(
models_[0].isValidForRectification() ||
models_[1].isValidForRectification())
941 ui_->radioButton_rectified->setEnabled(
true);
946 ui_->radioButton_stereoRectified->setEnabled(
true);
947 ui_->radioButton_stereoRectified->setChecked(
true);
948 ui_->pushButton_save->setEnabled(
true);
952 ui_->radioButton_rectified->setChecked(
ui_->radioButton_rectified->isEnabled());
955 else if(
models_[0].isValidForRectification())
957 models_[0].initRectificationMap();
958 ui_->radioButton_rectified->setEnabled(
true);
959 ui_->radioButton_rectified->setChecked(
true);
960 ui_->pushButton_save->setEnabled(
true);
963 UINFO(
"End calibration");
972 UERROR(
"No stereo correspondences!");
977 if (left.
K_raw().empty() || left.
D_raw().empty())
979 UERROR(
"Empty intrinsic parameters (K, D) for the %s camera! Aborting stereo calibration...",
leftSuffix_.toStdString().c_str());
982 if (right.
K_raw().empty() || right.
D_raw().empty())
984 UERROR(
"Empty intrinsic parameters (K, D) for the %s camera! Aborting stereo calibration...",
rightSuffix_.toStdString().c_str());
990 UERROR(
"left model (%dx%d) has not the same size as the processed images (%dx%d)",
997 UERROR(
"right model (%dx%d) has not the same size as the processed images (%dx%d)",
1006 cv::Size boardSize(
ui_->spinBox_boardWidth->value(),
ui_->spinBox_boardHeight->value());
1010 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 1011 bool fishEye = left.
D_raw().cols == 6;
1016 std::vector<std::vector<cv::Point3d> > objectPoints(1);
1017 for (
int i = 0; i < boardSize.height; ++i)
1018 for (
int j = 0; j < boardSize.width; ++j)
1019 objectPoints[0].push_back(cv::Point3d(
double(j*squareSize),
double(i*squareSize), 0));
1023 cv::Vec4d D_left(left.
D_raw().at<
double>(0,0), left.
D_raw().at<
double>(0,1), left.
D_raw().at<
double>(0,4), left.
D_raw().at<
double>(0,5));
1024 cv::Vec4d D_right(right.
D_raw().at<
double>(0,0), right.
D_raw().at<
double>(0,1), right.
D_raw().at<
double>(0,4), right.
D_raw().at<
double>(0,5));
1045 rms = cv::fisheye::stereoCalibrate(
1049 left.
K_raw(), D_left, right.
K_raw(), D_right,
1051 cv::fisheye::CALIB_FIX_INTRINSIC,
1052 cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 100, 1
e-5));
1053 UINFO(
"stereo calibration... done with RMS error=%f", rms);
1055 catch(
const cv::Exception &
e)
1057 UERROR(
"Error: %s (try restarting the calibration)", e.what());
1061 std::cout <<
"R = " << R << std::endl;
1062 std::cout <<
"T = " << Tvec << std::endl;
1066 UINFO(
"Compute stereo rectification");
1068 cv::Mat R1, R2, P1, P2, Q;
1070 left.
K_raw(), D_left,
1071 right.
K_raw(), D_right,
1072 imageSize, R, Tvec, R1, R2, P1, P2, Q,
1073 cv::CALIB_ZERO_DISPARITY, 0, imageSize);
1083 std::cout <<
"R1 = " << R1 << std::endl;
1084 std::cout <<
"R2 = " << R2 << std::endl;
1085 std::cout <<
"P1 = " << P1 << std::endl;
1086 std::cout <<
"P2 = " << P2 << std::endl;
1089 if(P1.at<
double>(0,0) < 0)
1091 P1.at<
double>(0,0) *= -1;
1092 P1.at<
double>(1,1) *= -1;
1094 if(P2.at<
double>(0,0) < 0)
1096 P2.at<
double>(0,0) *= -1;
1097 P2.at<
double>(1,1) *= -1;
1099 if(P2.at<
double>(0,3) > 0)
1101 P2.at<
double>(0,3) *= -1;
1103 P2.at<
double>(0,3) = P2.at<
double>(0,3) * left.
K_raw().at<
double>(0,0) / P2.at<
double>(0,0);
1104 P1.at<
double>(0,0) = P1.at<
double>(1,1) = left.
K_raw().at<
double>(0,0);
1105 P2.at<
double>(0,0) = P2.at<
double>(1,1) = left.
K_raw().at<
double>(0,0);
1107 std::cout <<
"P1n = " << P1 << std::endl;
1108 std::cout <<
"P2n = " << P2 << std::endl;
1111 cv::Mat T(3,1,CV_64FC1);
1112 T.at <
double>(0,0) = Tvec[0];
1113 T.at <
double>(1,0) = Tvec[1];
1114 T.at <
double>(2,0) = Tvec[2];
1136 std::vector<std::vector<cv::Point3f> > objectPoints(1);
1137 for (
int i = 0; i < boardSize.height; ++i)
1138 for (
int j = 0; j < boardSize.width; ++j)
1139 objectPoints[0].push_back(cv::Point3f(
float(j*squareSize),
float(i*squareSize), 0));
1142 #if CV_MAJOR_VERSION < 3 1143 rms = cv::stereoCalibrate(
1149 imageSize, R, T, E, F,
1150 cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 100, 1
e-5),
1151 cv::CALIB_FIX_INTRINSIC);
1153 rms = cv::stereoCalibrate(
1159 imageSize, R, T, E, F,
1160 cv::CALIB_FIX_INTRINSIC,
1161 cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 100, 1
e-5));
1163 UINFO(
"stereo calibration... done with RMS error=%f", rms);
1165 std::cout <<
"R = " << R << std::endl;
1166 std::cout <<
"T = " << T << std::endl;
1167 std::cout <<
"E = " << E << std::endl;
1168 std::cout <<
"F = " << F << std::endl;
1172 UINFO(
"Compute stereo rectification");
1174 cv::Mat R1, R2, P1, P2, Q;
1175 cv::stereoRectify(left.
K_raw(), left.
D_raw(),
1177 imageSize, R, T, R1, R2, P1, P2, Q,
1178 cv::CALIB_ZERO_DISPARITY, 0, imageSize);
1180 std::cout <<
"R1 = " << R1 << std::endl;
1181 std::cout <<
"P1 = " << P1 << std::endl;
1182 std::cout <<
"R2 = " << R2 << std::endl;
1183 std::cout <<
"P2 = " << P2 << std::endl;
1187 std::vector<cv::Vec3f> lines[2];
1188 UINFO(
"Computing avg re-projection error...");
1195 cv::undistortPoints(imgpt0, imgpt0, left.
K_raw(), left.
D_raw(), R1, P1);
1196 cv::undistortPoints(imgpt1, imgpt1, right.
K_raw(), right.
D_raw(), R2, P2);
1197 computeCorrespondEpilines(imgpt0, 1, F, lines[0]);
1198 computeCorrespondEpilines(imgpt1, 2, F, lines[1]);
1200 for(
int j = 0; j < npt; j++ )
1210 double totalAvgErr = err/(double)npoints;
1211 UINFO(
"stereo avg re projection error = %f", totalAvgErr);
1240 QString cameraName =
models_[0].name().c_str();
1241 QString filePath = QFileDialog::getSaveFileName(
this, tr(
"Export"),
savingDirectory_+
"/"+cameraName+
".yaml",
"*.yaml");
1243 if(!filePath.isEmpty())
1245 QString
name = QFileInfo(filePath).baseName();
1246 QString dir = QFileInfo(filePath).absoluteDir().absolutePath();
1247 models_[0].setName(name.toStdString());
1250 QMessageBox::information(
this, tr(
"Export"), tr(
"Calibration file saved to \"%1\".").arg(filePath));
1251 UINFO(
"Saved \"%s\"!", filePath.toStdString().c_str());
1257 UERROR(
"Error saving \"%s\"", filePath.toStdString().c_str());
1266 QString filePath = QFileDialog::getSaveFileName(
this, tr(
"Export"),
savingDirectory_ +
"/" + cameraName,
"*.yaml");
1267 QString
name = QFileInfo(filePath).baseName();
1268 QString dir = QFileInfo(filePath).absoluteDir().absolutePath();
1271 bool switched =
ui_->checkBox_switchImages->isChecked();
1273 std::string base = (dir+QDir::separator()+name).toStdString();
1276 std::string posePath = base+
"_pose.yaml";
1279 QMessageBox::information(
this, tr(
"Export"), tr(
"Calibration files saved:\n \"%1\"\n \"%2\"\n \"%3\".").
1280 arg(leftPath.c_str()).arg(rightPath.c_str()).arg(posePath.c_str()));
1281 UINFO(
"Saved \"%s\" and \"%s\"!", leftPath.c_str(), rightPath.c_str());
1287 UERROR(
"Error saving \"%s\" and \"%s\"", leftPath.c_str(), rightPath.c_str());
1301 cv::Point2f up_left = corners[0];
1302 cv::Point2f up_right = corners[boardSize.width-1];
1303 cv::Point2f down_right = corners[corners.size()-1];
1304 cv::Point2f down_left = corners[corners.size()-boardSize.width];
1305 cv::Point2f a = up_right - up_left;
1306 cv::Point2f b = down_right - up_right;
1307 cv::Point2f c = down_left - down_right;
1308 cv::Point2f p = b + c;
1309 cv::Point2f
q = a + b;
1310 return std::fabs(p.x*q.y - p.y*q.x) / 2.0f;
1319 cv::Point2f up_left = corners[0];
1320 cv::Point2f up_right = corners[boardSize.width-1];
1321 cv::Point2f down_right = corners[corners.size()-1];
1325 cv::Point2f ab = up_left - up_right;
1326 cv::Point2f cb = down_right - up_right;
1327 float angle =
std::acos(ab.dot(cb) / (cv::norm(ab) * cv::norm(cb)));
1329 float r = 2.0f * std::fabs((CV_PI / 2.0
f) - angle);
1330 return r > 1.0f?1.0f:r;
1338 float & x,
float & y,
float & size,
float & skew)
1340 float area =
getArea(corners, boardSize);
1341 size =
std::sqrt(area / (imageSize.width * imageSize.height));
1342 skew =
getSkew(corners, boardSize);
1345 for(
unsigned int i=0; i<corners.size(); ++i)
1347 meanX += corners[i].x;
1348 meanY += corners[i].y;
1350 meanX /= corners.size();
1351 meanY /= corners.size();
1352 x = meanX / imageSize.width;
1353 y = meanY / imageSize.height;
bool save(const std::string &directory, bool ignoreStereoTransform=true) const
void processImages(const cv::Mat &imageLeft, const cv::Mat &imageRight, const QString &cameraName)
bool isValidForProjection() const
const cv::Size & imageSize() const
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
void setBoardWidth(int width)
StereoCameraModel stereoCalibration(const CameraModel &left, const CameraModel &right, bool ignoreStereoRectification) const
void saveSettings(QSettings &settings, const QString &group="") const
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
std::vector< std::vector< std::vector< cv::Point2f > > > stereoImagePoints_
void loadSettings(QSettings &settings, const QString &group="")
const cv::Mat & depthOrRightRaw() const
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack, float depthMin=0, float depthMax=0)
GLM_FUNC_DECL genType e()
std::vector< unsigned short > minIrs_
double squareSize() const
void setSquareSize(double size)
GLM_FUNC_DECL T angle(detail::tquat< T, P > const &x)
std::vector< unsigned short > maxIrs_
void setSwitchedImages(bool switched)
virtual ~CalibrationDialog()
bool isValidForRectification() const
const cv::Mat & T() const
GLM_FUNC_DECL genType step(genType const &edge, genType const &x)
void initRectificationMap()
void setBoardHeight(int height)
const std::string & name() const
rtabmap::StereoCameraModel stereoModel_
#define UASSERT(condition)
const cv::Mat & F() const
virtual void closeEvent(QCloseEvent *event)
std::vector< std::vector< std::vector< cv::Point2f > > > imagePoints_
void getParams(const std::vector< cv::Point2f > &corners, const cv::Size &boardSize, const cv::Size &imageSize, float &x, float &y, float &size, float &skew)
bool isValidForRectification() const
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
virtual std::string getClassName() const =0
const cv::Mat & imageRaw() const
const std::string & getLeftSuffix() const
void stereoRectifyFisheye(cv::InputArray _cameraMatrix1, cv::InputArray _distCoeffs1, cv::InputArray _cameraMatrix2, cv::InputArray _distCoeffs2, cv::Size imageSize, cv::InputArray _Rmat, cv::InputArray _Tmat, cv::OutputArray _Rmat1, cv::OutputArray _Rmat2, cv::OutputArray _Pmat1, cv::OutputArray _Pmat2, cv::OutputArray _Qmat, int flags, double alpha, cv::Size newImageSize)
std::vector< rtabmap::CameraModel > models_
DiscreteDepthDistortionModel RTABMAP_EXP calibrate(const std::map< int, rtabmap::SensorData > &sequence, const std::map< int, rtabmap::Transform > &trajectory, const pcl::PointCloud< pcl::PointXYZ >::Ptr &map, double coneRadius=0.02, double coneStdevThresh=0.03)
const cv::Mat & R() const
void uSleep(unsigned int ms)
CalibrationDialog(bool stereo=false, const QString &savingDirectory=".", bool switchImages=false, QWidget *parent=0)
const Transform & localTransform() const
const std::string & getRightSuffix() const
void setStereoMode(bool stereo, const QString &leftSuffix="left", const QString &rightSuffix="right")
void setProgressVisibility(bool visible)
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
cv::Mat rectifyImage(const cv::Mat &raw, int interpolation=cv::INTER_LINEAR) const
void setMaxScale(int scale)
ULogger class and convenient macros.
GLM_FUNC_DECL genType acos(genType const &x)
void setName(const std::string &name, const std::string &leftSuffix="left", const std::string &rightSuffix="right")
std::vector< cv::Size > imageSize_
float getArea(const std::vector< cv::Point2f > &corners, const cv::Size &boardSize)
const cv::Mat & E() const
std::vector< std::vector< std::vector< float > > > imageParams_
Ui_calibrationDialog * ui_
virtual bool handleEvent(UEvent *event)
void unregisterFromEventsManager()
GLM_FUNC_DECL genType::value_type length(genType const &x)
void setExpectedStereoBaseline(double length)
void setCameraName(const QString &name)
float getSkew(const std::vector< cv::Point2f > &corners, const cv::Size &boardSize)
const std::string & cameraName() const
const CameraModel & right() const
void setFisheyeImages(bool enabled)
const SensorData & data() const
const CameraModel & left() const