43 model_viewer_widget_(model_viewer_widget),
46 zoom_(250.0 / 1024.0) {
47 setWindowFlags(Qt::Window);
48 resize(parent->size().width() - 20, parent->size().height() - 20);
51 font.setPointSize(10);
54 QGridLayout* grid =
new QGridLayout(
this);
55 grid->setContentsMargins(5, 5, 5, 5);
57 info_table_ =
new QTableWidget(
this);
59 info_table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
60 info_table_->setSelectionMode(QAbstractItemView::SingleSelection);
61 info_table_->setShowGrid(
true);
62 info_table_->horizontalHeader()->setStretchLastSection(
true);
63 info_table_->horizontalHeader()->setVisible(
false);
64 info_table_->verticalHeader()->setVisible(
false);
65 info_table_->verticalHeader()->setDefaultSectionSize(18);
67 info_table_->setColumnCount(2);
68 info_table_->setRowCount(3);
70 info_table_->setItem(0, 0,
new QTableWidgetItem(
"position"));
71 xyz_item_ =
new QTableWidgetItem();
72 info_table_->setItem(0, 1, xyz_item_);
74 info_table_->setItem(1, 0,
new QTableWidgetItem(
"color"));
75 rgb_item_ =
new QTableWidgetItem();
76 info_table_->setItem(1, 1, rgb_item_);
78 info_table_->setItem(2, 0,
new QTableWidgetItem(
"error"));
79 error_item_ =
new QTableWidgetItem();
80 info_table_->setItem(2, 1, error_item_);
82 grid->addWidget(info_table_, 0, 0);
84 location_table_ =
new QTableWidget(
this);
85 location_table_->setColumnCount(4);
86 QStringList table_header;
87 table_header <<
"image_id"
91 location_table_->setHorizontalHeaderLabels(table_header);
92 location_table_->resizeColumnsToContents();
93 location_table_->setShowGrid(
true);
94 location_table_->horizontalHeader()->setStretchLastSection(
true);
95 location_table_->verticalHeader()->setVisible(
true);
96 location_table_->setSelectionMode(QAbstractItemView::NoSelection);
97 location_table_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
98 location_table_->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
99 location_table_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
101 grid->addWidget(location_table_, 1, 0);
103 QHBoxLayout* button_layout =
new QHBoxLayout();
105 zoom_in_button_ =
new QPushButton(tr(
"+"),
this);
106 zoom_in_button_->setFont(font);
107 zoom_in_button_->setFixedWidth(50);
108 button_layout->addWidget(zoom_in_button_);
109 connect(zoom_in_button_, &QPushButton::released,
this,
110 &PointViewerWidget::ZoomIn);
112 zoom_out_button_ =
new QPushButton(tr(
"-"),
this);
113 zoom_out_button_->setFont(font);
114 zoom_out_button_->setFixedWidth(50);
115 button_layout->addWidget(zoom_out_button_);
116 connect(zoom_out_button_, &QPushButton::released,
this,
117 &PointViewerWidget::ZoomOut);
119 delete_button_ =
new QPushButton(tr(
"Delete"),
this);
120 button_layout->addWidget(delete_button_);
121 connect(delete_button_, &QPushButton::released,
this,
122 &PointViewerWidget::Delete);
124 grid->addLayout(button_layout, 2, 0, Qt::AlignRight);
128 location_pixmaps_.clear();
130 reproj_errors_.clear();
131 image_names_.clear();
133 if (model_viewer_widget_->
points3D.count(point3D_id) == 0) {
142 point3D_id_ = point3D_id;
146 setWindowTitle(QString::fromStdString(
"Point " +
std::to_string(point3D_id)));
148 const auto& point3D = model_viewer_widget_->
points3D[point3D_id];
150 xyz_item_->setText(QString::number(point3D.X()) +
", " +
151 QString::number(point3D.Y()) +
", " +
152 QString::number(point3D.Z()));
153 rgb_item_->setText(QString::number(point3D.Color(0)) +
", " +
154 QString::number(point3D.Color(1)) +
", " +
155 QString::number(point3D.Color(2)));
156 error_item_->setText(QString::number(point3D.Error()));
162 std::vector<std::pair<TrackElement, std::string>> track_idx_image_name_pairs;
163 track_idx_image_name_pairs.reserve(point3D.Track().Length());
164 for (
const auto& track_el : point3D.Track().Elements()) {
166 track_idx_image_name_pairs.emplace_back(track_el,
image.Name());
169 std::sort(track_idx_image_name_pairs.begin(),
170 track_idx_image_name_pairs.end(),
171 [](
const std::pair<TrackElement, std::string>& track_el1,
172 const std::pair<TrackElement, std::string>& track_el2) {
173 return track_el1.second < track_el2.second;
178 for (
const auto& track_el : track_idx_image_name_pairs) {
181 const Point2D& point2D =
image.Point2D(track_el.first.point2D_idx);
182 const Eigen::Vector2d proj_point2D =
184 const double reproj_error = (point2D.
XY() - proj_point2D).norm();
189 std::cerr <<
"ERROR: Cannot read image at path " <<
path <<
std::endl;
196 QPainter painter(&pixmap);
197 painter.setRenderHint(QPainter::Antialiasing);
204 const int kCrossSize = 15;
205 const int x =
static_cast<int>(std::round(point2D.
X()));
206 const int y =
static_cast<int>(std::round(point2D.
Y()));
207 painter.drawLine(
x - kCrossSize,
y - kCrossSize,
x + kCrossSize,
209 painter.drawLine(
x - kCrossSize,
y + kCrossSize,
x + kCrossSize,
215 const int proj_x =
static_cast<int>(std::round(proj_point2D.x()));
216 const int proj_y =
static_cast<int>(std::round(proj_point2D.y()));
217 painter.drawEllipse(proj_x - 5, proj_y - 5, 10, 10);
218 painter.drawEllipse(proj_x - 15, proj_y - 15, 30, 30);
219 painter.drawEllipse(proj_x - 45, proj_y - 45, 90, 90);
221 location_pixmaps_.push_back(pixmap);
222 image_ids_.push_back(track_el.first.image_id);
223 reproj_errors_.push_back(reproj_error);
224 image_names_.push_back(
image.Name());
230 void PointViewerWidget::closeEvent(QCloseEvent*
event) {
232 location_pixmaps_.clear();
234 reproj_errors_.clear();
235 image_names_.clear();
239 void PointViewerWidget::ResizeInfoTable() {
241 info_table_->resizeColumnsToContents();
243 info_table_->horizontalHeader()->height() + 2 * info_table_->frameWidth();
244 for (
int i = 0; i < info_table_->rowCount(); i++) {
245 height += info_table_->rowHeight(i);
247 info_table_->setFixedHeight(
height);
250 void PointViewerWidget::ClearLocations() {
251 while (location_table_->rowCount() > 0) {
252 location_table_->removeRow(0);
254 for (
auto location_label : location_labels_) {
255 delete location_label;
257 location_labels_.clear();
260 void PointViewerWidget::UpdateImages() {
263 location_table_->setRowCount(
static_cast<int>(location_pixmaps_.size()));
265 for (
size_t i = 0; i < location_pixmaps_.size(); ++i) {
266 QLabel* image_id_label =
new QLabel(QString::number(image_ids_[i]),
this);
267 image_id_label->setAlignment(Qt::AlignCenter);
268 location_table_->setCellWidget(i, 0, image_id_label);
269 location_labels_.push_back(image_id_label);
271 QLabel* error_label =
new QLabel(QString::number(reproj_errors_[i]),
this);
272 error_label->setAlignment(Qt::AlignCenter);
273 location_table_->setCellWidget(i, 1, error_label);
274 location_labels_.push_back(error_label);
276 const QPixmap& pixmap = location_pixmaps_[i];
277 QLabel* image_label =
new QLabel(
this);
278 image_label->setPixmap(
279 pixmap.scaledToWidth(zoom_ * pixmap.width(), Qt::FastTransformation));
280 location_table_->setCellWidget(i, 2, image_label);
281 location_table_->resizeRowToContents(i);
282 location_labels_.push_back(image_label);
284 QLabel* image_name_label =
new QLabel(image_names_[i].c_str(),
this);
285 image_name_label->setAlignment(Qt::AlignCenter);
286 location_table_->setCellWidget(i, 3, image_name_label);
287 location_labels_.push_back(image_name_label);
289 location_table_->resizeColumnToContents(2);
292 void PointViewerWidget::ZoomIn() {
297 void PointViewerWidget::ZoomOut() {
302 void PointViewerWidget::Delete() {
303 QMessageBox::StandardButton reply = QMessageBox::question(
304 this,
"", tr(
"Do you really want to delete this point?"),
305 QMessageBox::Yes | QMessageBox::No);
306 if (reply == QMessageBox::Yes) {
std::shared_ptr< core::Tensor > image
bool Read(const std::string &path, const bool as_rgb=true)
std::shared_ptr< std::string > image_path
const Eigen::Vector2d & XY() const
void DeletePoint3D(const point3D_t point3D_id)
bool ExistsPoint3D(const point3D_t point3D_id) const
QTextStream & endl(QTextStream &stream)
Tensor Minimum(const Tensor &input, const Tensor &other)
Computes the element-wise minimum of input and other. The tensors must have same data type and device...
static const std::string path
QImage BitmapToQImageRGB(const Bitmap &bitmap)
std::string JoinPaths(T const &... paths)
const point3D_t kInvalidPoint3DId
Eigen::Vector2d ProjectPointToImage(const Eigen::Vector3d &point3D, const Eigen::Matrix3x4d &proj_matrix, const Camera &camera)
constexpr Rgb red(MAX, 0, 0)
constexpr Rgb green(0, MAX, 0)
std::string to_string(const T &n)