29 #include "ui_exportBundlerDialog.h"
34 #include <QFileDialog>
35 #include <QPushButton>
36 #include <QMessageBox>
37 #include <QTextStream>
44 _ui =
new Ui_ExportBundlerDialog();
47 connect(
_ui->toolButton_path, SIGNAL(clicked()),
this, SLOT(
getPath()));
50 connect(
_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()),
this, SLOT(
restoreDefaults()));
52 connect(
_ui->doubleSpinBox_laplacianVariance, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
53 connect(
_ui->doubleSpinBox_linearSpeed, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
54 connect(
_ui->doubleSpinBox_angularSpeed, SIGNAL(valueChanged(
double)),
this, SIGNAL(
configChanged()));
55 connect(
_ui->groupBox_export_points, SIGNAL(clicked(
bool)),
this, SIGNAL(
configChanged()));
56 connect(
_ui->sba_iterations, SIGNAL(valueChanged(
int)),
this, SIGNAL(
configChanged()));
57 connect(
_ui->comboBox_sbaType, SIGNAL(currentIndexChanged(
int)),
this, SIGNAL(
configChanged()));
58 connect(
_ui->comboBox_sbaType, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateVisibility()));
59 connect(
_ui->sba_rematchFeatures, SIGNAL(stateChanged(
int)),
this, SIGNAL(
configChanged()));
63 _ui->groupBox_export_points->setEnabled(
false);
64 _ui->groupBox_export_points->setChecked(
false);
68 _ui->comboBox_sbaType->setItemData(1, 0, Qt::UserRole - 1);
69 _ui->comboBox_sbaType->setCurrentIndex(0);
73 _ui->comboBox_sbaType->setItemData(0, 0, Qt::UserRole - 1);
74 _ui->comboBox_sbaType->setCurrentIndex(1);
77 _ui->lineEdit_path->setText(QDir::currentPath());
91 settings.beginGroup(group);
93 settings.setValue(
"maxLinearSpeed",
_ui->doubleSpinBox_linearSpeed->value());
94 settings.setValue(
"maxAngularSpeed",
_ui->doubleSpinBox_angularSpeed->value());
95 settings.setValue(
"laplacianThr",
_ui->doubleSpinBox_laplacianVariance->value());
96 settings.setValue(
"exportPoints",
_ui->groupBox_export_points->isChecked());
97 settings.setValue(
"sba_iterations",
_ui->sba_iterations->value());
98 settings.setValue(
"sba_type",
_ui->comboBox_sbaType->currentIndex());
99 settings.setValue(
"sba_variance",
_ui->sba_variance->value());
100 settings.setValue(
"sba_rematch_features",
_ui->sba_rematchFeatures->isChecked());
111 settings.beginGroup(group);
113 _ui->doubleSpinBox_linearSpeed->setValue(settings.value(
"maxLinearSpeed",
_ui->doubleSpinBox_linearSpeed->value()).toDouble());
114 _ui->doubleSpinBox_angularSpeed->setValue(settings.value(
"maxAngularSpeed",
_ui->doubleSpinBox_angularSpeed->value()).toDouble());
115 _ui->doubleSpinBox_laplacianVariance->setValue(settings.value(
"laplacianThr",
_ui->doubleSpinBox_laplacianVariance->value()).toDouble());
116 _ui->groupBox_export_points->setChecked(settings.value(
"exportPoints",
_ui->groupBox_export_points->isChecked()).toBool());
117 _ui->sba_iterations->setValue(settings.value(
"sba_iterations",
_ui->sba_iterations->value()).toInt());
118 _ui->comboBox_sbaType->setCurrentIndex((
Optimizer::Type)settings.value(
"sba_type",
_ui->comboBox_sbaType->currentIndex()).toInt());
119 _ui->sba_variance->setValue(settings.value(
"sba_variance",
_ui->sba_variance->value()).toDouble());
120 _ui->sba_rematchFeatures->setChecked(settings.value(
"sba_rematch_features",
_ui->sba_rematchFeatures->isChecked()).toBool());
129 _ui->lineEdit_path->setText((
path.isEmpty()?QDir::currentPath():
path) +
"/bundler");
134 _ui->doubleSpinBox_linearSpeed->setValue(0);
135 _ui->doubleSpinBox_angularSpeed->setValue(0);
136 _ui->doubleSpinBox_laplacianVariance->setValue(0);
137 _ui->groupBox_export_points->setChecked(
false);
138 _ui->sba_iterations->setValue(20);
141 _ui->comboBox_sbaType->setCurrentIndex(0);
145 _ui->comboBox_sbaType->setCurrentIndex(1);
148 _ui->sba_variance->setValue(1.0);
149 _ui->sba_rematchFeatures->setChecked(
true);
154 _ui->sba_variance->setVisible(
_ui->comboBox_sbaType->currentIndex() == 0);
155 _ui->label_variance->setVisible(
_ui->comboBox_sbaType->currentIndex() == 0);
160 QString
path = QFileDialog::getExistingDirectory(
this, tr(
"Exporting cameras in Bundler format..."),
_ui->lineEdit_path->text());
163 _ui->lineEdit_path->setText(
path);
168 std::map<int, Transform> & poses,
169 const std::multimap<int, Link> & links,
170 const QMap<int, Signature> & signatures,
173 if(this->
exec() != QDialog::Accepted)
177 QString
path =
_ui->lineEdit_path->text();
180 if(!QDir(
path).mkpath(
"."))
182 QMessageBox::warning(
this, tr(
"Exporting cameras..."), tr(
"Failed creating directory %1.").
arg(
path));
186 std::map<int, cv::Point3f> points3DMap;
187 std::map<int, std::map<int, FeatureBA> > wordReferences;
188 if(
_ui->groupBox_export_points->isEnabled() &&
_ui->groupBox_export_points->isChecked())
190 std::map<int, Transform> posesOut;
191 std::multimap<int, Link> linksOut;
195 uInsert(parametersSBA, std::make_pair(Parameters::kOptimizerIterations(),
uNumber2Str(
_ui->sba_iterations->value())));
196 uInsert(parametersSBA, std::make_pair(Parameters::kg2oPixelVariance(),
uNumber2Str(
_ui->sba_variance->value())));
200 posesOut.begin()->first,
203 signatures.toStdMap(),
206 _ui->sba_rematchFeatures->isChecked());
211 QMessageBox::warning(
this, tr(
"Exporting cameras..."), tr(
"SBA optimization failed! Cannot export with 3D points.").
arg(
path));
217 QFile fileOut(
path+QDir::separator()+
"cameras.out");
218 QFile fileList(
path+QDir::separator()+
"list.txt");
219 QFile fileListKeys(
path+QDir::separator()+
"list_keys.txt");
220 QDir(
path).mkdir(
"images");
221 if(wordReferences.size())
223 QDir(
path).mkdir(
"keys");
225 if(fileOut.open(QIODevice::WriteOnly | QIODevice::Text))
227 if(fileList.open(QIODevice::WriteOnly | QIODevice::Text))
229 std::map<int, Transform>
cameras;
230 std::map<int, int> cameraIndexes;
232 std::map<int, QColor> colors;
233 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
235 QMap<int, Signature>::const_iterator ster = signatures.find(
iter->first);
236 if(ster!= signatures.end())
238 cv::Mat image = ster.value().sensorData().imageRaw();
241 ster.value().sensorData().uncompressDataConst(&image, 0, 0, 0);
244 double maxLinearVel =
_ui->doubleSpinBox_linearSpeed->value();
245 double maxAngularVel =
_ui->doubleSpinBox_angularSpeed->value();
246 double laplacianThr =
_ui->doubleSpinBox_laplacianVariance->value();
247 bool blurryImage =
false;
248 const std::vector<float> &
velocity = ster.value().getVelocity();
249 if(maxLinearVel>0.0 || maxAngularVel>0.0)
255 if(maxLinearVel>0.0 && transVel > maxLinearVel)
257 UWARN(
"Fast motion detected for camera %d (speed=%f m/s > thr=%f m/s), camera is ignored for texturing.",
iter->first, transVel, maxLinearVel);
260 else if(maxAngularVel>0.0 && rotVel > maxAngularVel)
262 UWARN(
"Fast motion detected for camera %d (speed=%f rad/s > thr=%f rad/s), camera is ignored for texturing.",
iter->first, rotVel, maxAngularVel);
268 UWARN(
"Camera motion filtering is set, but velocity of camera %d is not available.",
iter->first);
272 if(!blurryImage && !image.empty() && laplacianThr>0.0)
274 cv::Mat imgLaplacian;
275 cv::Laplacian(image, imgLaplacian, CV_16S);
277 cv::meanStdDev(imgLaplacian,
m,
s);
278 double stddev_pxl =
s.at<
double>(0);
279 double var = stddev_pxl*stddev_pxl;
280 if(var < laplacianThr)
283 UWARN(
"Camera's image %d is detected as blurry (var=%f < thr=%f), camera is ignored for texturing.",
iter->first, var, laplacianThr);
289 cameraIndexes.insert(std::make_pair(
iter->first, camIndex++));
290 QString
p = QString(
"images")+QDir::separator()+tr(
"%1.jpg").arg(
iter->first);
291 p =
path+QDir::separator()+
p;
292 if(cv::imwrite(
p.toStdString(), image))
294 UINFO(
"saved image %s",
p.toStdString().c_str());
298 UERROR(
"Failed to save image %s",
p.toStdString().c_str());
317 if(wordReferences.size())
319 std::list<FeatureBA> descriptors;
320 for(std::map<
int, std::map<int, FeatureBA> >::
iterator jter=wordReferences.begin(); jter!=wordReferences.end(); ++jter)
322 for(std::map<int, FeatureBA>::iterator kter=jter->second.begin(); kter!=jter->second.end(); ++kter)
324 if(kter->first ==
iter->first)
326 if(!kter->second.descriptor.empty())
328 descriptors.push_back(kter->second);
331 if(colors.find(jter->first) == colors.end())
334 kter->second.kpt.pt.x >= 0.0f && (
int)kter->second.kpt.pt.x < image.cols &&
335 kter->second.kpt.pt.y >= 0.0f && (
int)kter->second.kpt.pt.y < image.rows)
337 UASSERT(image.type() == CV_8UC3 || image.type() == CV_8UC1);
339 if(image.channels() == 3)
341 cv::Vec3b & pixel = image.at<cv::Vec3b>((
int)kter->second.kpt.pt.y, (
int)kter->second.kpt.pt.x);
342 c.setRgb(pixel[2], pixel[1], pixel[0]);
346 unsigned char & pixel = image.at<
unsigned char>((
int)kter->second.kpt.pt.y, (
int)kter->second.kpt.pt.x);
347 c.setRgb(pixel, pixel, pixel);
349 colors.insert(std::make_pair(jter->first,
c));
356 QString
p = QString(
"keys")+QDir::separator()+tr(
"%1.key").arg(
iter->first);
357 p =
path+QDir::separator()+
p;
359 if(fileKey.open(QIODevice::WriteOnly | QIODevice::Text))
361 if(descriptors.size())
363 QTextStream
key(&fileKey);
364 key << descriptors.size() <<
" " << descriptors.front().descriptor.cols <<
"\n";
365 for(std::list<FeatureBA>::iterator dter=descriptors.begin(); dter!=descriptors.end(); ++dter)
368 int octave = dter->kpt.octave & 255;
369 octave = octave < 128 ? octave : (-128 | octave);
370 float scale = octave >= 0 ? 1.f/(1 << octave) : (
float)(1 << -octave);
372 key << dter->kpt.pt.x <<
" " << dter->kpt.pt.y <<
" " <<
scale <<
" " << dter->kpt.angle <<
"\n";
373 for(
int i=0;
i<dter->descriptor.cols; ++
i)
375 if(dter->descriptor.type() == CV_8U)
377 key <<
" " << (
int)dter->descriptor.at<
unsigned char>(
i);
381 key <<
" " << (
int)dter->descriptor.at<
float>(
i);
383 if((
i+1)%20 == 0 &&
i+1 < dter->descriptor.cols)
393 UWARN(
"No descriptors saved for frame %d in file %s. "
394 "Descriptors may not have been saved in the nodes. "
395 "Verify that parameter %s was true during mapping.",
396 iter->first,
p.toStdString().c_str(),
397 Parameters::kMemRawDescriptorsKept().c_str());
406 UWARN(
"Could not find node data for pose %d",
iter->first);
411 0.0
f, -1.0
f, 0.0
f, 0.0
f,
412 0.0
f, 0.0
f, 1.0
f, 0.0
f,
413 -1.0
f, 0.0
f, 0.0
f, 0.0
f);
415 static const Transform optical_rotation_inv(
416 0.0
f, -1.0
f, 0.0
f, 0.0
f,
417 0.0
f, 0.0
f, -1.0
f, 0.0
f,
418 1.0
f, 0.0
f, 0.0
f, 0.0
f);
420 QTextStream
out(&fileOut);
421 QTextStream
list(&fileList);
422 out <<
"# Bundle file v0.3\n";
423 out <<
cameras.size() <<
" " << points3DMap.size() <<
"\n";
436 QString
p = QString(
"images")+QDir::separator()+tr(
"%1.jpg").arg(
iter->first);
440 QMap<int, Signature>::const_iterator ster = signatures.find(
iter->first);
441 UASSERT(ster!=signatures.end());
442 if(ster.value().sensorData().cameraModels().size())
444 out << ster.value().sensorData().cameraModels().at(0).fx() <<
" 0 0\n";
445 localTransform = ster.value().sensorData().cameraModels().at(0).localTransform();
447 else if(ster.value().sensorData().stereoCameraModels().size())
449 out << ster.value().sensorData().stereoCameraModels()[0].left().fx() <<
" 0 0\n";
450 localTransform = ster.value().sensorData().stereoCameraModels()[0].left().localTransform();
454 if(!localTransform.
isNull())
456 pose*=localTransform*optical_rotation_inv;
460 out << poseGL.
r11() <<
" " << poseGL.
r12() <<
" " << poseGL.
r13() <<
"\n";
461 out << poseGL.
r21() <<
" " << poseGL.
r22() <<
" " << poseGL.
r23() <<
"\n";
462 out << poseGL.
r31() <<
" " << poseGL.
r32() <<
" " << poseGL.
r33() <<
"\n";
463 out << poseGL.
x() <<
" " << poseGL.
y() <<
" " << poseGL.
z() <<
"\n";
465 if(wordReferences.size())
467 if(fileListKeys.open(QIODevice::WriteOnly | QIODevice::Text))
469 QTextStream listKeys(&fileListKeys);
472 QString
p = QString(
"keys")+QDir::separator()+tr(
"%1.key").arg(
iter->first);
473 listKeys <<
p <<
"\n";
475 fileListKeys.close();
499 std::map<int, int> descriptorIndexes;
500 for(std::map<int, cv::Point3f>::iterator
iter=points3DMap.begin();
iter!=points3DMap.end(); ++
iter)
502 std::map<int, std::map<int, FeatureBA> >
::iterator jter = wordReferences.find(
iter->first);
503 out <<
iter->second.x <<
" " <<
iter->second.y <<
" " <<
iter->second.z <<
"\n";
505 QColor &
c = colors.at(
iter->first);
506 out <<
c.red() <<
" " <<
c.green() <<
" " <<
c.blue() <<
"\n";
507 out << jter->second.size();
508 for(std::map<int, FeatureBA>::iterator kter = jter->second.begin(); kter!=jter->second.end(); ++kter)
511 int camId = kter->first;
512 UASSERT(signatures.contains(camId));
513 UASSERT(cameraIndexes.find(camId) != cameraIndexes.end());
516 if(signatures[camId].sensorData().cameraModels().
size())
518 pt.x = kter->second.kpt.pt.x -
s.sensorData().cameraModels().at(0).cx();
519 pt.y = kter->second.kpt.pt.y -
s.sensorData().cameraModels().at(0).cy();
521 else if(signatures[camId].sensorData().stereoCameraModels().
size())
523 pt.x = kter->second.kpt.pt.x -
s.sensorData().stereoCameraModels()[0].left().cx();
524 pt.y = kter->second.kpt.pt.y -
s.sensorData().stereoCameraModels()[0].left().cy();
526 descriptorIndexes.insert(std::make_pair(camId, 0));
527 out <<
" " << cameraIndexes.at(camId) <<
" " << descriptorIndexes.at(camId)++ <<
" " << pt.x <<
" " << -pt.y;
535 QMessageBox::information(
this,
536 tr(
"Exporting cameras in Bundler format..."),
537 tr(
"%1 cameras/images and %2 points exported to directory \"%3\".%4")
539 .
arg(points3DMap.size())
541 .arg(poses.size()>
cameras.size()?tr(
" %1/%2 cameras ignored for too fast motion and/or blur level.").
arg(poses.size()-
cameras.size()).
arg(poses.size()):
""));
546 QMessageBox::warning(
this, tr(
"Exporting cameras..."), tr(
"Failed opening file %1 for writing.").
arg(
path+QDir::separator()+
"list.txt"));
551 QMessageBox::warning(
this, tr(
"Exporting cameras..."), tr(
"Failed opening file %1 for writing.").
arg(
path+QDir::separator()+
"cameras.out"));