11 #include "ui/qt_utils.h"
12 #include "ui/render_options.h"
25 #define SELECTION_BUFFER_IMAGE_IDX 0
26 #define SELECTION_BUFFER_POINT_IDX 1
40 inline size_t RGBToIndex(
const uint8_t r,
const uint8_t g,
const uint8_t b) {
41 return static_cast<size_t>(r) +
static_cast<size_t>(g) * 256 +
42 static_cast<size_t>(b) * 65536;
46 inline Eigen::Vector4f IndexToRGB(
const size_t index) {
47 Eigen::Vector4f
color;
48 color(0) = ((index & 0x000000FF) >> 0) / 255.0f;
49 color(1) = ((index & 0x0000FF00) >> 8) / 255.0f;
50 color(2) = ((index & 0x00FF0000) >> 16) / 255.0f;
56 const colmap::Image&
image,
57 const colmap::Camera& camera,
58 const float image_size,
59 const Eigen::Vector4d& plane_color,
60 const Eigen::Vector4d& frame_color) {
62 const float kBaseCameraWidth = 1024.0f;
63 const float image_width = image_size * camera.Width() / kBaseCameraWidth;
64 const float image_height = image_width *
65 static_cast<float>(camera.Height()) /
66 static_cast<float>(camera.Width());
67 const float image_extent =
std::max(image_width, image_height);
68 const float camera_extent =
std::max(camera.Width(), camera.Height());
69 const float camera_extent_world =
70 static_cast<float>(camera.ImageToWorldThreshold(camera_extent));
71 const float focal_length = 2.0f * image_extent / camera_extent_world;
75 Eigen::Vector3d(plane_color(0), plane_color(1), plane_color(2)));
78 Eigen::Vector3d(frame_color(0), frame_color(1), frame_color(2)));
87 float pixelSize_mm = image_size;
93 iParams.
arrayWidth =
static_cast<int>(camera.Width());
94 iParams.
arrayHeight =
static_cast<int>(camera.Height());
95 iParams.
principal_point[0] =
static_cast<float>(camera.PrincipalPointX());
96 iParams.
principal_point[1] =
static_cast<float>(camera.PrincipalPointY());
100 const Eigen::Matrix<float, 3, 4> proj_matrix =
101 image.InverseProjectionMatrix().cast<
float>();
102 Eigen::Matrix3f rotation = proj_matrix.leftCols<3>();
103 Eigen::Vector3f translation = proj_matrix.rightCols<1>();
116 statusbar_status_label(nullptr),
119 image_viewer_widget_(
122 focus_distance_(kInitFocusDistance),
123 selected_image_id_(kInvalidImageId),
124 selected_point3D_id_(kInvalidPoint3DId),
126 cloud_sparse_(nullptr),
127 main_sensors_(nullptr) {
140 point_line_data_.
clear();
141 image_line_data_.
clear();
143 movie_grabber_sensors_.clear();
147 if (movie_grabber_widget_) {
148 movie_grabber_widget_->
views.clear();
154 delete cloud_sparse_;
155 cloud_sparse_ =
nullptr;
159 delete main_sensors_;
160 main_sensors_ =
nullptr;
182 "%d Images - %d Points",
static_cast<int>(
reg_image_ids.size()),
183 static_cast<int>(
points3D.size())));
195 selected_image_id_ = kInvalidImageId;
196 selected_point3D_id_ = kInvalidPoint3DId;
202 options_->render->projection_type =
203 colmap::RenderOptions::ProjectionType::PERSPECTIVE;
205 options_->render->projection_type =
206 colmap::RenderOptions::ProjectionType::ORTHOGRAPHIC;
208 return options_->render->projection_type;
212 point_colormap_.reset(colormap);
216 image_colormap_.reset(colormap);
221 UploadMovieGrabberData();
248 const float prev_focus_distance = focus_distance_;
250 focus_distance_ -= diff;
253 diff = prev_focus_distance - focus_distance_;
256 diff = prev_focus_distance - focus_distance_;
259 static_cast<double>(focus_distance_));
272 cloud_sparse_->
setPointSize(
static_cast<unsigned>(point_size_));
286 UploadMovieGrabberData();
303 unsigned subEntityID,
315 if (!main_sensors_ || !cloud_sparse_) {
319 if (!main_sensors_->
find(subEntityID)) {
330 UploadImageData(
true);
331 UploadPointData(
true);
333 std::size_t selected_index = 0;
338 RGBToIndex(plane_color.
r, plane_color.
g, plane_color.
b);
341 selected_index =
static_cast<std::size_t
>(subEntityID);
342 if (selected_index >= cloud_sparse_->
size()) {
344 "[ModelViewerWidget::SelectObject] Invalid picking point "
356 selected_index = RGBToIndex(pointColor.
r, pointColor.
g, pointColor.
b);
362 colmap::image_t last_selected_image_id = selected_image_id_;
364 if (selected_index < selection_buffer_.size()) {
365 const char buffer_type = selection_buffer_[selected_index].second;
367 selected_image_id_ =
static_cast<image_t
>(
368 selection_buffer_[selected_index].first);
369 selected_point3D_id_ = kInvalidPoint3DId;
372 selected_image_id_ = kInvalidImageId;
373 selected_point3D_id_ = selection_buffer_[selected_index].first;
376 selected_image_id_ = kInvalidImageId;
377 selected_point3D_id_ = kInvalidPoint3DId;
378 image_viewer_widget_->hide();
381 selected_image_id_ = kInvalidImageId;
382 selected_point3D_id_ = kInvalidPoint3DId;
383 image_viewer_widget_->hide();
386 selection_buffer_.clear();
391 UploadPointConnectionData();
392 UploadImageConnectionData();
396 if (selected_image_id_ == kInvalidImageId) {
398 ccHObject* obj = getSelectedCamera(last_selected_image_id);
404 ccHObject* obj = getSelectedCamera(selected_image_id_);
415 selected_movie_grabber_view_ = view_idx;
417 UploadMovieGrabberData();
429 colmap::RenderOptions::ProjectionType::PERSPECTIVE) {
430 const int reply = QMessageBox::question(
432 tr(
"You must use perspective projection, "
433 "do you want to switch to perspective mode now?"),
434 QMessageBox::Yes | QMessageBox::No);
435 if (reply == QMessageBox::Yes) {
444 movie_grabber_widget_->show();
448 point_viewer_widget_->
Show(point3D_id);
473 point_size_ = point_size;
480 cloud_sparse_->
setPointSize(
static_cast<unsigned>(point_size_));
491 image_size_ = image_size;
515 void ModelViewerWidget::SetupView() {
521 void ModelViewerWidget::Upload() {
528 UploadMovieGrabberData();
529 UploadPointConnectionData();
530 UploadImageConnectionData();
543 if (autoZoom && bbox_.
isValid()) {
550 void ModelViewerWidget::UploadPointData(
const bool selection_mode) {
551 if (!cloud_sparse_) {
553 if (!cloud_sparse_) {
555 "[ModelViewerWidget::UploadPointData] Not enough memory!");
560 cloud_sparse_->
clear();
563 resetPointCloud(cloud_sparse_);
581 const size_t min_track_len =
582 static_cast<size_t>(options_->render->min_track_len);
584 if (selected_image_id_ == kInvalidImageId &&
585 images.count(selected_image_id_) == 0) {
586 for (
const auto& point3D :
points3D) {
587 if (point3D.second.Error() <= options_->render->max_error &&
588 point3D.second.Track().Length() >= min_track_len) {
596 cloud_sparse_->
addPoint(painter_point);
598 Eigen::Vector4d
color;
599 if (selection_mode) {
600 const size_t index = selection_buffer_.size();
603 color = IndexToRGB(index).cast<
double>();
605 }
else if (point3D.first == selected_point3D_id_) {
608 color = point_colormap_
609 ->ComputeColor(point3D.first,
620 const auto& selected_image =
images[selected_image_id_];
621 for (
const auto& point3D :
points3D) {
622 if (point3D.second.Error() <= options_->render->max_error &&
623 point3D.second.Track().Length() >= min_track_len) {
631 cloud_sparse_->
addPoint(painter_point);
633 Eigen::Vector4d
color;
634 if (selection_mode) {
635 const size_t index = selection_buffer_.size();
638 color = IndexToRGB(index).cast<
double>();
639 }
else if (selected_image.HasPoint3D(point3D.first)) {
641 }
else if (point3D.first == selected_point3D_id_) {
644 color = point_colormap_
645 ->ComputeColor(point3D.first,
657 if (app_ && objContext.
parent) {
661 drawPointCloud(cloud_sparse_);
664 void ModelViewerWidget::UploadPointConnectionData() {
665 point_line_data_.
clear();
666 if (selected_point3D_id_ == kInvalidPoint3DId) {
668 resetLines(point_line_data_);
672 const auto& point3D =
points3D[selected_point3D_id_];
673 if (point3D.Track().Elements().empty()) {
674 resetLines(point_line_data_);
679 point_line_data_.
points_.push_back(point3D.XYZ());
683 for (
const auto& track_el : point3D.Track().Elements()) {
684 const Image& conn_image =
images[track_el.image_id];
685 const Eigen::Vector3d conn_proj_center = conn_image.ProjectionCenter();
686 point_line_data_.
points_.push_back(conn_proj_center);
693 drawLines(point_line_data_);
696 void ModelViewerWidget::UploadImageData(
const bool selection_mode) {
697 std::size_t lastSensorNum = sensors_.size();
700 if (curSensorNum == 0) {
701 resetCameraSensors(sensors_);
705 if (lastSensorNum < curSensorNum) {
706 sensors_.reserve(curSensorNum);
707 }
else if (lastSensorNum > curSensorNum) {
709 lastSensorNum = sensors_.size();
712 std::size_t cameraIndex = 0;
717 Eigen::Vector4f plane_color;
718 Eigen::Vector4f frame_color;
719 if (selection_mode) {
720 const size_t index = selection_buffer_.size();
721 selection_buffer_.push_back(
723 plane_color = frame_color = IndexToRGB(index);
725 if (image_id == selected_image_id_) {
729 image_colormap_->ComputeColor(
image, &plane_color,
737 if (cameraIndex < lastSensorNum) {
738 sensor = sensors_[cameraIndex];
741 sensors_.push_back(sensor);
748 sensor->
setName(QString::number(image_id));
749 BuildImageModel(sensor,
image, camera, image_size_,
750 plane_color.cast<
double>(), frame_color.cast<
double>());
754 drawCameraSensors(sensors_);
757 void ModelViewerWidget::UploadImageConnectionData() {
758 std::vector<image_t> image_ids;
760 image_line_data_.
clear();
762 if (selected_image_id_ != kInvalidImageId) {
764 image_ids.push_back(selected_image_id_);
765 }
else if (options_->render->image_connections) {
769 resetLines(image_line_data_);
773 for (
const image_t image_id : image_ids) {
776 const Eigen::Vector3d proj_center =
image.ProjectionCenter();
779 std::unordered_set<image_t> conn_image_ids;
781 for (
const Point2D& point2D :
image.Points2D()) {
782 if (point2D.HasPoint3D()) {
784 for (
const auto& track_elem : point3D.Track().Elements()) {
785 conn_image_ids.insert(track_elem.image_id);
791 int centerIndex =
static_cast<int>(image_line_data_.
points_.size());
792 image_line_data_.
points_.push_back(proj_center);
795 int index = centerIndex;
796 for (
const image_t conn_image_id : conn_image_ids) {
797 const Image& conn_image =
images[conn_image_id];
798 const Eigen::Vector3d conn_proj_center =
799 conn_image.ProjectionCenter();
800 image_line_data_.
points_.push_back(conn_proj_center);
801 image_line_data_.
lines_.push_back(
809 drawLines(image_line_data_);
812 void ModelViewerWidget::UploadMovieGrabberData() {
813 std::size_t lastSensorNum = movie_grabber_sensors_.size();
814 std::size_t curSensorNum = movie_grabber_widget_->
views.size();
816 if (lastSensorNum < curSensorNum) {
817 movie_grabber_sensors_.reserve(curSensorNum);
818 }
else if (lastSensorNum > curSensorNum) {
819 std::vector<colmap::image_t> image_ids;
820 for (
const Image&
image : movie_grabber_widget_->
views) {
821 image_ids.push_back(
image.ImageId());
823 updateSensors(movie_grabber_sensors_, image_ids);
824 lastSensorNum = movie_grabber_sensors_.size();
827 movie_grabber_path_.
clear();
829 if (curSensorNum > 0) {
830 const Image& image0 = movie_grabber_widget_->
views[0];
831 Eigen::Vector3d prev_proj_center = image0.ProjectionCenter();
833 for (
size_t i = 1; i < movie_grabber_widget_->
views.size(); ++i) {
834 const Image&
image = movie_grabber_widget_->
views[i];
835 const Eigen::Vector3d curr_proj_center =
image.ProjectionCenter();
836 movie_grabber_path_.
points_.push_back(prev_proj_center);
837 movie_grabber_path_.
points_.push_back(curr_proj_center);
838 std::size_t start = movie_grabber_path_.
points_.size() - 2;
839 std::size_t end = movie_grabber_path_.
points_.size() - 1;
841 prev_proj_center = curr_proj_center;
848 const unsigned long kDefaultImageWdith = 2048;
849 const unsigned long kDefaultImageHeight = 1536;
850 const double focal_length =
855 camera.InitializeWithId(SimplePinholeCameraModel::model_id,
856 focal_length, kDefaultImageWdith,
857 kDefaultImageHeight);
860 std::size_t index = 0;
861 for (
size_t i = 0; i < curSensorNum; ++i) {
862 const Image&
image = movie_grabber_widget_->
views[i];
863 Eigen::Vector4d plane_color;
864 Eigen::Vector4d frame_color;
865 if (i == selected_movie_grabber_view_) {
874 if (index < lastSensorNum) {
875 sensor = movie_grabber_sensors_[index];
878 movie_grabber_sensors_.push_back(sensor);
886 BuildImageModel(sensor,
image, camera, image_size_, plane_color,
891 drawLines(movie_grabber_path_);
892 drawCameraSensors(movie_grabber_sensors_);
894 resetLines(movie_grabber_path_);
895 resetCameraSensors(movie_grabber_sensors_);
902 void ModelViewerWidget::drawPointCloud(
ccPointCloud* cloud) {
914 cloud->
setPointSize(
static_cast<unsigned>(point_size_));
925 void ModelViewerWidget::resetPointCloud(
ccPointCloud* cloud) {
935 void ModelViewerWidget::drawLines(geometry::LineSet& lineset) {
936 if (!lineset.IsEmpty()) {
938 if (lineset.isColorOverridden()) {
939 context.defaultPolylineColor = lineset.getTempColor();
940 }
else if (lineset.colorsShown() && lineset.hasColors()) {
946 context.viewID = QString::number(lineset.getUniqueID(), 10);
947 lineset.setRedrawFlagRecursive(
true);
957 void ModelViewerWidget::resetLines(geometry::LineSet& lineset) {
961 void ModelViewerWidget::drawCameraSensors(
962 std::vector<ccCameraSensor*>& sensors) {
963 if (!main_sensors_) {
964 main_sensors_ =
new ccHObject(
"SensorsGroup");
969 if (main_sensors_ && app_ &&
974 for (std::size_t i = 0; i < sensors.size(); ++i) {
975 if (!sensors[i])
continue;
976 if (main_sensors_ && !main_sensors_->
find(sensors[i]->getUniqueID())) {
977 sensors[i]->setLocked(
true);
978 main_sensors_->
addChild(sensors[i]);
980 sensors[i]->setVisible(
true);
981 sensors[i]->setEnabled(
true);
982 sensors[i]->setRedrawFlagRecursive(
true);
989 if (main_sensors_ && app_ && objContext.
parent) {
1003 void ModelViewerWidget::resetCameraSensors(
1004 std::vector<ccCameraSensor*>& sensors) {
1005 clearSensors(sensors);
1008 void ModelViewerWidget::clearSensors(std::vector<ccCameraSensor*>& sensors) {
1009 for (std::size_t i = 0; i < sensors.size(); ++i) {
1010 if (!sensors[i])
continue;
1012 app_->
db()->
find(
static_cast<int>(sensors[i]->getUniqueID()))) {
1013 sensors[i]->setLocked(
false);
1014 if (sensors[i]->isSelected()) {
1021 sensors[i] =
nullptr;
1029 main_sensors_ =
nullptr;
1036 void ModelViewerWidget::updateSensors(
1037 std::vector<ccCameraSensor*>& sensors,
1038 const std::vector<colmap::image_t>& image_ids) {
1039 if (sensors.size() > image_ids.size()) {
1040 std::vector<ccCameraSensor*> toBeDeleted;
1041 std::vector<ccCameraSensor*> preserved;
1046 colmap::image_t sensorId = sensor->
getName().toUInt();
1047 if (std::find(image_ids.begin(), image_ids.end(), sensorId) ==
1049 toBeDeleted.push_back(sensor);
1051 preserved.push_back(sensor);
1055 if (!toBeDeleted.empty()) {
1058 sensors.push_back(sensor);
1061 clearSensors(toBeDeleted);
1066 ccHObject* ModelViewerWidget::getSelectedCamera(colmap::image_t selected_id) {
1070 if (obj->
getName().toUInt() == selected_id) {
constexpr PointCoordinateType PC_ONE
'1' as a PointCoordinateType value
float PointCoordinateType
Type of the coordinates of a (N-D) point.
std::shared_ptr< core::Tensor > image
cmdLineReadable * params[]
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
ccHObjectContext removeObjectTemporarilyFromDBTree(ccHObject *obj) override
Removes object temporarily from DB tree.
ccDBRoot * db()
Returns real 'dbRoot' object.
void addToDB(const QStringList &filenames, QString fileFilter=QString(), bool displayDialog=true)
void doActionOrthogonalProjection()
void removeFromDB(ccHObject *obj, bool autoDelete=true) override
Removes an entity from main db tree.
void doActionPerspectiveProjection()
void putObjectBackIntoDBTree(ccHObject *obj, const ccHObjectContext &context) override
Adds back object to DB tree.
virtual ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Camera (projective) sensor.
const ecvColor::Rgb & getPlaneColor() const
static float ConvertFocalMMToPix(float focal_mm, float ccdPixelSize_mm)
Helper: converts camera focal from mm to pixels.
void setIntrinsicParameters(const IntrinsicParameters ¶ms)
Sets intrinsic parameters.
void setPlaneColor(ecvColor::Rgb color)
void expandElement(ccHObject *object, bool state)
Expands tree at a given node.
void unselectEntity(ccHObject *obj)
Unselects a given entity.
void selectEntity(ccHObject *obj, bool forceAdditiveSelection=false)
Selects a given entity.
ccHObject * find(int uniqueID) const
Finds an element in DB.
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
static ccGLMatrixTpl< float > FromEigenMatrix3(const Eigen::Matrix< float, 3, 3 > &mat)
T * data()
Returns a pointer to internal data.
void setTranslation(const Vector3Tpl< float > &Tr)
Sets translation (float version)
Float version of ccGLMatrixTpl.
Double version of ccGLMatrixTpl.
void setPointSize(unsigned size=0)
Sets point size.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
static ccCameraSensor * ToCameraSensor(ccHObject *obj)
Hierarchical CLOUDVIEWER Object.
ccHObject * find(unsigned uniqueID)
Finds an entity in this object hierarchy.
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.
void setRedrawFlagRecursive(bool redraw=false)
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
virtual void setLocked(bool state)
Sets the "enabled" property.
virtual QString getName() const
Returns object name.
virtual unsigned getUniqueID() const
Returns object unique ID.
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
bool isKindOf(CV_CLASS_ENUM type) const
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
virtual bool IsEmpty() const override
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
ecvColor::Rgb & getPointColorPtr(size_t pointIndex)
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void clear() override
Clears the entity from all its points and features.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
void setFrameColor(ecvColor::Rgb color)
virtual void setRigidTransformation(const ccGLMatrix &mat)
void setGraphicScale(PointCoordinateType scale)
Sets the sensor graphic representation scale.
void clear()
Resets the bounding box.
bool isValid() const
Returns whether bounding box is valid or not.
CCVector3 * getPointPtr(size_t index)
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
std::vector< Eigen::Vector3d > points_
Points coordinates.
std::vector< Eigen::Vector2i > lines_
Lines denoted by the index of points forming the line.
LineSet & PaintUniformColor(const Eigen::Vector3d &color)
Assigns each line in the LineSet the same color.
constexpr static RgbTpl FromEigen(const Eigen::Vector3d &t)
static const ParamStruct & Parameters()
Returns the stored values of each parameter.
__host__ __device__ int2 abs(int2 v)
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
Generic file read and write utility for python interface.
bool GreaterThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
float DegreesToRadians(int degrees)
Convert degrees to radians.
colmap::ImageColormapBase ImageColormapBase
colmap::OptionManager OptionManager
colmap::PointColormapBase PointColormapBase
Eigen::Matrix< Index, 2, 1 > Vector2i
Intrinsic parameters of the camera sensor.
Backup "context" for an object.