Berkeley SfM
camera_intrinsics.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: Erik Nelson ( eanelson@eecs.berkeley.edu )
35  * David Fridovich-Keil ( dfk@eecs.berkeley.edu )
36  */
37 
38 ///////////////////////////////////////////////////////////////////////////////
39 //
40 // This class defines a camera's intrinsic parameters, calibration, and
41 // computations using the OpenCV camera model, with the minor modification that
42 // we will use a 5th-order distortion model rather than a 6th-order model. Math
43 // for the 5th-order distortion model can be found at the caltech vision page:
44 //
45 // http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
46 // http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
47 //
48 ///////////////////////////////////////////////////////////////////////////////
49 
50 #include "camera_intrinsics.h"
51 
52 #include <glog/logging.h>
53 
54 namespace bsfm {
55 
56 // Initialize to zero.
58  : image_left_(0),
59  image_top_(0),
60  image_width_(0),
61  image_height_(0),
62  f_u_(0.0),
63  f_v_(0.0),
64  c_u_(0.0),
65  c_v_(0.0),
66  k1_(0.0),
67  k2_(0.0),
68  k3_(0.0),
69  k4_(0.0),
70  k5_(0.0),
71  horizontal_fov_(0.0),
72  vertical_fov_(0.0) {}
73 
74 // Assume no radial distortion, and image left and top are both zero.
75 CameraIntrinsics::CameraIntrinsics(const Matrix3d &K, int image_width,
76  int image_height)
77  : image_left_(0),
78  image_top_(0),
79  image_width_(image_width),
80  image_height_(image_height),
81  f_u_(K(0, 0)),
82  f_v_(K(1, 1)),
83  c_u_(K(0, 2)),
84  c_v_(K(1, 2)),
85  k1_(0.0),
86  k2_(0.0),
87  k3_(0.0),
88  k4_(0.0),
89  k5_(0.0) {
90  horizontal_fov_ = 2.0 * atan2(0.5 * image_width_, f_u_);
91  vertical_fov_ = 2.0 * atan2(0.5 * image_height_, f_v_);
92 }
93 
94 // Full initialization.
95 CameraIntrinsics::CameraIntrinsics(int image_left, int image_top,
96  int image_width, int image_height,
97  double f_u, double f_v, double c_u,
98  double c_v, double k1, double k2, double k3,
99  double k4, double k5)
100  : image_left_(image_left),
101  image_top_(image_top),
102  image_width_(image_width),
103  image_height_(image_height),
104  f_u_(f_u),
105  f_v_(f_v),
106  c_u_(c_u),
107  c_v_(c_v),
108  k1_(k1),
109  k2_(k2),
110  k3_(k3),
111  k4_(k4),
112  k5_(k5) {
113  horizontal_fov_ = 2.0 * atan2(0.5 * image_width_, f_u_);
114  vertical_fov_ = 2.0 * atan2(0.5 * image_height_, f_v_);
115 }
116 
117 // Set individual parameters.
118 void CameraIntrinsics::SetImageLeft(int image_left) {
119  image_left_ = image_left;
120 }
121 
122 void CameraIntrinsics::SetImageTop(int image_top) {
123  image_top_ = image_top;
124 }
125 
126 void CameraIntrinsics::SetImageWidth(int image_width) {
127  image_width_ = image_width;
128  horizontal_fov_ = 2.0 * atan2(0.5 * image_width_, f_u_);
129 }
130 
131 void CameraIntrinsics::SetImageHeight(int image_height) {
132  image_height_ = image_height;
133  vertical_fov_ = 2.0 * atan2(0.5 * image_height_, f_v_);
134 }
135 
136 void CameraIntrinsics::SetFU(double f_u) {
137  f_u_ = f_u;
138  horizontal_fov_ = 2.0 * atan2(0.5 * image_width_, f_u_);
139 }
140 
141 void CameraIntrinsics::SetFV(double f_v) {
142  f_v_ = f_v;
143  vertical_fov_ = 2.0 * atan2(0.5 * image_height_, f_v_);
144 }
145 
146 void CameraIntrinsics::SetCU(double c_u) {
147  c_u_ = c_u;
148 }
149 
150 void CameraIntrinsics::SetCV(double c_v) {
151  c_v_ = c_v;
152 }
153 
154 void CameraIntrinsics::SetK(double k1, double k2, double k3, double k4,
155  double k5) {
156  k1_ = k1;
157  k2_ = k2;
158  k3_ = k3;
159  k4_ = k4;
160  k5_ = k5;
161 }
162 
163 void CameraIntrinsics::SetK1(double k1) {
164  k1_ = k1;
165 }
166 
167 void CameraIntrinsics::SetK2(double k2) {
168  k2_ = k2;
169 }
170 
171 void CameraIntrinsics::SetK3(double k3) {
172  k3_ = k3;
173 }
174 
175 void CameraIntrinsics::SetK4(double k4) {
176  k4_ = k4;
177 }
178 
179 void CameraIntrinsics::SetK5(double k5) {
180  k5_ = k5;
181 }
182 
183 void CameraIntrinsics::SetHorizontalFOV(double horizontal_fov) {
184  horizontal_fov_ = horizontal_fov;
185  f_u_ = 0.5 * image_width_ / tan(0.5 * horizontal_fov_);
186 }
187 
188 void CameraIntrinsics::SetVerticalFOV(double vertical_fov) {
189  vertical_fov_ = vertical_fov;
190  f_v_ = 0.5 * image_height_ / tan(0.5 * vertical_fov_);
191 }
192 
193 // Extract parameters.
195  return image_left_;
196 }
197 
199  return image_top_;
200 }
201 
203  return image_width_;
204 }
205 
207  return image_height_;
208 }
209 
210 double CameraIntrinsics::f_u() const {
211  return f_u_;
212 }
213 
214 double CameraIntrinsics::f_v() const {
215  return f_v_;
216 }
217 
218 double CameraIntrinsics::c_u() const {
219  return c_u_;
220 }
221 
222 double CameraIntrinsics::c_v() const {
223  return c_v_;
224 }
225 
226 double CameraIntrinsics::k1() const {
227  return k1_;
228 }
229 
230 double CameraIntrinsics::k2() const {
231  return k2_;
232 }
233 
234 double CameraIntrinsics::k3() const {
235  return k3_;
236 }
237 
238 double CameraIntrinsics::k4() const {
239  return k4_;
240 }
241 
242 double CameraIntrinsics::k5() const {
243  return k5_;
244 }
245 
247  return horizontal_fov_;
248 }
249 
251  return vertical_fov_;
252 }
253 
254 // Get intrinsics matrix.
255 Matrix3d CameraIntrinsics::K() const {
256  Matrix3d K;
257  K << f_u_, 0.0, c_u_, 0.0, f_v_, c_v_, 0.0, 0.0, 1.0;
258 
259  return K;
260 }
261 
262 // Get inverse of intrinsics matrix.
263 Matrix3d CameraIntrinsics::Kinv() const {
264  return CameraIntrinsics::K().inverse();
265 }
266 
267 // Test if a point is in the image.
268 bool CameraIntrinsics::PointInImage(double u, double v) const {
269  const bool in_cols = u >= image_left_ && u < image_left_ + image_width_;
270  const bool in_rows = v >= image_top_ && v < image_top_ + image_height_;
271  return in_cols && in_rows;
272 }
273 
274 // Check if a point is in front of the camera.
275 bool CameraIntrinsics::CameraToImage(double cx, double cy, double cz,
276  double *u_distorted,
277  double *v_distorted) const {
278  CHECK_NOTNULL(u_distorted);
279  CHECK_NOTNULL(v_distorted);
280 
281  // We can't project points that lie behind the camera.
282  if (cz < 0.0) return false;
283 
284  // Convert the camera frame point into a normalized direction vector (see
285  // OpenCV help page at the top of this file).
286  const double u_normalized = cx / cz;
287  const double v_normalized = cy / cz;
288 
289  return DirectionToImage(u_normalized, v_normalized, u_distorted, v_distorted);
290 }
291 
292 bool CameraIntrinsics::DirectionToImage(double u_normalized,
293  double v_normalized,
294  double *u_distorted,
295  double *v_distorted) const {
296  CHECK_NOTNULL(u_distorted);
297  CHECK_NOTNULL(v_distorted);
298 
299  // Distort the normalized direction vector;
300  double u = 0.0, v = 0.0;
301  Distort(u_normalized, v_normalized, &u, &v);
302 
303  // Make a homogeneous vector from the output.
304  Vector3d p;
305  p << u, v, 1.0;
306 
307  // Multiply the distorted direction vector by camera intrinsic matrix to get
308  // the image space point.
309  const Vector3d p_out = CameraIntrinsics::K() * p;
310  *u_distorted = p_out(0);
311  *v_distorted = p_out(1);
312 
313  // Make sure that the resulting point is in the image.
314  return PointInImage(*u_distorted, *v_distorted);
315 }
316 
317 void CameraIntrinsics::ImageToDirection(double u_distorted, double v_distorted,
318  double *u_normalized,
319  double *v_normalized) const {
320  CHECK_NOTNULL(u_normalized);
321  CHECK_NOTNULL(v_normalized);
322 
323  // Make a homogeneous image space point.
324  Vector3d p_distorted;
325  p_distorted << u_distorted, v_distorted, 1.0;
326 
327  // Multiply the distorted homogeneous image space point by the inverse
328  // of the camera intrinsic matrix to get a distorted ray.
329  const Vector3d p = CameraIntrinsics::Kinv() * p_distorted;
330 
331  // Undistort the ray to get the normalized direction vector.
332  Undistort(p(0), p(1), u_normalized, v_normalized);
333 }
334 
335 // Warp a point into the image.
336 void CameraIntrinsics::Distort(double u, double v, double *u_distorted,
337  double *v_distorted) const {
338  CHECK_NOTNULL(u_distorted);
339  CHECK_NOTNULL(v_distorted);
340 
341  // Get the camera's radial distortion (see OpenCV help page at the top of
342  // this file).
343  const double r_sq = u * u + v * v;
344  const double radial_dist =
345  1.0 + k1_ * r_sq + k2_ * r_sq * r_sq + k5_ * r_sq * r_sq * r_sq;
346 
347  // If radial distortion is too extreme, our 5th-order model might not be a
348  // good fit. Instead, estimate the distortion with a simpler model (linear),
349  // and apply radial corrections.
350  if (radial_dist < 0.85 || radial_dist > 1.15) {
351  // Distortion too extreme. Warp the point with estimated radial
352  // distortion.
353  const double radius = hypot(image_width_, image_height_);
354  *u_distorted = u / sqrt(r_sq) * radius;
355  *v_distorted = v / sqrt(r_sq) * radius;
356  } else {
357  // Compute radial distortion with 5th order model.
358  const double dx0 = 2.0 * k3_ * u * v + k4_ * (r_sq + 2.0 * u * u);
359  const double dx1 = k3_ * (r_sq + 2.0 * v * v) + 2.0 * k4_ * u * v;
360 
361  // Homogeneous distorted direction vector.
362  *u_distorted = radial_dist * u + dx0;
363  *v_distorted = radial_dist * v + dx1;
364  }
365 }
366 
367 // Rectilinearize point.
368 void CameraIntrinsics::Undistort(double u_distorted, double v_distorted,
369  double *u, double *v, int iterations) const {
370  CHECK_NOTNULL(u);
371  CHECK_NOTNULL(v);
372 
373  // Iteratively attempt to undo the radial distortion (see OpenCV help page
374  // at the top of this file).
375  double u_refine = u_distorted;
376  double v_refine = v_distorted;
377  for (int i = 0; i < iterations; ++i) {
378  const double r_sq = u_refine * u_refine + v_refine * v_refine;
379  const double dx0 = 2.0 * k3_ * u_refine * v_refine +
380  k4_ * (r_sq + 2.0 * u_refine * u_refine);
381  const double dx1 = k3_ * (r_sq + 2.0 * v_refine * v_refine) +
382  2.0 * k4_ * u_refine * v_refine;
383  u_refine = u_distorted - dx0;
384  v_refine = v_distorted - dx1;
385  }
386 
387  // Return the undistorted direction vector.
388  *u = u_refine;
389  *v = v_refine;
390 }
391 
392 } //\namespace bsfm
void ImageToDirection(double u_distorted, double v_distorted, double *u_normalized, double *v_normalized) const
void SetImageLeft(int image_left)
void SetVerticalFOV(double vertical_fov)
bool DirectionToImage(double u_normalized, double v_normalized, double *u_distorted, double *v_distorted) const
void SetImageHeight(int image_height)
bool PointInImage(double u, double v) const
void SetK(double k1, double k2, double k3, double k4, double k5)
Definition: camera.cpp:50
void SetImageWidth(int image_width)
void Distort(double u, double v, double *u_distorted, double *v_distorted) const
void SetImageTop(int image_top)
void Undistort(double u_distorted, double v_distorted, double *u, double *v, int iterations=10) const
void SetHorizontalFOV(double horizontal_fov)
bool CameraToImage(double cx, double cy, double cz, double *u_distorted, double *v_distorted) const