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);
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();
233 data.uncompressDataConst(0, &depth);
234 if(
data.cameraModels().size() == 1 &&
data.cameraModels()[0].isValidForProjection() && !depth.empty())
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);
250 else if(
data.cameraModels().size() > 1)
252 QMessageBox::warning(
this, tr(
"Depth Calibration"),tr(
"Multi-camera not supported!"));
255 else if(
data.cameraModels().size() != 1)
257 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"Camera model not found."));
260 else if(
data.cameraModels().size() == 1 && !
data.cameraModels()[0].isValidForProjection())
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))
317 data.uncompressData(0, &depth,
_ui->checkBox_laserScan->isChecked()?&laserScan:0);
318 if(
data.cameraModels().size() == 1 &&
data.cameraModels()[0].isValidForProjection() && !depth.empty())
321 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
323 if(
_ui->checkBox_laserScan->isChecked())
326 indices->resize(cloud->size());
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();
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.")
368 QMessageBox::warning(
this, tr(
"Depth Calibration"),
msg);
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();
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()));
447 Transform baseToCamera =
iter->second.cameraModels()[0].localTransform();
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->setContentsMargins(0,0,0,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);
513 ster->second.uncompressDataConst(0, &depthImage);
515 if(ster->second.cameraModels().size() == 1 && ster->second.cameraModels()[0].isValidForProjection() && !depthImage.empty())
519 if(
model.imageWidth() != depthImage.cols)
522 model =
model.scaled(
double(depthImage.rows) /
double(
model.imageHeight()));
527 iter->second.inverse(),
529 _ui->doubleSpinBox_coneRadius->value(),
530 _ui->doubleSpinBox_coneStdDevThresh->value());
543 QApplication::processEvents();
547 QApplication::processEvents();
556 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"The resulting map is empty!"));