12 #include <QApplication>
13 #include <QMessageBox>
14 #include <QProgressDialog>
20 #include "retrieval/resources.h"
21 #include "util/download.h"
28 : OptionsWidget(main_window),
29 main_window_(main_window),
31 setWindowTitle(
"Automatic reconstruction");
33 AddOptionDirPath(&options_.workspace_path,
"Workspace folder");
35 AddOptionDirPath(&options_.image_path,
"Image folder");
37 AddOptionDirPath(&options_.mask_path,
"Mask folder");
40 AddOptionFilePath(&options_.vocab_tree_path,
41 "Vocabulary tree<br>(optional)");
45 QLabel* data_type_label =
new QLabel(tr(
"Data type"),
this);
46 data_type_label->setFont(font());
47 data_type_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
48 grid_layout_->addWidget(data_type_label, grid_layout_->rowCount(), 0);
50 data_type_cb_ =
new QComboBox(
this);
51 data_type_cb_->addItem(
"Individual images");
52 data_type_cb_->addItem(
"Video frames");
53 data_type_cb_->addItem(
"Internet images");
54 grid_layout_->addWidget(data_type_cb_, grid_layout_->rowCount() - 1, 1);
56 QLabel* quality_label =
new QLabel(tr(
"Quality"),
this);
57 quality_label->setFont(font());
58 quality_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
59 grid_layout_->addWidget(quality_label, grid_layout_->rowCount(), 0);
61 quality_cb_ =
new QComboBox(
this);
62 quality_cb_->addItem(
"Low");
63 quality_cb_->addItem(
"Medium");
64 quality_cb_->addItem(
"High");
65 quality_cb_->addItem(
"Extreme");
66 quality_cb_->setCurrentIndex(2);
67 grid_layout_->addWidget(quality_cb_, grid_layout_->rowCount() - 1, 1);
71 AddOptionBool(&options_.single_camera,
"Shared intrinsics");
72 AddOptionBool(&options_.sparse,
"Sparse model");
73 AddOptionBool(&options_.dense,
"Dense model");
74 AddOptionBool(&options_.texturing,
"Mesh texturing");
77 QLabel* mesher_label =
new QLabel(tr(
"Mesher"),
this);
78 mesher_label->setFont(font());
79 mesher_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
80 grid_layout_->addWidget(mesher_label, grid_layout_->rowCount(), 0);
82 mesher_cb_ =
new QComboBox(
this);
83 mesher_cb_->addItem(
"Delaunay");
84 mesher_cb_->addItem(
"Poisson");
85 mesher_cb_->setCurrentIndex(0);
86 grid_layout_->addWidget(mesher_cb_, grid_layout_->rowCount() - 1, 1);
90 AddOptionInt(&options_.num_threads,
"num_threads", -1);
91 AddOptionBool(&options_.use_gpu,
"GPU");
92 AddOptionText(&options_.gpu_index,
"gpu_index");
96 QPushButton* run_button =
new QPushButton(tr(
"Run"),
this);
97 grid_layout_->addWidget(run_button, grid_layout_->rowCount(), 1);
98 connect(run_button, &QPushButton::released,
this,
101 render_result_ =
new QAction(
this);
102 connect(render_result_, &QAction::triggered,
this,
103 &AutomaticReconstructionWidget::RenderResult, Qt::QueuedConnection);
109 if (!ExistsDir(options_.workspace_path)) {
110 QMessageBox::critical(
this,
"", tr(
"Invalid workspace folder"));
114 if (!ExistsDir(options_.image_path)) {
115 QMessageBox::critical(
this,
"", tr(
"Invalid image folder"));
119 switch (data_type_cb_->currentIndex()) {
122 AutomaticReconstructionController::DataType::INDIVIDUAL;
126 AutomaticReconstructionController::DataType::VIDEO;
130 AutomaticReconstructionController::DataType::INTERNET;
134 AutomaticReconstructionController::DataType::INDIVIDUAL;
138 switch (quality_cb_->currentIndex()) {
140 options_.quality = AutomaticReconstructionController::Quality::LOW;
144 AutomaticReconstructionController::Quality::MEDIUM;
147 options_.quality = AutomaticReconstructionController::Quality::HIGH;
151 AutomaticReconstructionController::Quality::EXTREME;
154 options_.quality = AutomaticReconstructionController::Quality::HIGH;
158 switch (mesher_cb_->currentIndex()) {
161 AutomaticReconstructionController::Mesher::DELAUNAY;
165 AutomaticReconstructionController::Mesher::POISSON;
169 AutomaticReconstructionController::Mesher::DELAUNAY;
174 std::string vocab_tree_path = options_.vocab_tree_path;
175 if (vocab_tree_path.empty()) {
176 vocab_tree_path = retrieval::kDefaultVocabTreeUri;
180 if (!vocab_tree_path.empty() && colmap::IsURI(vocab_tree_path)) {
181 #ifdef COLMAP_DOWNLOAD_ENABLED
184 colmap::GetCachedFilePath(vocab_tree_path);
185 if (!cached_path.empty() && std::filesystem::exists(cached_path)) {
187 LOG(INFO) <<
"Using cached vocabulary tree file: " << cached_path;
188 options_.vocab_tree_path = cached_path.string();
191 QProgressDialog progress_dialog(
192 tr(
"Downloading vocabulary tree..."), tr(
"Cancel"), 0, 100,
194 progress_dialog.setWindowModality(Qt::ApplicationModal);
195 progress_dialog.setWindowTitle(tr(
"Downloading"));
196 progress_dialog.setAutoClose(
false);
197 progress_dialog.setAutoReset(
false);
198 progress_dialog.setMinimumDuration(0);
199 progress_dialog.show();
200 QApplication::processEvents();
202 bool download_canceled =
false;
203 colmap::DownloadProgressCallback progress_callback =
204 [&progress_dialog, &download_canceled](int64_t downloaded,
206 QApplication::processEvents();
207 if (progress_dialog.wasCanceled()) {
208 download_canceled =
true;
213 int percent =
static_cast<int>((downloaded * 100) /
215 progress_dialog.setValue(percent);
218 double downloaded_mb =
219 static_cast<double>(downloaded) /
221 double total_mb =
static_cast<double>(total) /
223 progress_dialog.setLabelText(
224 tr(
"Downloading vocabulary tree...\n%1 MB "
226 .arg(downloaded_mb, 0,
'f', 2)
227 .arg(total_mb, 0,
'f', 2)
230 progress_dialog.setValue(0);
231 double downloaded_mb =
232 static_cast<double>(downloaded) /
234 progress_dialog.setLabelText(
235 tr(
"Downloading vocabulary tree...\n%1 MB")
236 .arg(downloaded_mb, 0,
'f', 2));
238 QApplication::processEvents();
242 std::string downloaded_path = colmap::DownloadAndCacheFile(
243 vocab_tree_path, progress_callback);
244 progress_dialog.close();
246 if (download_canceled || downloaded_path.empty()) {
247 QMessageBox::warning(
248 this, tr(
"Download Canceled"),
249 tr(
"Vocabulary tree download was canceled. Please "
250 "provide a local path."));
255 options_.vocab_tree_path = downloaded_path;
256 }
catch (
const std::exception& e) {
257 progress_dialog.close();
258 QMessageBox::critical(
259 this, tr(
"Download Failed"),
260 tr(
"Failed to download vocabulary tree: %1")
266 QMessageBox::warning(
this, tr(
"Download Disabled"),
267 tr(
"Download support is disabled. Please provide "
268 "a local vocabulary tree path."));
273 main_window_->reconstruction_manager_.Clear();
274 main_window_->reconstruction_manager_widget_->
Update();
275 main_window_->RenderClear();
276 main_window_->RenderNow();
280 options_, &main_window_->reconstruction_manager_);
282 controller->AddCallback(Thread::FINISHED_CALLBACK, [
this, controller]() {
290 render_result_->trigger();
293 thread_control_widget_->
StartThread(
"Reconstructing...",
true, controller);
300 if (options_.vocab_tree_path.empty()) {
301 options_.vocab_tree_path = retrieval::kDefaultVocabTreeUri;
306 OptionsWidget::showEvent(
event);
310 for (
auto& option : options_path_) {
311 if (option.second == &options_.vocab_tree_path) {
312 if (option.first->text().isEmpty() &&
313 !options_.vocab_tree_path.empty()) {
314 option.first->setText(
315 QString::fromStdString(options_.vocab_tree_path));
322 void AutomaticReconstructionWidget::RenderResult() {
323 if (main_window_->reconstruction_manager_.Size() > 0) {
324 main_window_->reconstruction_manager_widget_->
Update();
325 main_window_->RenderClear();
326 main_window_->RenderNow();
329 if (options_.sparse) {
330 QMessageBox::information(
this,
"",
331 tr(
"Imported the reconstructed sparse models "
332 "for visualization. The "
333 "models were also exported to the "
334 "<i>sparse</i> sub-folder in the "
338 if (options_.dense) {
341 if (!fused_points_.empty()) {
347 for (std::size_t i = 0; i < fused_points_.size(); ++i) {
352 static_cast<unsigned>(fused_points_.size());
356 for (
const auto&
point : fused_points_[i]) {
366 "[AutomaticReconstructionWidget::"
367 "RenderResult] Not enough memory!");
371 "[RenderResult] Ignore empty fused points "
377 "[AutomaticReconstructionWidget::RenderResult] "
378 "Not enough memory!");
383 delete fusedCloudGroup;
384 fusedCloudGroup =
nullptr;
386 "[AutomaticReconstructionWidget::RenderResult] "
387 "some unknown error!");
389 if (main_window_->app_) {
390 main_window_->app_->
addToDB(fusedCloudGroup);
396 if (main_window_->app_) {
397 QStringList filenames;
401 if (options_.texturing && texturing_success_ &&
402 !textured_paths_.empty()) {
403 for (
const std::string&
path : textured_paths_) {
404 if (!ExistsFile(
path)) {
406 "[RenderResult] Ignore invalid textured "
407 "mesh for file [%s]",
411 filenames.push_back(
path.c_str());
413 if (!filenames.isEmpty()) {
420 else if (!meshing_paths_.empty()) {
421 for (
const std::string&
path : meshing_paths_) {
422 if (!ExistsFile(
path)) {
424 "[RenderResult] Ignore invalid meshed "
425 "model for file [%s]",
429 filenames.push_back(
path.c_str());
431 if (!filenames.isEmpty()) {
439 QMessageBox::information(
441 tr(
"To visualize the reconstructed dense point cloud, "
443 "<i>dense</i> sub-folder in your workspace with <i>File "
445 "model from...</i>. To visualize the meshed model, "
446 "you can only drop meshed file into the main window."));
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
void addToDB(const QStringList &filenames, QString fileFilter=QString(), bool displayDialog=true)
void addToDBAuto(const QStringList &filenames, bool displayDialog=true)
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
Hierarchical CLOUDVIEWER Object.
unsigned getChildrenNumber() const
Returns the number of children.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
std::vector< std::string > meshing_paths_
std::vector< std::string > textured_paths_
std::vector< std::vector< colmap::PlyPoint > > fused_points_
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
static const std::string path
Generic file read and write utility for python interface.