ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
camera_rig.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "base/camera_rig.h"
33 
34 #include "util/misc.h"
35 
36 namespace colmap {
37 
39 
40 size_t CameraRig::NumCameras() const { return rig_cameras_.size(); }
41 
42 size_t CameraRig::NumSnapshots() const { return snapshots_.size(); }
43 
44 bool CameraRig::HasCamera(const camera_t camera_id) const {
45  return rig_cameras_.count(camera_id);
46 }
47 
48 camera_t CameraRig::RefCameraId() const { return ref_camera_id_; }
49 
50 void CameraRig::SetRefCameraId(const camera_t camera_id) {
51  CHECK(HasCamera(camera_id));
52  ref_camera_id_ = camera_id;
53 }
54 
55 std::vector<camera_t> CameraRig::GetCameraIds() const {
56  std::vector<camera_t> rig_camera_ids;
57  rig_camera_ids.reserve(NumCameras());
58  for (const auto& rig_camera : rig_cameras_) {
59  rig_camera_ids.push_back(rig_camera.first);
60  }
61  return rig_camera_ids;
62 }
63 
64 const std::vector<std::vector<image_t>>& CameraRig::Snapshots() const {
65  return snapshots_;
66 }
67 
68 void CameraRig::AddCamera(const camera_t camera_id,
69  const Eigen::Vector4d& rel_qvec,
70  const Eigen::Vector3d& rel_tvec) {
71  CHECK(!HasCamera(camera_id));
72  CHECK_EQ(NumSnapshots(), 0);
73  RigCamera rig_camera;
74  rig_camera.rel_qvec = rel_qvec;
75  rig_camera.rel_tvec = rel_tvec;
76  rig_cameras_.emplace(camera_id, rig_camera);
77 }
78 
79 void CameraRig::AddSnapshot(const std::vector<image_t>& image_ids) {
80  CHECK(!image_ids.empty());
81  CHECK_LE(image_ids.size(), NumCameras());
82  CHECK(!VectorContainsDuplicateValues(image_ids));
83  snapshots_.push_back(image_ids);
84 }
85 
86 void CameraRig::Check(const Reconstruction& reconstruction) const {
87  CHECK(HasCamera(ref_camera_id_));
88 
89  for (const auto& rig_camera : rig_cameras_) {
90  CHECK(reconstruction.ExistsCamera(rig_camera.first));
91  }
92 
93  std::unordered_set<image_t> all_image_ids;
94  for (const auto& snapshot : snapshots_) {
95  CHECK(!snapshot.empty());
96  CHECK_LE(snapshot.size(), NumCameras());
97  bool has_ref_camera = false;
98  for (const auto image_id : snapshot) {
99  CHECK(reconstruction.ExistsImage(image_id));
100  CHECK_EQ(all_image_ids.count(image_id), 0);
101  all_image_ids.insert(image_id);
102  const auto& image = reconstruction.Image(image_id);
103  CHECK(HasCamera(image.CameraId()));
104  if (image.CameraId() == ref_camera_id_) {
105  has_ref_camera = true;
106  }
107  }
108  CHECK(has_ref_camera);
109  }
110 }
111 
112 Eigen::Vector4d& CameraRig::RelativeQvec(const camera_t camera_id) {
113  return rig_cameras_.at(camera_id).rel_qvec;
114 }
115 
116 const Eigen::Vector4d& CameraRig::RelativeQvec(const camera_t camera_id) const {
117  return rig_cameras_.at(camera_id).rel_qvec;
118 }
119 
120 Eigen::Vector3d& CameraRig::RelativeTvec(const camera_t camera_id) {
121  return rig_cameras_.at(camera_id).rel_tvec;
122 }
123 
124 const Eigen::Vector3d& CameraRig::RelativeTvec(const camera_t camera_id) const {
125  return rig_cameras_.at(camera_id).rel_tvec;
126 }
127 
128 double CameraRig::ComputeScale(const Reconstruction& reconstruction) const {
129  CHECK_GT(NumSnapshots(), 0);
130  CHECK_GT(NumCameras(), 0);
131  double scaling_factor = 0;
132  size_t num_dists = 0;
133  std::vector<Eigen::Vector3d> rel_proj_centers(NumCameras());
134  std::vector<Eigen::Vector3d> abs_proj_centers(NumCameras());
135  for (const auto& snapshot : snapshots_) {
136  // Compute the projection relative and absolute projection centers.
137  for (size_t i = 0; i < NumCameras(); ++i) {
138  const auto& image = reconstruction.Image(snapshot[i]);
139  rel_proj_centers[i] = ProjectionCenterFromPose(
140  RelativeQvec(image.CameraId()), RelativeTvec(image.CameraId()));
141  abs_proj_centers[i] = image.ProjectionCenter();
142  }
143 
144  // Accumulate the scaling factor for all pairs of camera distances.
145  for (size_t i = 0; i < NumCameras(); ++i) {
146  for (size_t j = 0; j < i; ++j) {
147  const double rel_dist =
148  (rel_proj_centers[i] - rel_proj_centers[j]).norm();
149  const double abs_dist =
150  (abs_proj_centers[i] - abs_proj_centers[j]).norm();
151  const double kMinDist = 1e-6;
152  if (rel_dist > kMinDist && abs_dist > kMinDist) {
153  scaling_factor += rel_dist / abs_dist;
154  num_dists += 1;
155  }
156  }
157  }
158  }
159 
160  if (num_dists == 0) {
161  return std::numeric_limits<double>::quiet_NaN();
162  }
163 
164  return scaling_factor / num_dists;
165 }
166 
167 bool CameraRig::ComputeRelativePoses(const Reconstruction& reconstruction) {
168  CHECK_GT(NumSnapshots(), 0);
169  CHECK_NE(ref_camera_id_, kInvalidCameraId);
170 
171  for (auto& rig_camera : rig_cameras_) {
172  rig_camera.second.rel_tvec = Eigen::Vector3d::Zero();
173  }
174 
175  std::unordered_map<camera_t, std::vector<Eigen::Vector4d>> rel_qvecs;
176 
177  for (const auto& snapshot : snapshots_) {
178  // Find the image of the reference camera in the current snapshot.
179  const Image* ref_image = nullptr;
180  for (const auto image_id : snapshot) {
181  const auto& image = reconstruction.Image(image_id);
182  if (image.CameraId() == ref_camera_id_) {
183  ref_image = &image;
184  }
185  }
186 
187  CHECK_NOTNULL(ref_image);
188 
189  // Compute the relative poses from all cameras in the current snapshot to
190  // the reference camera.
191  for (const auto image_id : snapshot) {
192  const auto& image = reconstruction.Image(image_id);
193  if (image.CameraId() != ref_camera_id_) {
194  Eigen::Vector4d rel_qvec;
195  Eigen::Vector3d rel_tvec;
196  ComputeRelativePose(ref_image->Qvec(), ref_image->Tvec(), image.Qvec(),
197  image.Tvec(), &rel_qvec, &rel_tvec);
198 
199  rel_qvecs[image.CameraId()].push_back(rel_qvec);
200  RelativeTvec(image.CameraId()) += rel_tvec;
201  }
202  }
203  }
204 
205  RelativeQvec(ref_camera_id_) = ComposeIdentityQuaternion();
206  RelativeTvec(ref_camera_id_) = Eigen::Vector3d(0, 0, 0);
207 
208  // Compute the average relative poses.
209  for (auto& rig_camera : rig_cameras_) {
210  if (rig_camera.first != ref_camera_id_) {
211  if (rel_qvecs.count(rig_camera.first) == 0) {
212  std::cout << "Need at least one snapshot with an image of camera "
213  << rig_camera.first << " and the reference camera "
214  << ref_camera_id_
215  << " to compute its relative pose in the camera rig"
216  << std::endl;
217  return false;
218  }
219  const std::vector<Eigen::Vector4d>& camera_rel_qvecs =
220  rel_qvecs.at(rig_camera.first);
221  const std::vector<double> rel_qvec_weights(camera_rel_qvecs.size(), 1.0);
222  rig_camera.second.rel_qvec =
223  AverageQuaternions(camera_rel_qvecs, rel_qvec_weights);
224  rig_camera.second.rel_tvec /= camera_rel_qvecs.size();
225  }
226  }
227  return true;
228 }
229 
230 void CameraRig::ComputeAbsolutePose(const size_t snapshot_idx,
231  const Reconstruction& reconstruction,
232  Eigen::Vector4d* abs_qvec,
233  Eigen::Vector3d* abs_tvec) const {
234  const auto& snapshot = snapshots_.at(snapshot_idx);
235 
236  std::vector<Eigen::Vector4d> abs_qvecs;
237  *abs_tvec = Eigen::Vector3d::Zero();
238 
239  for (const auto image_id : snapshot) {
240  const auto& image = reconstruction.Image(image_id);
241  Eigen::Vector4d inv_rel_qvec;
242  Eigen::Vector3d inv_rel_tvec;
243  InvertPose(RelativeQvec(image.CameraId()), RelativeTvec(image.CameraId()),
244  &inv_rel_qvec, &inv_rel_tvec);
245 
246  const Eigen::Vector4d qvec =
247  ConcatenateQuaternions(image.Qvec(), inv_rel_qvec);
248  const Eigen::Vector3d tvec = QuaternionRotatePoint(
249  inv_rel_qvec, image.Tvec() - RelativeTvec(image.CameraId()));
250 
251  abs_qvecs.push_back(qvec);
252  *abs_tvec += tvec;
253  }
254 
255  const std::vector<double> abs_qvec_weights(snapshot.size(), 1);
256  *abs_qvec = AverageQuaternions(abs_qvecs, abs_qvec_weights);
257  *abs_tvec /= snapshot.size();
258 }
259 
260 } // namespace colmap
std::shared_ptr< core::Tensor > image
void SetRefCameraId(const camera_t camera_id)
Definition: camera_rig.cc:50
camera_t RefCameraId() const
Definition: camera_rig.cc:48
void Check(const Reconstruction &reconstruction) const
Definition: camera_rig.cc:86
void AddCamera(const camera_t camera_id, const Eigen::Vector4d &rel_qvec, const Eigen::Vector3d &rel_tvec)
Definition: camera_rig.cc:68
bool HasCamera(const camera_t camera_id) const
Definition: camera_rig.cc:44
size_t NumSnapshots() const
Definition: camera_rig.cc:42
Eigen::Vector3d & RelativeTvec(const camera_t camera_id)
Definition: camera_rig.cc:120
void AddSnapshot(const std::vector< image_t > &image_ids)
Definition: camera_rig.cc:79
size_t NumCameras() const
Definition: camera_rig.cc:40
bool ComputeRelativePoses(const Reconstruction &reconstruction)
Definition: camera_rig.cc:167
std::vector< camera_t > GetCameraIds() const
Definition: camera_rig.cc:55
const std::vector< std::vector< image_t > > & Snapshots() const
Definition: camera_rig.cc:64
Eigen::Vector4d & RelativeQvec(const camera_t camera_id)
Definition: camera_rig.cc:112
void ComputeAbsolutePose(const size_t snapshot_idx, const Reconstruction &reconstruction, Eigen::Vector4d *abs_qvec, Eigen::Vector3d *abs_tvec) const
Definition: camera_rig.cc:230
double ComputeScale(const Reconstruction &reconstruction) const
Definition: camera_rig.cc:128
const Eigen::Vector3d & Tvec() const
Definition: image.h:325
const Eigen::Vector4d & Qvec() const
Definition: image.h:301
const class Image & Image(const image_t image_id) const
bool ExistsCamera(const camera_t camera_id) const
bool ExistsImage(const image_t image_id) const
const double * e
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
void ComputeRelativePose(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2, Eigen::Vector4d *qvec12, Eigen::Vector3d *tvec12)
Definition: pose.cc:173
Eigen::Vector4d ComposeIdentityQuaternion()
Definition: pose.h:209
void InvertPose(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, Eigen::Vector4d *inv_qvec, Eigen::Vector3d *inv_tvec)
Definition: pose.cc:192
Eigen::Vector4d AverageQuaternions(const std::vector< Eigen::Vector4d > &qvecs, const std::vector< double > &weights)
Definition: pose.cc:118
bool VectorContainsDuplicateValues(const std::vector< T > &vector)
Definition: misc.h:143
const camera_t kInvalidCameraId
Definition: types.h:75
Eigen::Vector4d ConcatenateQuaternions(const Eigen::Vector4d &qvec1, const Eigen::Vector4d &qvec2)
Definition: pose.cc:97
Eigen::Vector3d QuaternionRotatePoint(const Eigen::Vector4d &qvec, const Eigen::Vector3d &point)
Definition: pose.cc:110
Eigen::Vector3d ProjectionCenterFromPose(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec)
Definition: pose.cc:164
uint32_t camera_t
Definition: types.h:58