| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "base/camera_rig.h" |
|
|
| #include "util/misc.h" |
|
|
| namespace colmap { |
|
|
| CameraRig::CameraRig() {} |
|
|
| size_t CameraRig::NumCameras() const { return rig_cameras_.size(); } |
|
|
| size_t CameraRig::NumSnapshots() const { return snapshots_.size(); } |
|
|
| bool CameraRig::HasCamera(const camera_t camera_id) const { |
| return rig_cameras_.count(camera_id); |
| } |
|
|
| camera_t CameraRig::RefCameraId() const { return ref_camera_id_; } |
|
|
| void CameraRig::SetRefCameraId(const camera_t camera_id) { |
| CHECK(HasCamera(camera_id)); |
| ref_camera_id_ = camera_id; |
| } |
|
|
| std::vector<camera_t> CameraRig::GetCameraIds() const { |
| std::vector<camera_t> rig_camera_ids; |
| rig_camera_ids.reserve(NumCameras()); |
| for (const auto& rig_camera : rig_cameras_) { |
| rig_camera_ids.push_back(rig_camera.first); |
| } |
| return rig_camera_ids; |
| } |
|
|
| const std::vector<std::vector<image_t>>& CameraRig::Snapshots() const { |
| return snapshots_; |
| } |
|
|
| void CameraRig::AddCamera(const camera_t camera_id, |
| const Eigen::Vector4d& rel_qvec, |
| const Eigen::Vector3d& rel_tvec) { |
| CHECK(!HasCamera(camera_id)); |
| CHECK_EQ(NumSnapshots(), 0); |
| RigCamera rig_camera; |
| rig_camera.rel_qvec = rel_qvec; |
| rig_camera.rel_tvec = rel_tvec; |
| rig_cameras_.emplace(camera_id, rig_camera); |
| } |
|
|
| void CameraRig::AddSnapshot(const std::vector<image_t>& image_ids) { |
| CHECK(!image_ids.empty()); |
| CHECK_LE(image_ids.size(), NumCameras()); |
| CHECK(!VectorContainsDuplicateValues(image_ids)); |
| snapshots_.push_back(image_ids); |
| } |
|
|
| void CameraRig::Check(const Reconstruction& reconstruction) const { |
| CHECK(HasCamera(ref_camera_id_)); |
|
|
| for (const auto& rig_camera : rig_cameras_) { |
| CHECK(reconstruction.ExistsCamera(rig_camera.first)); |
| } |
|
|
| std::unordered_set<image_t> all_image_ids; |
| for (const auto& snapshot : snapshots_) { |
| CHECK(!snapshot.empty()); |
| CHECK_LE(snapshot.size(), NumCameras()); |
| bool has_ref_camera = false; |
| for (const auto image_id : snapshot) { |
| CHECK(reconstruction.ExistsImage(image_id)); |
| CHECK_EQ(all_image_ids.count(image_id), 0); |
| all_image_ids.insert(image_id); |
| const auto& image = reconstruction.Image(image_id); |
| CHECK(HasCamera(image.CameraId())); |
| if (image.CameraId() == ref_camera_id_) { |
| has_ref_camera = true; |
| } |
| } |
| CHECK(has_ref_camera); |
| } |
| } |
|
|
| Eigen::Vector4d& CameraRig::RelativeQvec(const camera_t camera_id) { |
| return rig_cameras_.at(camera_id).rel_qvec; |
| } |
|
|
| const Eigen::Vector4d& CameraRig::RelativeQvec(const camera_t camera_id) const { |
| return rig_cameras_.at(camera_id).rel_qvec; |
| } |
|
|
| Eigen::Vector3d& CameraRig::RelativeTvec(const camera_t camera_id) { |
| return rig_cameras_.at(camera_id).rel_tvec; |
| } |
|
|
| const Eigen::Vector3d& CameraRig::RelativeTvec(const camera_t camera_id) const { |
| return rig_cameras_.at(camera_id).rel_tvec; |
| } |
|
|
| double CameraRig::ComputeScale(const Reconstruction& reconstruction) const { |
| CHECK_GT(NumSnapshots(), 0); |
| CHECK_GT(NumCameras(), 0); |
| double scaling_factor = 0; |
| size_t num_dists = 0; |
| std::vector<Eigen::Vector3d> rel_proj_centers(NumCameras()); |
| std::vector<Eigen::Vector3d> abs_proj_centers(NumCameras()); |
| for (const auto& snapshot : snapshots_) { |
| |
| for (size_t i = 0; i < NumCameras(); ++i) { |
| const auto& image = reconstruction.Image(snapshot[i]); |
| rel_proj_centers[i] = ProjectionCenterFromPose( |
| RelativeQvec(image.CameraId()), RelativeTvec(image.CameraId())); |
| abs_proj_centers[i] = image.ProjectionCenter(); |
| } |
|
|
| |
| for (size_t i = 0; i < NumCameras(); ++i) { |
| for (size_t j = 0; j < i; ++j) { |
| const double rel_dist = |
| (rel_proj_centers[i] - rel_proj_centers[j]).norm(); |
| const double abs_dist = |
| (abs_proj_centers[i] - abs_proj_centers[j]).norm(); |
| const double kMinDist = 1e-6; |
| if (rel_dist > kMinDist && abs_dist > kMinDist) { |
| scaling_factor += rel_dist / abs_dist; |
| num_dists += 1; |
| } |
| } |
| } |
| } |
|
|
| if (num_dists == 0) { |
| return std::numeric_limits<double>::quiet_NaN(); |
| } |
|
|
| return scaling_factor / num_dists; |
| } |
|
|
| bool CameraRig::ComputeRelativePoses(const Reconstruction& reconstruction) { |
| CHECK_GT(NumSnapshots(), 0); |
| CHECK_NE(ref_camera_id_, kInvalidCameraId); |
|
|
| for (auto& rig_camera : rig_cameras_) { |
| rig_camera.second.rel_tvec = Eigen::Vector3d::Zero(); |
| } |
|
|
| EIGEN_STL_UMAP(camera_t, std::vector<Eigen::Vector4d>) rel_qvecs; |
|
|
| for (const auto& snapshot : snapshots_) { |
| |
| const Image* ref_image = nullptr; |
| for (const auto image_id : snapshot) { |
| const auto& image = reconstruction.Image(image_id); |
| if (image.CameraId() == ref_camera_id_) { |
| ref_image = ℑ |
| } |
| } |
|
|
| CHECK_NOTNULL(ref_image); |
|
|
| |
| |
| for (const auto image_id : snapshot) { |
| const auto& image = reconstruction.Image(image_id); |
| if (image.CameraId() != ref_camera_id_) { |
| Eigen::Vector4d rel_qvec; |
| Eigen::Vector3d rel_tvec; |
| ComputeRelativePose(ref_image->Qvec(), ref_image->Tvec(), image.Qvec(), |
| image.Tvec(), &rel_qvec, &rel_tvec); |
|
|
| rel_qvecs[image.CameraId()].push_back(rel_qvec); |
| RelativeTvec(image.CameraId()) += rel_tvec; |
| } |
| } |
| } |
|
|
| RelativeQvec(ref_camera_id_) = ComposeIdentityQuaternion(); |
| RelativeTvec(ref_camera_id_) = Eigen::Vector3d(0, 0, 0); |
|
|
| |
| for (auto& rig_camera : rig_cameras_) { |
| if (rig_camera.first != ref_camera_id_) { |
| if (rel_qvecs.count(rig_camera.first) == 0) { |
| std::cout << "Need at least one snapshot with an image of camera " |
| << rig_camera.first << " and the reference camera " |
| << ref_camera_id_ |
| << " to compute its relative pose in the camera rig" |
| << std::endl; |
| return false; |
| } |
| const std::vector<Eigen::Vector4d>& camera_rel_qvecs = |
| rel_qvecs.at(rig_camera.first); |
| const std::vector<double> rel_qvec_weights(camera_rel_qvecs.size(), 1.0); |
| rig_camera.second.rel_qvec = |
| AverageQuaternions(camera_rel_qvecs, rel_qvec_weights); |
| rig_camera.second.rel_tvec /= camera_rel_qvecs.size(); |
| } |
| } |
| return true; |
| } |
|
|
| void CameraRig::ComputeAbsolutePose(const size_t snapshot_idx, |
| const Reconstruction& reconstruction, |
| Eigen::Vector4d* abs_qvec, |
| Eigen::Vector3d* abs_tvec) const { |
| const auto& snapshot = snapshots_.at(snapshot_idx); |
|
|
| std::vector<Eigen::Vector4d> abs_qvecs; |
| *abs_tvec = Eigen::Vector3d::Zero(); |
|
|
| for (const auto image_id : snapshot) { |
| const auto& image = reconstruction.Image(image_id); |
| Eigen::Vector4d inv_rel_qvec; |
| Eigen::Vector3d inv_rel_tvec; |
| InvertPose(RelativeQvec(image.CameraId()), RelativeTvec(image.CameraId()), |
| &inv_rel_qvec, &inv_rel_tvec); |
|
|
| const Eigen::Vector4d qvec = |
| ConcatenateQuaternions(image.Qvec(), inv_rel_qvec); |
| const Eigen::Vector3d tvec = QuaternionRotatePoint( |
| inv_rel_qvec, image.Tvec() - RelativeTvec(image.CameraId())); |
|
|
| abs_qvecs.push_back(qvec); |
| *abs_tvec += tvec; |
| } |
|
|
| const std::vector<double> abs_qvec_weights(snapshot.size(), 1); |
| *abs_qvec = AverageQuaternions(abs_qvecs, abs_qvec_weights); |
| *abs_tvec /= snapshot.size(); |
| } |
|
|
| } |
|
|