23 model_viewer_widget_(model_viewer_widget),
26 zoom_(250.0 / 1024.0) {
27 setWindowFlags(Qt::Window);
28 resize(parent->size().width() - 20, parent->size().height() - 20);
31 font.setPointSize(10);
34 QGridLayout* grid =
new QGridLayout(
this);
35 grid->setContentsMargins(5, 5, 5, 5);
37 info_table_ =
new QTableWidget(
this);
39 info_table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
40 info_table_->setSelectionMode(QAbstractItemView::SingleSelection);
41 info_table_->setShowGrid(
true);
42 info_table_->horizontalHeader()->setStretchLastSection(
true);
43 info_table_->horizontalHeader()->setVisible(
false);
44 info_table_->verticalHeader()->setVisible(
false);
45 info_table_->verticalHeader()->setDefaultSectionSize(18);
47 info_table_->setColumnCount(2);
48 info_table_->setRowCount(3);
50 info_table_->setItem(0, 0,
new QTableWidgetItem(
"position"));
51 xyz_item_ =
new QTableWidgetItem();
52 info_table_->setItem(0, 1, xyz_item_);
54 info_table_->setItem(1, 0,
new QTableWidgetItem(
"color"));
55 rgb_item_ =
new QTableWidgetItem();
56 info_table_->setItem(1, 1, rgb_item_);
58 info_table_->setItem(2, 0,
new QTableWidgetItem(
"error"));
59 error_item_ =
new QTableWidgetItem();
60 info_table_->setItem(2, 1, error_item_);
62 grid->addWidget(info_table_, 0, 0);
64 location_table_ =
new QTableWidget(
this);
65 location_table_->setColumnCount(4);
66 QStringList table_header;
67 table_header <<
"image_id"
71 location_table_->setHorizontalHeaderLabels(table_header);
72 location_table_->resizeColumnsToContents();
73 location_table_->setShowGrid(
true);
74 location_table_->horizontalHeader()->setStretchLastSection(
true);
75 location_table_->verticalHeader()->setVisible(
true);
76 location_table_->setSelectionMode(QAbstractItemView::NoSelection);
77 location_table_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
78 location_table_->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
79 location_table_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
81 grid->addWidget(location_table_, 1, 0);
83 QHBoxLayout* button_layout =
new QHBoxLayout();
85 zoom_in_button_ =
new QPushButton(tr(
"+"),
this);
86 zoom_in_button_->setFont(font);
87 zoom_in_button_->setFixedWidth(50);
88 button_layout->addWidget(zoom_in_button_);
89 connect(zoom_in_button_, &QPushButton::released,
this,
90 &PointViewerWidget::ZoomIn);
92 zoom_out_button_ =
new QPushButton(tr(
"-"),
this);
93 zoom_out_button_->setFont(font);
94 zoom_out_button_->setFixedWidth(50);
95 button_layout->addWidget(zoom_out_button_);
96 connect(zoom_out_button_, &QPushButton::released,
this,
97 &PointViewerWidget::ZoomOut);
99 delete_button_ =
new QPushButton(tr(
"Delete"),
this);
100 button_layout->addWidget(delete_button_);
101 connect(delete_button_, &QPushButton::released,
this,
102 &PointViewerWidget::Delete);
104 grid->addLayout(button_layout, 2, 0, Qt::AlignRight);
108 location_pixmaps_.clear();
110 reproj_errors_.clear();
111 image_names_.clear();
113 if (model_viewer_widget_->
points3D.count(point3D_id) == 0) {
122 point3D_id_ = point3D_id;
129 const auto& point3D = model_viewer_widget_->
points3D[point3D_id];
131 xyz_item_->setText(QString::number(point3D.X()) +
", " +
132 QString::number(point3D.Y()) +
", " +
133 QString::number(point3D.Z()));
134 rgb_item_->setText(QString::number(point3D.Color(0)) +
", " +
135 QString::number(point3D.Color(1)) +
", " +
136 QString::number(point3D.Color(2)));
137 error_item_->setText(QString::number(point3D.Error()));
143 std::vector<std::pair<TrackElement, std::string>>
144 track_idx_image_name_pairs;
145 track_idx_image_name_pairs.reserve(point3D.Track().Length());
146 for (
const auto& track_el : point3D.Track().Elements()) {
148 track_idx_image_name_pairs.emplace_back(track_el,
image.Name());
151 std::sort(track_idx_image_name_pairs.begin(),
152 track_idx_image_name_pairs.end(),
153 [](
const std::pair<TrackElement, std::string>& track_el1,
154 const std::pair<TrackElement, std::string>& track_el2) {
155 return track_el1.second < track_el2.second;
160 for (
const auto& track_el : track_idx_image_name_pairs) {
162 model_viewer_widget_->
images[track_el.first.image_id];
164 const Point2D& point2D =
image.Point2D(track_el.first.point2D_idx);
166 point3D.XYZ(),
image.ProjectionMatrix(), camera);
167 const double reproj_error = (point2D.
XY() - proj_point2D).norm();
172 std::cerr <<
"ERROR: Cannot read image at path " <<
path
180 QPainter painter(&pixmap);
181 painter.setRenderHint(QPainter::Antialiasing);
188 const int kCrossSize = 15;
189 const int x =
static_cast<int>(std::round(point2D.
X()));
190 const int y =
static_cast<int>(std::round(point2D.
Y()));
191 painter.drawLine(
x - kCrossSize,
y - kCrossSize,
x + kCrossSize,
193 painter.drawLine(
x - kCrossSize,
y + kCrossSize,
x + kCrossSize,
199 const int proj_x =
static_cast<int>(std::round(proj_point2D.x()));
200 const int proj_y =
static_cast<int>(std::round(proj_point2D.y()));
201 painter.drawEllipse(proj_x - 5, proj_y - 5, 10, 10);
202 painter.drawEllipse(proj_x - 15, proj_y - 15, 30, 30);
203 painter.drawEllipse(proj_x - 45, proj_y - 45, 90, 90);
205 location_pixmaps_.push_back(pixmap);
206 image_ids_.push_back(track_el.first.image_id);
207 reproj_errors_.push_back(reproj_error);
208 image_names_.push_back(
image.Name());
214 void PointViewerWidget::closeEvent(QCloseEvent*
event) {
216 location_pixmaps_.clear();
218 reproj_errors_.clear();
219 image_names_.clear();
223 void PointViewerWidget::ResizeInfoTable() {
225 info_table_->resizeColumnsToContents();
226 int height = info_table_->horizontalHeader()->height() +
227 2 * info_table_->frameWidth();
228 for (
int i = 0; i < info_table_->rowCount(); i++) {
229 height += info_table_->rowHeight(i);
231 info_table_->setFixedHeight(
height);
234 void PointViewerWidget::ClearLocations() {
235 while (location_table_->rowCount() > 0) {
236 location_table_->removeRow(0);
238 for (
auto location_label : location_labels_) {
239 delete location_label;
241 location_labels_.clear();
244 void PointViewerWidget::UpdateImages() {
247 location_table_->setRowCount(
static_cast<int>(location_pixmaps_.size()));
249 for (
size_t i = 0; i < location_pixmaps_.size(); ++i) {
250 QLabel* image_id_label =
251 new QLabel(QString::number(image_ids_[i]),
this);
252 image_id_label->setAlignment(Qt::AlignCenter);
253 location_table_->setCellWidget(i, 0, image_id_label);
254 location_labels_.push_back(image_id_label);
256 QLabel* error_label =
257 new QLabel(QString::number(reproj_errors_[i]),
this);
258 error_label->setAlignment(Qt::AlignCenter);
259 location_table_->setCellWidget(i, 1, error_label);
260 location_labels_.push_back(error_label);
262 const QPixmap& pixmap = location_pixmaps_[i];
263 QLabel* image_label =
new QLabel(
this);
264 image_label->setPixmap(pixmap.scaledToWidth(zoom_ * pixmap.width(),
265 Qt::FastTransformation));
266 location_table_->setCellWidget(i, 2, image_label);
267 location_table_->resizeRowToContents(i);
268 location_labels_.push_back(image_label);
270 QLabel* image_name_label =
new QLabel(image_names_[i].c_str(),
this);
271 image_name_label->setAlignment(Qt::AlignCenter);
272 location_table_->setCellWidget(i, 3, image_name_label);
273 location_labels_.push_back(image_name_label);
275 location_table_->resizeColumnToContents(2);
278 void PointViewerWidget::ZoomIn() {
283 void PointViewerWidget::ZoomOut() {
288 void PointViewerWidget::Delete() {
289 QMessageBox::StandardButton reply = QMessageBox::question(
290 this,
"", tr(
"Do you really want to delete this point?"),
291 QMessageBox::Yes | QMessageBox::No);
292 if (reply == QMessageBox::Yes) {
std::shared_ptr< core::Tensor > image
The Image class stores image with customizable width, height, num of channels and bytes per channel.
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
std::string JoinPaths(T const &...paths)
Generic file read and write utility for python interface.
QImage BitmapToQImageRGB(const Bitmap &bitmap)
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)