12 #include <QApplication>
13 #include <QMessageBox>
14 #include <QProgressDialog>
29 main_window_(main_window),
31 setWindowTitle(
"Automatic reconstruction");
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);
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");
56 QLabel* quality_label =
new QLabel(tr(
"Quality"),
this);
57 quality_label->setFont(font());
58 quality_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
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);
77 QLabel* mesher_label =
new QLabel(tr(
"Mesher"),
this);
78 mesher_label->setFont(font());
79 mesher_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
82 mesher_cb_ =
new QComboBox(
this);
83 mesher_cb_->addItem(
"Delaunay");
84 mesher_cb_->addItem(
"Poisson");
85 mesher_cb_->setCurrentIndex(0);
96 QPushButton* run_button =
new QPushButton(tr(
"Run"),
this);
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);
110 QMessageBox::critical(
this,
"", tr(
"Invalid workspace folder"));
115 QMessageBox::critical(
this,
"", tr(
"Invalid image folder"));
119 switch (data_type_cb_->currentIndex()) {
138 switch (quality_cb_->currentIndex()) {
158 switch (mesher_cb_->currentIndex()) {
175 if (vocab_tree_path.empty()) {
180 if (!vocab_tree_path.empty() &&
colmap::IsURI(vocab_tree_path)) {
181 #ifdef COLMAP_DOWNLOAD_ENABLED
185 if (!cached_path.empty() && std::filesystem::exists(cached_path)) {
187 LOG(INFO) <<
"Using cached vocabulary tree file: " << cached_path;
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."));
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_);
290 render_result_->trigger();
293 thread_control_widget_->
StartThread(
"Reconstructing...",
true, controller);
312 if (option.first->text().isEmpty() &&
314 option.first->setText(
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();
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]) {
360 point.r, point.g, point.b));
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_) {
406 "[RenderResult] Ignore invalid textured "
407 "mesh for file [%s]",
411 filenames.push_back(
path.c_str());
413 if (!filenames.isEmpty()) {
416 main_window_->app_->addToDBAuto(filenames,
false);
420 else if (!meshing_paths_.empty()) {
421 for (
const std::string&
path : meshing_paths_) {
424 "[RenderResult] Ignore invalid meshed "
425 "model for file [%s]",
429 filenames.push_back(
path.c_str());
431 if (!filenames.isEmpty()) {
434 main_window_->app_->addToDBAuto(filenames,
false);
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.
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.
void AddCallback(const int id, const std::function< void()> &func)
static const std::string path
Generic file read and write utility for python interface.
static const std::string kDefaultVocabTreeUri
bool IsURI(const std::string &uri)
std::filesystem::path GetCachedFilePath(const std::string &uri)
bool ExistsDir(const std::string &path)
bool ExistsFile(const std::string &path)
std::string workspace_path
std::string vocab_tree_path