15 #include "base/pose.h"
16 #include "base/projection.h"
18 #include "ui/qt_utils.h"
19 #include "ui/render_options.h"
27 : QWidget(parent), model_viewer_widget_(model_viewer_widget) {
28 setWindowFlags(Qt::Widget | Qt::WindowStaysOnTopHint | Qt::Tool);
29 setWindowTitle(
"Grab movie");
31 QGridLayout* grid =
new QGridLayout(
this);
32 grid->setContentsMargins(0, 5, 0, 5);
34 add_button_ =
new QPushButton(tr(
"Add"),
this);
35 connect(add_button_, &QPushButton::released,
this,
36 &MovieGrabberWidget::Add);
37 grid->addWidget(add_button_, 0, 0);
39 add_from_selected_button_ =
new QPushButton(tr(
"Add Selected"),
this);
40 connect(add_from_selected_button_, &QPushButton::released,
this,
41 &MovieGrabberWidget::AddFromSelected);
42 grid->addWidget(add_from_selected_button_, 0, 1);
44 delete_button_ =
new QPushButton(tr(
"Delete"),
this);
45 connect(delete_button_, &QPushButton::released,
this,
46 &MovieGrabberWidget::Delete);
47 grid->addWidget(delete_button_, 0, 2);
49 clear_button_ =
new QPushButton(tr(
"Clear"),
this);
50 connect(clear_button_, &QPushButton::released,
this,
51 &MovieGrabberWidget::Clear);
52 grid->addWidget(clear_button_, 0, 3);
54 table_ =
new QTableWidget(
this);
55 table_->setColumnCount(1);
56 QStringList table_header;
57 table_header <<
"Time [seconds]";
58 table_->setHorizontalHeaderLabels(table_header);
59 table_->resizeColumnsToContents();
60 table_->setShowGrid(
true);
61 table_->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
62 table_->verticalHeader()->setVisible(
true);
63 table_->verticalHeader()->setDefaultSectionSize(18);
64 table_->setSelectionMode(QAbstractItemView::SingleSelection);
65 table_->setSelectionBehavior(QAbstractItemView::SelectRows);
66 connect(table_, &QTableWidget::itemChanged,
this,
67 &MovieGrabberWidget::TimeChanged);
68 connect(table_->selectionModel(), &QItemSelectionModel::selectionChanged,
69 this, &MovieGrabberWidget::SelectionChanged);
70 grid->addWidget(table_, 1, 0, 1, 3);
72 grid->addWidget(
new QLabel(tr(
"Frame rate"),
this), 2, 1);
73 frame_rate_sb_ =
new QSpinBox(
this);
74 frame_rate_sb_->setMinimum(1);
75 frame_rate_sb_->setMaximum(1000);
76 frame_rate_sb_->setSingleStep(1);
77 frame_rate_sb_->setValue(100);
78 grid->addWidget(frame_rate_sb_, 2, 2);
80 grid->addWidget(
new QLabel(tr(
"Smooth transition"),
this), 3, 1);
81 smooth_cb_ =
new QCheckBox(
this);
82 smooth_cb_->setChecked(
true);
83 grid->addWidget(smooth_cb_, 3, 2);
85 grid->addWidget(
new QLabel(tr(
"Smoothness"),
this), 4, 1);
86 smoothness_sb_ =
new QDoubleSpinBox(
this);
87 smoothness_sb_->setMinimum(0);
88 smoothness_sb_->setMaximum(1);
89 smoothness_sb_->setSingleStep(0.01);
90 smoothness_sb_->setValue(0.5);
91 grid->addWidget(smoothness_sb_, 4, 2);
93 assemble_button_ =
new QPushButton(tr(
"Assemble movie"),
this);
94 connect(assemble_button_, &QPushButton::released,
this,
95 &MovieGrabberWidget::Assemble);
96 grid->addWidget(assemble_button_, 5, 1, 1, 2);
99 void MovieGrabberWidget::AddFromSelected() {
100 if (!view_data_.empty()) {
101 if (QMessageBox::question(
102 this, tr(
"Add viewports from selected"),
103 tr(
"Are you sure you want to remove all history views?"),
104 QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes) {
114 std::vector<cc2DViewportObject*> selected_viewports;
115 for (
const auto& obj : objects) {
117 selected_viewports.push_back(
123 .arg(selected_viewports.size()));
124 for (
auto& viewport : selected_viewports) {
130 if (table_->rowCount() > 0) {
131 time = table_->item(table_->rowCount() - 1, 0)->text().toDouble() +
135 QTableWidgetItem* item =
new QTableWidgetItem();
136 item->setData(Qt::DisplayRole, time);
137 item->setFlags(Qt::NoItemFlags | Qt::ItemIsEnabled |
138 Qt::ItemIsSelectable | Qt::ItemIsEditable);
139 item->setTextAlignment(Qt::AlignRight);
142 MovieGrabberWidget::ViewData view_data;
143 view_data.viewportParams = viewport->getParameters();
144 view_data.model_view_matrix =
145 viewport->getParameters().computeViewMatrix();
146 view_data.point_size = model_viewer_widget_->
PointSize();
147 view_data.image_size = model_viewer_widget_->
ImageSize();
148 view_data_.emplace(item, view_data);
150 table_->insertRow(table_->rowCount());
151 table_->setItem(table_->rowCount() - 1, 0, item);
152 table_->selectRow(table_->rowCount() - 1);
156 void MovieGrabberWidget::Add() {
160 if (table_->rowCount() > 0) {
161 time = table_->item(table_->rowCount() - 1, 0)->text().toDouble() + 1;
164 QTableWidgetItem* item =
new QTableWidgetItem();
165 item->setData(Qt::DisplayRole, time);
166 item->setFlags(Qt::NoItemFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable |
168 item->setTextAlignment(Qt::AlignRight);
171 MovieGrabberWidget::ViewData view_data;
173 view_data.model_view_matrix = matrix;
174 view_data.point_size = model_viewer_widget_->
PointSize();
175 view_data.image_size = model_viewer_widget_->
ImageSize();
176 view_data_.emplace(item, view_data);
178 table_->insertRow(table_->rowCount());
179 table_->setItem(table_->rowCount() - 1, 0, item);
180 table_->selectRow(table_->rowCount() - 1);
186 void MovieGrabberWidget::Delete() {
187 QModelIndexList selection = table_->selectionModel()->selectedIndexes();
188 std::vector<colmap::camera_t> toBeDeleted;
189 for (
const auto& index : selection) {
190 table_->removeRow(index.row());
191 Image&
image =
views[
static_cast<std::size_t
>(index.row())];
192 toBeDeleted.push_back(
image.CameraId());
195 std::vector<colmap::camera_t>::iterator it;
196 for (it = camera_ids_.begin(); it != camera_ids_.end();) {
197 if (std::find(toBeDeleted.begin(), toBeDeleted.end(), *it) !=
199 it = camera_ids_.erase(it);
209 void MovieGrabberWidget::Clear() {
211 while (table_->rowCount() > 0) {
212 table_->removeRow(0);
219 void MovieGrabberWidget::Assemble() {
220 if (table_->rowCount() < 2) {
221 QMessageBox::critical(
this, tr(
"Error"),
222 tr(
"You must add at least two control views."));
227 colmap::RenderOptions::ProjectionType::PERSPECTIVE) {
228 QMessageBox::critical(
this, tr(
"Error"),
229 tr(
"You must use perspective projection."));
233 const QString
path = QFileDialog::getExistingDirectory(
234 this, tr(
"Choose destination..."),
"", QFileDialog::ShowDirsOnly);
241 const QDir dir = QDir(
path);
245 const float point_size_cached = model_viewer_widget_->
PointSize();
246 const float image_size_cached = model_viewer_widget_->
ImageSize();
247 const std::vector<Image> views_cached =
views;
252 bool coords_changed =
false;
253 bool lengend_changed =
false;
258 lengend_changed =
true;
262 coords_changed =
true;
265 const float frame_rate = frame_rate_sb_->value();
266 const float frame_time = 1.0f / frame_rate;
267 size_t frame_number = 0;
271 for (
int row = 1; row < table_->rowCount(); ++row) {
272 const auto logical_idx = table_->verticalHeader()->logicalIndex(row);
273 QTableWidgetItem* prev_table_item = table_->item(logical_idx - 1, 0);
274 QTableWidgetItem* table_item = table_->item(logical_idx, 0);
276 const float dt =
std::abs(table_item->text().toFloat() -
277 prev_table_item->text().toFloat());
281 int frameCount =
static_cast<int>(frame_rate * totalTime);
284 QProgressDialog progressDialog(QString(
"Frames: %1").arg(frameCount),
285 "Cancel", 0, frameCount,
this);
286 progressDialog.setWindowTitle(
"Generate movie frames");
287 progressDialog.setModal(
true);
289 progressDialog.show();
290 QApplication::processEvents();
294 view_data_[table_->item(0, 0)].viewportParams;
295 for (
int row = 1; row < table_->rowCount(); ++row) {
296 const auto logical_idx = table_->verticalHeader()->logicalIndex(row);
297 QTableWidgetItem* prev_table_item = table_->item(logical_idx - 1, 0);
298 QTableWidgetItem* table_item = table_->item(logical_idx, 0);
300 const MovieGrabberWidget::ViewData& prev_view_data =
301 view_data_.at(prev_table_item);
302 const MovieGrabberWidget::ViewData& view_data =
303 view_data_.at(table_item);
306 const float dt =
std::abs(table_item->text().toFloat() -
307 prev_table_item->text().toFloat());
310 const float dpoint_size =
311 view_data.point_size - prev_view_data.point_size;
312 const float dimage_size =
313 view_data.image_size - prev_view_data.image_size;
315 const auto num_frames = dt * frame_rate;
317 for (
size_t i = 0; i < num_frames; ++i) {
318 const float t = i * frame_time;
321 if (smooth_cb_->isChecked()) {
322 tt = ScaleSigmoid(tt,
323 static_cast<float>(smoothness_sb_->value()));
327 view_data.viewportParams);
329 interpolator.interpolate(currentViewport,
static_cast<double>(tt));
334 prev_view_data.point_size + dpoint_size * tt,
false);
336 prev_view_data.image_size + dimage_size * tt,
false);
339 model_viewer_widget_->
update();
342 image.save(dir.filePath(
"frame" +
343 QString().asprintf(
"%06zu", frame_number) +
346 progressDialog.setValue(frame_number);
347 QApplication::processEvents();
348 if (progressDialog.wasCanceled()) {
349 firstViewport = currentViewport;
355 views = views_cached;
359 if (lengend_changed) {
362 if (coords_changed) {
369 void MovieGrabberWidget::TimeChanged(QTableWidgetItem* item) {
370 table_->sortItems(0, Qt::AscendingOrder);
375 void MovieGrabberWidget::SelectionChanged(
const QItemSelection& selected,
376 const QItemSelection& deselected) {
377 for (
const auto& index : table_->selectionModel()->selectedIndexes()) {
382 void MovieGrabberWidget::UpdateViews() {
384 colmap::camera_t base_id = 1000;
385 std::size_t lastNum = camera_ids_.size();
386 for (
int row = 0; row < table_->rowCount(); ++row) {
387 const auto logical_idx = table_->verticalHeader()->logicalIndex(row);
388 QTableWidgetItem* item = table_->item(logical_idx, 0);
391 view_data_.at(item).model_view_matrix);
394 colmap::camera_t camera_id;
395 std::size_t curIndex =
static_cast<std::size_t
>(row);
396 if (curIndex < lastNum) {
397 camera_id = camera_ids_[curIndex];
399 if (camera_ids_.empty()) {
400 camera_id = base_id +
static_cast<colmap::camera_t
>(row);
402 camera_id = camera_ids_[camera_ids_.size() - 1] + 1;
405 camera_ids_.push_back(camera_id);
408 image.SetImageId(camera_id);
409 image.SetCameraId(camera_id);
412 RotationMatrixToQuaternion(model_view_matrix.block<3, 3>(0, 0));
413 image.Tvec() = model_view_matrix.block<3, 1>(0, 3);
std::shared_ptr< core::Tensor > image
static bool Print(const char *format,...)
Prints out a formatted message in console.
The ViewInterpolate class.
static Eigen::Matrix< double, 4, 4 > ToEigenMatrix4(const ccGLMatrixTpl< float > &mat)
Double version of ccGLMatrixTpl.
static cc2DViewportObject * To2DViewportObject(ccHObject *obj)
Converts current object to cc2DViewportObject (if possible)
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Standard parameters for GL displays/viewports.
__host__ __device__ int2 abs(int2 v)
static const std::string path
Generic file read and write utility for python interface.