ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
cost_functions.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <ceres/ceres.h>
11 #include <ceres/rotation.h>
12 
13 #include <Eigen/Core>
14 
15 namespace colmap {
16 
17 // Standard bundle adjustment cost function for variable
18 // camera pose and calibration and point parameters.
19 template <typename CameraModel>
21 public:
22  explicit BundleAdjustmentCostFunction(const Eigen::Vector2d& point2D)
23  : observed_x_(point2D(0)), observed_y_(point2D(1)) {}
24 
25  static ceres::CostFunction* Create(const Eigen::Vector2d& point2D) {
26  return (new ceres::AutoDiffCostFunction<
28  CameraModel::kNumParams>(
29  new BundleAdjustmentCostFunction(point2D)));
30  }
31 
32  template <typename T>
33  bool operator()(const T* const qvec,
34  const T* const tvec,
35  const T* const point3D,
36  const T* const camera_params,
37  T* residuals) const {
38  // Rotate and translate.
39  T projection[3];
40  ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
41  projection[0] += tvec[0];
42  projection[1] += tvec[1];
43  projection[2] += tvec[2];
44 
45  // Project to image plane.
46  projection[0] /= projection[2];
47  projection[1] /= projection[2];
48 
49  // Distort and transform to pixel space.
50  CameraModel::WorldToImage(camera_params, projection[0], projection[1],
51  &residuals[0], &residuals[1]);
52 
53  // Re-projection error.
54  residuals[0] -= T(observed_x_);
55  residuals[1] -= T(observed_y_);
56 
57  return true;
58  }
59 
60 private:
61  const double observed_x_;
62  const double observed_y_;
63 };
64 
65 // Bundle adjustment cost function for variable
66 // camera calibration and point parameters, and fixed camera pose.
67 template <typename CameraModel>
69 public:
70  BundleAdjustmentConstantPoseCostFunction(const Eigen::Vector4d& qvec,
71  const Eigen::Vector3d& tvec,
72  const Eigen::Vector2d& point2D)
73  : qw_(qvec(0)),
74  qx_(qvec(1)),
75  qy_(qvec(2)),
76  qz_(qvec(3)),
77  tx_(tvec(0)),
78  ty_(tvec(1)),
79  tz_(tvec(2)),
80  observed_x_(point2D(0)),
81  observed_y_(point2D(1)) {}
82 
83  static ceres::CostFunction* Create(const Eigen::Vector4d& qvec,
84  const Eigen::Vector3d& tvec,
85  const Eigen::Vector2d& point2D) {
86  return (new ceres::AutoDiffCostFunction<
88  CameraModel::kNumParams>(
90  point2D)));
91  }
92 
93  template <typename T>
94  bool operator()(const T* const point3D,
95  const T* const camera_params,
96  T* residuals) const {
97  const T qvec[4] = {T(qw_), T(qx_), T(qy_), T(qz_)};
98 
99  // Rotate and translate.
100  T projection[3];
101  ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
102  projection[0] += T(tx_);
103  projection[1] += T(ty_);
104  projection[2] += T(tz_);
105 
106  // Project to image plane.
107  projection[0] /= projection[2];
108  projection[1] /= projection[2];
109 
110  // Distort and transform to pixel space.
111  CameraModel::WorldToImage(camera_params, projection[0], projection[1],
112  &residuals[0], &residuals[1]);
113 
114  // Re-projection error.
115  residuals[0] -= T(observed_x_);
116  residuals[1] -= T(observed_y_);
117 
118  return true;
119  }
120 
121 private:
122  const double qw_;
123  const double qx_;
124  const double qy_;
125  const double qz_;
126  const double tx_;
127  const double ty_;
128  const double tz_;
129  const double observed_x_;
130  const double observed_y_;
131 };
132 
133 // Rig bundle adjustment cost function for variable camera pose and calibration
134 // and point parameters. Different from the standard bundle adjustment function,
135 // this cost function is suitable for camera rigs with consistent relative poses
136 // of the cameras within the rig. The cost function first projects points into
137 // the local system of the camera rig and then into the local system of the
138 // camera within the rig.
139 template <typename CameraModel>
141 public:
142  explicit RigBundleAdjustmentCostFunction(const Eigen::Vector2d& point2D)
143  : observed_x_(point2D(0)), observed_y_(point2D(1)) {}
144 
145  static ceres::CostFunction* Create(const Eigen::Vector2d& point2D) {
146  return (new ceres::AutoDiffCostFunction<
148  CameraModel::kNumParams>(
149  new RigBundleAdjustmentCostFunction(point2D)));
150  }
151 
152  template <typename T>
153  bool operator()(const T* const rig_qvec,
154  const T* const rig_tvec,
155  const T* const rel_qvec,
156  const T* const rel_tvec,
157  const T* const point3D,
158  const T* const camera_params,
159  T* residuals) const {
160  // Concatenate rotations.
161  T qvec[4];
162  ceres::QuaternionProduct(rel_qvec, rig_qvec, qvec);
163 
164  // Concatenate translations.
165  T tvec[3];
166  ceres::UnitQuaternionRotatePoint(rel_qvec, rig_tvec, tvec);
167  tvec[0] += rel_tvec[0];
168  tvec[1] += rel_tvec[1];
169  tvec[2] += rel_tvec[2];
170 
171  // Rotate and translate.
172  T projection[3];
173  ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
174  projection[0] += tvec[0];
175  projection[1] += tvec[1];
176  projection[2] += tvec[2];
177 
178  // Project to image plane.
179  projection[0] /= projection[2];
180  projection[1] /= projection[2];
181 
182  // Distort and transform to pixel space.
183  CameraModel::WorldToImage(camera_params, projection[0], projection[1],
184  &residuals[0], &residuals[1]);
185 
186  // Re-projection error.
187  residuals[0] -= T(observed_x_);
188  residuals[1] -= T(observed_y_);
189 
190  return true;
191  }
192 
193 private:
194  const double observed_x_;
195  const double observed_y_;
196 };
197 
198 // Cost function for refining two-view geometry based on the Sampson-Error.
199 //
200 // First pose is assumed to be located at the origin with 0 rotation. Second
201 // pose is assumed to be on the unit sphere around the first pose, i.e. the
202 // pose of the second camera is parameterized by a 3D rotation and a
203 // 3D translation with unit norm. `tvec` is therefore over-parameterized as is
204 // and should be down-projected using `HomogeneousVectorParameterization`.
206 public:
207  RelativePoseCostFunction(const Eigen::Vector2d& x1,
208  const Eigen::Vector2d& x2)
209  : x1_(x1(0)), y1_(x1(1)), x2_(x2(0)), y2_(x2(1)) {}
210 
211  static ceres::CostFunction* Create(const Eigen::Vector2d& x1,
212  const Eigen::Vector2d& x2) {
213  return (new ceres::AutoDiffCostFunction<RelativePoseCostFunction, 1, 4,
214  3>(
215  new RelativePoseCostFunction(x1, x2)));
216  }
217 
218  template <typename T>
219  bool operator()(const T* const qvec,
220  const T* const tvec,
221  T* residuals) const {
222  Eigen::Matrix<T, 3, 3, Eigen::RowMajor> R;
223  ceres::QuaternionToRotation(qvec, R.data());
224 
225  // Matrix representation of the cross product t x R.
226  Eigen::Matrix<T, 3, 3> t_x;
227  t_x << T(0), -tvec[2], tvec[1], tvec[2], T(0), -tvec[0], -tvec[1],
228  tvec[0], T(0);
229 
230  // Essential matrix.
231  const Eigen::Matrix<T, 3, 3> E = t_x * R;
232 
233  // Homogeneous image coordinates.
234  const Eigen::Matrix<T, 3, 1> x1_h(T(x1_), T(y1_), T(1));
235  const Eigen::Matrix<T, 3, 1> x2_h(T(x2_), T(y2_), T(1));
236 
237  // Squared sampson error.
238  const Eigen::Matrix<T, 3, 1> Ex1 = E * x1_h;
239  const Eigen::Matrix<T, 3, 1> Etx2 = E.transpose() * x2_h;
240  const T x2tEx1 = x2_h.transpose() * Ex1;
241  residuals[0] = x2tEx1 * x2tEx1 /
242  (Ex1(0) * Ex1(0) + Ex1(1) * Ex1(1) + Etx2(0) * Etx2(0) +
243  Etx2(1) * Etx2(1));
244 
245  return true;
246  }
247 
248 private:
249  const double x1_;
250  const double y1_;
251  const double x2_;
252  const double y2_;
253 };
254 
255 } // namespace colmap
static ceres::CostFunction * Create(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, const Eigen::Vector2d &point2D)
bool operator()(const T *const point3D, const T *const camera_params, T *residuals) const
BundleAdjustmentConstantPoseCostFunction(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, const Eigen::Vector2d &point2D)
BundleAdjustmentCostFunction(const Eigen::Vector2d &point2D)
static ceres::CostFunction * Create(const Eigen::Vector2d &point2D)
bool operator()(const T *const qvec, const T *const tvec, const T *const point3D, const T *const camera_params, T *residuals) const
RelativePoseCostFunction(const Eigen::Vector2d &x1, const Eigen::Vector2d &x2)
static ceres::CostFunction * Create(const Eigen::Vector2d &x1, const Eigen::Vector2d &x2)
bool operator()(const T *const qvec, const T *const tvec, T *residuals) const
bool operator()(const T *const rig_qvec, const T *const rig_tvec, const T *const rel_qvec, const T *const rel_tvec, const T *const point3D, const T *const camera_params, T *residuals) const
static ceres::CostFunction * Create(const Eigen::Vector2d &point2D)
RigBundleAdjustmentCostFunction(const Eigen::Vector2d &point2D)