29 #include "ui_depthCalibrationDialog.h" 44 #include <QPushButton> 48 #include <QtGui/QDesktopServices> 49 #include <QMessageBox> 50 #include <QFileDialog> 59 _ui =
new Ui_DepthCalibrationDialog();
62 connect(
_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()),
this, SLOT(
restoreDefaults()));
63 connect(
_ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()),
this, SLOT(
saveModel()));
64 connect(
_ui->buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
this, SLOT(accept()));
65 _ui->buttonBox->button(QDialogButtonBox::Ok)->setText(
"Calibrate");
69 connect(
_ui->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SIGNAL(
configChanged()));
70 connect(
_ui->doubleSpinBox_maxDepth, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
71 connect(
_ui->doubleSpinBox_minDepth, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
72 connect(
_ui->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
73 connect(
_ui->doubleSpinBox_coneRadius, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
74 connect(
_ui->doubleSpinBox_coneStdDevThresh, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
75 connect(
_ui->checkBox_laserScan, SIGNAL(stateChanged(
int)),
this, SIGNAL(
configChanged()));
77 connect(
_ui->spinBox_bin_width, SIGNAL(valueChanged(
int)),
this, SIGNAL(
configChanged()));
78 connect(
_ui->spinBox_bin_height, SIGNAL(valueChanged(
int)),
this, SIGNAL(
configChanged()));
79 connect(
_ui->doubleSpinBox_bin_depth, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
80 connect(
_ui->spinBox_smoothing, SIGNAL(valueChanged(
int)),
this, SIGNAL(
configChanged()));
81 connect(
_ui->doubleSpinBox_maxDepthModel, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
83 _ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
104 settings.beginGroup(group);
107 settings.setValue(
"decimation",
_ui->spinBox_decimation->value());
108 settings.setValue(
"max_depth",
_ui->doubleSpinBox_maxDepth->value());
109 settings.setValue(
"min_depth",
_ui->doubleSpinBox_minDepth->value());
110 settings.setValue(
"voxel",
_ui->doubleSpinBox_voxelSize->value());
111 settings.setValue(
"cone_radius",
_ui->doubleSpinBox_coneRadius->value());
112 settings.setValue(
"cone_stddev_thresh",
_ui->doubleSpinBox_coneStdDevThresh->value());
113 settings.setValue(
"laser_scan",
_ui->checkBox_laserScan->isChecked());
115 settings.setValue(
"bin_width",
_ui->spinBox_bin_width->value());
116 settings.setValue(
"bin_height",
_ui->spinBox_bin_height->value());
117 settings.setValue(
"bin_depth",
_ui->doubleSpinBox_bin_depth->value());
118 settings.setValue(
"smoothing",
_ui->spinBox_smoothing->value());
119 settings.setValue(
"max_model_depth",
_ui->doubleSpinBox_maxDepthModel->value());
131 settings.beginGroup(group);
134 _ui->spinBox_decimation->setValue(settings.value(
"decimation",
_ui->spinBox_decimation->value()).toInt());
135 _ui->doubleSpinBox_maxDepth->setValue(settings.value(
"max_depth",
_ui->doubleSpinBox_maxDepth->value()).toDouble());
136 _ui->doubleSpinBox_minDepth->setValue(settings.value(
"min_depth",
_ui->doubleSpinBox_minDepth->value()).toDouble());
137 _ui->doubleSpinBox_voxelSize->setValue(settings.value(
"voxel",
_ui->doubleSpinBox_voxelSize->value()).toDouble());
138 _ui->doubleSpinBox_coneRadius->setValue(settings.value(
"cone_radius",
_ui->doubleSpinBox_coneRadius->value()).toDouble());
139 _ui->doubleSpinBox_coneStdDevThresh->setValue(settings.value(
"cone_stddev_thresh",
_ui->doubleSpinBox_coneStdDevThresh->value()).toDouble());
140 _ui->checkBox_laserScan->setChecked(settings.value(
"laser_scan",
_ui->checkBox_laserScan->isChecked()).toBool());
142 _ui->spinBox_bin_width->setValue(settings.value(
"bin_width",
_ui->spinBox_bin_width->value()).toInt());
143 _ui->spinBox_bin_height->setValue(settings.value(
"bin_height",
_ui->spinBox_bin_height->value()).toInt());
144 _ui->doubleSpinBox_bin_depth->setValue(settings.value(
"bin_depth",
_ui->doubleSpinBox_bin_depth->value()).toDouble());
145 _ui->spinBox_smoothing->setValue(settings.value(
"smoothing",
_ui->spinBox_smoothing->value()).toInt());
146 _ui->doubleSpinBox_maxDepthModel->setValue(settings.value(
"max_model_depth",
_ui->doubleSpinBox_maxDepthModel->value()).toDouble());
156 _ui->spinBox_decimation->setValue(1);
157 _ui->doubleSpinBox_maxDepth->setValue(3.5);
158 _ui->doubleSpinBox_minDepth->setValue(0);
159 _ui->doubleSpinBox_voxelSize->setValue(0.01);
160 _ui->doubleSpinBox_coneRadius->setValue(0.02);
161 _ui->doubleSpinBox_coneStdDevThresh->setValue(0.1);
162 _ui->checkBox_laserScan->setChecked(
false);
163 _ui->checkBox_resetModel->setChecked(
true);
165 _ui->spinBox_bin_width->setValue(8);
166 _ui->spinBox_bin_height->setValue(6);
169 size_t bin_width, bin_height;
171 _ui->spinBox_bin_width->setValue(bin_width);
172 _ui->spinBox_bin_height->setValue(bin_height);
174 _ui->doubleSpinBox_bin_depth->setValue(2.0),
175 _ui->spinBox_smoothing->setValue(1);
176 _ui->doubleSpinBox_maxDepthModel->setValue(10.0);
183 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save distortion model to ..."),
_workingDirectory+QDir::separator()+
"distortion_model.bin", tr(
"Distortion model (*.bin *.txt)"));
194 QString
name = QString(path).replace(
".bin",
".png", Qt::CaseInsensitive).replace(
".txt",
".png", Qt::CaseInsensitive);
195 cv::imwrite(name.toStdString(), results);
196 QDesktopServices::openUrl(QUrl::fromLocalFile(name));
199 QMessageBox::information(
this, tr(
"Depth Calibration"), tr(
"Distortion model saved to \"%1\"!").arg(path));
211 const std::map<int, Transform> & poses,
212 const QMap<int, Signature> & cachedSignatures,
213 const QString & workingDirectory,
224 _ui->label_width->setText(
"NA");
225 _ui->label_height->setText(
"NA");
228 if(cachedSignatures.size())
230 const Signature & s = cachedSignatures.begin().value();
241 if(
_imageSize.width %
_ui->spinBox_bin_width->value() != 0 ||
244 size_t bin_width, bin_height;
246 _ui->spinBox_bin_width->setValue(bin_width);
247 _ui->spinBox_bin_height->setValue(bin_height);
252 QMessageBox::warning(
this, tr(
"Depth Calibration"),tr(
"Multi-camera not supported!"));
257 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"Camera model not found."));
262 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"Camera model %1 not valid for projection.").arg(s.
id()));
267 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"Depth image cannot be found in the cache, make sure to update cache before doing calibration."));
273 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"No signatures detected! Map is empty!?"));
277 if(this->exec() == QDialog::Accepted)
279 if(
_model &&
_ui->checkBox_resetModel->isChecked())
285 if(
_ui->doubleSpinBox_maxDepthModel->value() <
_ui->doubleSpinBox_bin_depth->value())
287 QMessageBox::warning(
this, tr(
"Wrong parameter"), tr(
"Maximum model depth should be higher than bin depth, setting to bin depth x5."));
288 _ui->doubleSpinBox_maxDepthModel->setValue(
_ui->doubleSpinBox_bin_depth->value() * 5.0);
292 if(
_ui->doubleSpinBox_voxelSize->value() > 0.0)
299 std::map<int, rtabmap::SensorData> sequence;
302 pcl::PointCloud<pcl::PointXYZ>::Ptr map(
new pcl::PointCloud<pcl::PointXYZ>);
304 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end() && !
_canceled; ++iter, ++index)
307 if(!iter->second.isNull())
309 pcl::IndicesPtr indices(
new std::vector<int>);
310 if(cachedSignatures.contains(iter->first))
312 const Signature & s = cachedSignatures.find(iter->first).value();
317 data.
uncompressData(0, &depth,
_ui->checkBox_laserScan->isChecked()?&laserScan:0);
321 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
323 if(
_ui->checkBox_laserScan->isChecked())
326 indices->resize(cloud->size());
327 for(
unsigned int i=0; i<indices->size(); ++i)
336 _ui->spinBox_decimation->value(),
337 _ui->doubleSpinBox_maxDepth->value(),
338 _ui->doubleSpinBox_minDepth->value(),
345 if(
_ui->doubleSpinBox_voxelSize->value() > 0.0)
352 points+=cloud->size();
356 sequence.insert(std::make_pair(iter->first, data));
358 cv::Size size = depth.size();
363 QString msg = tr(
"Depth images (%1x%2) in the map don't have the " 364 "same size then in the current model (%3x%4). You may want " 365 "to check \"Reset previous model\" before trying again.")
366 .arg(size.width).arg(size.height)
368 QMessageBox::warning(
this, tr(
"Depth Calibration"), msg);
377 _progressDialog->
appendText(tr(
"Not suitable camera model found for node %1, ignoring this node!").arg(iter->first), Qt::darkYellow);
383 UERROR(
"Cloud %d not found in cache!", iter->first);
388 UERROR(
"transform is null!?");
394 .arg(iter->first).arg(points).arg(index).arg(poses.size()));
401 QApplication::processEvents();
404 if(!
_canceled && map->size() && sequence.size())
406 if(
_ui->doubleSpinBox_voxelSize->value() > 0.0)
409 .arg(
_ui->doubleSpinBox_voxelSize->value())
411 QApplication::processEvents();
412 QApplication::processEvents();
423 QDialog * window =
new QDialog(this->parentWidget()?this->parentWidget():
this, Qt::Window);
424 window->setAttribute(Qt::WA_DeleteOnClose,
true);
425 window->setWindowTitle(tr(
"Map"));
426 window->setMinimumWidth(800);
427 window->setMinimumHeight(600);
433 QVBoxLayout *layout =
new QVBoxLayout();
434 layout->addWidget(viewer);
435 window->setLayout(layout);
436 connect(window, SIGNAL(finished(
int)), viewer, SLOT(clear()));
445 for(std::map<int, SensorData>::iterator iter=sequence.begin(); iter!=sequence.end(); ++iter)
447 Transform baseToCamera = iter->second.cameraModels()[0].localTransform();
448 viewer->
addOrUpdateFrustum(
uFormat(
"frustum%d",iter->first), poses.at(iter->first), baseToCamera, 0.2, QColor(), iter->second.cameraModels()[0].fovX(), iter->second.cameraModels()[0].fovY());
450 _progressDialog->
appendText(tr(
"Viewing the cloud (%1 points and %2 poses)... done.").arg(map->size()).arg(sequence.size()));
456 QApplication::processEvents();
457 QApplication::processEvents();
459 QDialog * dialog =
new QDialog(this->parentWidget()?this->parentWidget():
this, Qt::Window);
460 dialog->setAttribute(Qt::WA_DeleteOnClose,
true);
461 dialog->setWindowTitle(tr(
"Original/Map"));
464 imageView1->setMinimumSize(320, 240);
466 imageView2->setMinimumSize(320, 240);
467 QVBoxLayout * vlayout =
new QVBoxLayout();
468 vlayout->setMargin(0);
469 vlayout->addWidget(imageView1, 1);
470 vlayout->addWidget(imageView2, 1);
471 dialog->setLayout(vlayout);
481 size_t bin_width =
_ui->spinBox_bin_width->value();
482 size_t bin_height =
_ui->spinBox_bin_height->value();
483 if(imageSize.width %
_ui->spinBox_bin_width->value() != 0 ||
484 imageSize.height %
_ui->spinBox_bin_height->value() != 0)
486 size_t bin_width, bin_height;
488 _ui->spinBox_bin_width->setValue(bin_width);
489 _ui->spinBox_bin_height->setValue(bin_height);
496 _ui->doubleSpinBox_bin_depth->value(),
497 _ui->spinBox_smoothing->value(),
498 _ui->doubleSpinBox_maxDepthModel->value());
506 for(std::map<int, rtabmap::Transform>::const_iterator iter = poses.begin(); iter != poses.end() && !
_canceled; ++iter)
508 size_t idx = iter->first;
509 std::map<int, rtabmap::SensorData>::const_iterator ster = sequence.find(idx);
510 if(ster!=sequence.end())
513 ster->second.uncompressDataConst(0, &depthImage);
515 if(ster->second.cameraModels().size() == 1 && ster->second.cameraModels()[0].isValidForProjection() && !depthImage.empty())
518 CameraModel model = ster->second.cameraModels()[0];
522 model = model.
scaled(
double(depthImage.rows) /
double(model.imageHeight()));
527 iter->second.inverse(),
529 _ui->doubleSpinBox_coneRadius->value(),
530 _ui->doubleSpinBox_coneStdDevThresh->value());
539 _progressDialog->
appendText(tr(
"Added %1 training examples from node %2 (%3/%4).").arg(counts).arg(iter->first).arg(++index).arg(sequence.size()));
543 QApplication::processEvents();
547 QApplication::processEvents();
556 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"The resulting map is empty!"));
void setFrustumShown(bool shown)
void incrementStep(int steps=1)
cv::Mat estimateMapDepth(const pcl::PointCloud< pcl::PointXYZ >::Ptr &map, const rtabmap::Transform &transform, const cv::Mat &measurement, double coneRadius=0.02, double coneStdevThresh=0.03) const
void setAutoClose(bool on, int delayedClosingTimeSec=-1)
CameraModel scaled(double scale) const
void setCancelButtonVisible(bool visible)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP transformPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const Transform &transform)
void saveSettings(QSettings &settings, const QString &group="") const
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack, float depthMin=0, float depthMax=0)
std::map< std::string, std::string > ParametersMap
void setImage(const QImage &image)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
void loadSettings(QSettings &settings, const QString &group="")
#define UASSERT(condition)
ProgressDialog * _progressDialog
const std::vector< CameraModel > & cameraModels() const
void calibrate(const std::map< int, Transform > &poses, const QMap< int, Signature > &cachedSignatures, const QString &workingDirectory, const ParametersMap ¶meters)
Ui_DepthCalibrationDialog * _ui
static void getBinSize(const size_t &width, const size_t &height, size_t &bin_width, size_t &bin_height)
#define UASSERT_MSG(condition, msg_str)
cv::Mat visualize(const std::string &path="") const
void save(const std::string &path) const
void setMaximumSteps(int steps)
void addOrUpdateFrustum(const std::string &id, const Transform &pose, const Transform &localTransform, double scale, const QColor &color=QColor(), float fovX=1.1, float fovY=0.85)
static ULogger::Level level()
void setCameraLockZ(bool enabled=true)
bool addCloud(const std::string &id, const pcl::PCLPointCloud2Ptr &binaryCloud, const Transform &pose, bool rgb, bool hasNormals, bool hasIntensity, const QColor &color=QColor(), int viewport=1)
void uSleep(unsigned int ms)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP cloudFromSensorData(const SensorData &sensorData, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0, const ParametersMap &stereoParameters=ParametersMap(), const std::vector< float > &roiRatios=std::vector< float >())
size_t accumulate(const cv::Mat &ground_truth, const cv::Mat &measurement)
SensorData & sensorData()
ULogger class and convenient macros.
QString _workingDirectory
size_t getTrainingSamples() const
void appendText(const QString &text, const QColor &color=Qt::black)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
DepthCalibrationDialog(QWidget *parent=0)
std::string UTILITE_EXP uFormat(const char *fmt,...)
void uncompressDataConst(cv::Mat *imageRaw, cv::Mat *depthOrRightRaw, LaserScan *laserScanRaw=0, cv::Mat *userDataRaw=0, cv::Mat *groundCellsRaw=0, cv::Mat *obstacleCellsRaw=0, cv::Mat *emptyCellsRaw=0) const
virtual ~DepthCalibrationDialog()
clams::DiscreteDepthDistortionModel * _model