42 : QWidget(parent), model_viewer_widget_(model_viewer_widget) {
43 setWindowFlags(Qt::Widget | Qt::WindowStaysOnTopHint | Qt::Tool);
44 setWindowTitle(
"Grab movie");
46 QGridLayout* grid =
new QGridLayout(
this);
47 grid->setContentsMargins(0, 5, 0, 5);
49 add_button_ =
new QPushButton(tr(
"Add"),
this);
50 connect(add_button_, &QPushButton::released,
this, &MovieGrabberWidget::Add);
51 grid->addWidget(add_button_, 0, 0);
53 delete_button_ =
new QPushButton(tr(
"Delete"),
this);
54 connect(delete_button_, &QPushButton::released,
this,
55 &MovieGrabberWidget::Delete);
56 grid->addWidget(delete_button_, 0, 1);
58 clear_button_ =
new QPushButton(tr(
"Clear"),
this);
59 connect(clear_button_, &QPushButton::released,
this,
60 &MovieGrabberWidget::Clear);
61 grid->addWidget(clear_button_, 0, 2);
63 table_ =
new QTableWidget(
this);
64 table_->setColumnCount(1);
65 QStringList table_header;
66 table_header <<
"Time [seconds]";
67 table_->setHorizontalHeaderLabels(table_header);
68 table_->resizeColumnsToContents();
69 table_->setShowGrid(
true);
70 table_->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
71 table_->verticalHeader()->setVisible(
true);
72 table_->verticalHeader()->setDefaultSectionSize(18);
73 table_->setSelectionMode(QAbstractItemView::SingleSelection);
74 table_->setSelectionBehavior(QAbstractItemView::SelectRows);
75 connect(table_, &QTableWidget::itemChanged,
this,
76 &MovieGrabberWidget::TimeChanged);
77 connect(table_->selectionModel(), &QItemSelectionModel::selectionChanged,
78 this, &MovieGrabberWidget::SelectionChanged);
79 grid->addWidget(table_, 1, 0, 1, 3);
81 grid->addWidget(
new QLabel(tr(
"Frame rate"),
this), 2, 1);
82 frame_rate_sb_ =
new QSpinBox(
this);
83 frame_rate_sb_->setMinimum(1);
84 frame_rate_sb_->setMaximum(1000);
85 frame_rate_sb_->setSingleStep(1);
86 frame_rate_sb_->setValue(100);
87 grid->addWidget(frame_rate_sb_, 2, 2);
89 grid->addWidget(
new QLabel(tr(
"Smooth transition"),
this), 3, 1);
90 smooth_cb_ =
new QCheckBox(
this);
91 smooth_cb_->setChecked(
true);
92 grid->addWidget(smooth_cb_, 3, 2);
94 grid->addWidget(
new QLabel(tr(
"Smoothness"),
this), 4, 1);
95 smoothness_sb_ =
new QDoubleSpinBox(
this);
96 smoothness_sb_->setMinimum(0);
97 smoothness_sb_->setMaximum(1);
98 smoothness_sb_->setSingleStep(0.01);
99 smoothness_sb_->setValue(0.5);
100 grid->addWidget(smoothness_sb_, 4, 2);
102 assemble_button_ =
new QPushButton(tr(
"Assemble movie"),
this);
103 connect(assemble_button_, &QPushButton::released,
this,
104 &MovieGrabberWidget::Assemble);
105 grid->addWidget(assemble_button_, 5, 1, 1, 2);
108 void MovieGrabberWidget::Add() {
112 if (table_->rowCount() > 0) {
113 time = table_->item(table_->rowCount() - 1, 0)->text().toDouble() + 1;
116 QTableWidgetItem* item =
new QTableWidgetItem();
117 item->setData(Qt::DisplayRole, time);
118 item->setFlags(Qt::NoItemFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable |
120 item->setTextAlignment(Qt::AlignRight);
124 view_data.model_view_matrix = matrix;
125 view_data.point_size = model_viewer_widget_->
PointSize();
126 view_data.image_size = model_viewer_widget_->
ImageSize();
127 view_data_.emplace(item, view_data);
129 table_->insertRow(table_->rowCount());
130 table_->setItem(table_->rowCount() - 1, 0, item);
131 table_->selectRow(table_->rowCount() - 1);
137 void MovieGrabberWidget::Delete() {
138 QModelIndexList selection = table_->selectionModel()->selectedIndexes();
139 for (
const auto& index : selection) {
140 table_->removeRow(index.row());
146 void MovieGrabberWidget::Clear() {
148 while (table_->rowCount() > 0) {
149 table_->removeRow(0);
155 void MovieGrabberWidget::Assemble() {
156 if (table_->rowCount() < 2) {
157 QMessageBox::critical(
this, tr(
"Error"),
158 tr(
"You must add at least two control views."));
163 RenderOptions::ProjectionType::PERSPECTIVE) {
164 QMessageBox::critical(
this, tr(
"Error"),
165 tr(
"You must use perspective projection."));
169 const QString
path = QFileDialog::getExistingDirectory(
170 this, tr(
"Choose destination..."),
"", QFileDialog::ShowDirsOnly);
177 const QDir dir = QDir(
path);
179 const QMatrix4x4 model_view_matrix_cached =
181 const float point_size_cached = model_viewer_widget_->
PointSize();
182 const float image_size_cached = model_viewer_widget_->
ImageSize();
183 const std::vector<Image> views_cached =
views;
190 const float frame_rate = frame_rate_sb_->value();
191 const float frame_time = 1.0f / frame_rate;
192 size_t frame_number = 0;
195 const Eigen::Matrix4d prev_model_view_matrix =
200 Eigen::Vector4d prev_qvec =
202 Eigen::Vector3d prev_tvec = prev_view_model_matrix.block<3, 1>(0, 3);
204 for (
int row = 1; row < table_->rowCount(); ++row) {
205 const auto logical_idx = table_->verticalHeader()->logicalIndex(row);
206 QTableWidgetItem* prev_table_item = table_->item(logical_idx - 1, 0);
207 QTableWidgetItem* table_item = table_->item(logical_idx, 0);
209 const ViewData& prev_view_data = view_data_.at(prev_table_item);
210 const ViewData& view_data = view_data_.at(table_item);
213 const Eigen::Matrix4d curr_model_view_matrix =
217 const Eigen::Vector4d curr_qvec =
219 const Eigen::Vector3d curr_tvec = curr_view_model_matrix.block<3, 1>(0, 3);
222 const float dt = std::abs(table_item->text().toFloat() -
223 prev_table_item->text().toFloat());
226 const float dpoint_size = view_data.point_size - prev_view_data.point_size;
227 const float dimage_size = view_data.image_size - prev_view_data.image_size;
229 const auto num_frames = dt * frame_rate;
230 for (
size_t i = 0; i < num_frames; ++i) {
231 const float t = i * frame_time;
234 if (smooth_cb_->isChecked()) {
235 tt =
ScaleSigmoid(tt,
static_cast<float>(smoothness_sb_->value()));
239 Eigen::Vector4d interp_qvec;
240 Eigen::Vector3d interp_tvec;
242 &interp_qvec, &interp_tvec);
244 Eigen::Matrix4d frame_model_view_matrix = Eigen::Matrix4d::Identity();
252 model_viewer_widget_->
SetPointSize(prev_view_data.point_size +
254 model_viewer_widget_->
SetImageSize(prev_view_data.image_size +
258 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
259 image.save(dir.filePath(
260 "frame" + QString::asprintf(
"%06zu", frame_number) +
".png"));
262 image.save(dir.filePath(
263 "frame" + QString().sprintf(
"%06zu", frame_number) +
".png"));
268 prev_qvec = curr_qvec;
269 prev_tvec = curr_tvec;
272 views = views_cached;
280 void MovieGrabberWidget::TimeChanged(QTableWidgetItem* item) {
281 table_->sortItems(0, Qt::AscendingOrder);
286 void MovieGrabberWidget::SelectionChanged(
const QItemSelection& selected,
287 const QItemSelection& deselected) {
288 for (
const auto& index : table_->selectionModel()->selectedIndexes()) {
293 void MovieGrabberWidget::UpdateViews() {
295 for (
int row = 0; row < table_->rowCount(); ++row) {
296 const auto logical_idx = table_->verticalHeader()->logicalIndex(row);
297 QTableWidgetItem* item = table_->item(logical_idx, 0);
299 const Eigen::Matrix4d model_view_matrix =
300 QMatrixToEigen(view_data_.at(item).model_view_matrix).cast<
double>();
304 image.Tvec() = model_view_matrix.block<3, 1>(0, 3);
std::shared_ptr< core::Tensor > image
Matrix< double, 3, 4 > Matrix3x4d
static const std::string path
Eigen::Matrix3x4d InvertProjectionMatrix(const Eigen::Matrix3x4d &proj_matrix)
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d &rot_mat)
T ScaleSigmoid(T x, const T alpha=1, const T x0=10)
Eigen::Matrix4f QMatrixToEigen(const QMatrix4x4 &matrix)
QMatrix4x4 EigenToQMatrix(const Eigen::Matrix4f &matrix)
Eigen::Matrix3x4d ComposeProjectionMatrix(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec)
void InterpolatePose(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2, const double t, Eigen::Vector4d *qveci, Eigen::Vector3d *tveci)