Monado OpenXR Runtime
t_calibration_opencv.hpp
Go to the documentation of this file.
1 // Copyright 2019-2020, Collabora, Ltd.
2 // SPDX-License-Identifier: BSL-1.0
3 /*!
4  * @file
5  * @brief OpenCV calibration helpers.
6  * @author Pete Black <pblack@collabora.com>
7  * @author Jakob Bornecrantz <jakob@collabora.com>
8  * @author Rylie Pavlik <rylie.pavlik@collabora.com>
9  * @ingroup aux_tracking
10  */
11 
12 #pragma once
13 
14 #ifndef __cplusplus
15 #error "This header is C++-only."
16 #endif
17 
18 #include "tracking/t_tracking.h"
19 
20 #include <opencv2/opencv.hpp>
21 #include <sys/stat.h>
22 
23 namespace xrt::auxiliary::tracking {
24 
25 static inline size_t
26 t_num_opencv_params_from_distortion_model(const enum t_camera_distortion_model model)
27 {
28  switch (model) {
29  case T_DISTORTION_WMR:
30  // OpenCV doesn't know what to do with codx, cody or rpmax. We reinterpret it as
31  // T_DISTORTION_OPENCV_RADTAN_8.
33  break;
34  default: return t_num_params_from_distortion_model(model);
35  }
36 }
37 /*!
38  * @brief Essential calibration data wrapped for C++.
39  *
40  * Like the cv::Mat that it holds, this object does not own all the memory
41  * it points to!
42  */
44 {
46  xrt_size &image_size_pixels;
47  const cv::Size image_size_pixels_cv;
48  cv::Mat_<double> intrinsics_mat;
49  cv::Mat_<double> distortion_mat;
50  enum t_camera_distortion_model &distortion_model;
51 
53  : base(calib), //
54  image_size_pixels(calib.image_size_pixels), //
55  image_size_pixels_cv(calib.image_size_pixels.w, calib.image_size_pixels.h), //
56  intrinsics_mat(3, 3, &calib.intrinsics[0][0]), //
57  distortion_mat(t_num_opencv_params_from_distortion_model(base.distortion_model),
58  1,
59  &calib.distortion_parameters_as_array[0]), //
60  distortion_model(calib.distortion_model)
61  {
62  if (base.distortion_model == T_DISTORTION_WMR) {
63  U_LOG_W("Reinterpreting T_DISTORTION_WMR model as T_DISTORTION_OPENCV_RADTAN_8!");
64  }
65  assert(isDataStorageValid());
66  }
67 
68  //! Try to verify nothing was reallocated.
69  bool
70  isDataStorageValid() const noexcept
71  {
72  return intrinsics_mat.size() == cv::Size(3, 3) &&
73  (double *)intrinsics_mat.data == &(base.intrinsics[0][0]) &&
74  (base.distortion_model != T_DISTORTION_FISHEYE_KB4 || distortion_mat.size() == cv::Size(1, 4)) &&
75  distortion_mat.size() ==
76  cv::Size(1, t_num_opencv_params_from_distortion_model(base.distortion_model)) &&
77  (double *)distortion_mat.data == &(base.distortion_parameters_as_array[0]);
78  }
79 };
80 
81 
82 /*!
83  * @brief Essential stereo calibration data wrapped for C++.
84  *
85  * Like the cv::Mat that it holds, this object does not own (all) the
86  * memory it points to!
87  */
89 {
92  cv::Mat_<double> camera_translation_mat;
93  cv::Mat_<double> camera_rotation_mat;
94  cv::Mat_<double> camera_essential_mat;
95  cv::Mat_<double> camera_fundamental_mat;
96 
97 
99  allocData(enum t_camera_distortion_model distortion_model)
100  {
101  t_stereo_camera_calibration *data_ptr = NULL;
102  t_stereo_camera_calibration_alloc(&data_ptr, distortion_model);
103  return data_ptr;
104  }
105 
107  : base(stereo), view{CameraCalibrationWrapper{stereo->view[0]}, CameraCalibrationWrapper{stereo->view[1]}},
108  camera_translation_mat(3, 1, &stereo->camera_translation[0]),
109  camera_rotation_mat(3, 3, &stereo->camera_rotation[0][0]),
110  camera_essential_mat(3, 3, &stereo->camera_essential[0][0]),
111  camera_fundamental_mat(3, 3, &stereo->camera_fundamental[0][0])
112  {
113  // Correct reference counting.
114  t_stereo_camera_calibration *temp = NULL;
115  t_stereo_camera_calibration_reference(&temp, stereo);
116 
117  assert(isDataStorageValid());
118  }
119 
121  : StereoCameraCalibrationWrapper(allocData(distortion_model))
122  {
123 
124  // The function allocData returns with a ref count of one,
125  // the constructor increments the refcount with one,
126  // so to correct it we need to decrement the ref count with one.
128  t_stereo_camera_calibration_reference(&tmp, NULL);
129  }
130 
132  {
133  t_stereo_camera_calibration_reference(&base, NULL);
134  }
135 
136  bool
137  isDataStorageValid() const noexcept
138  {
139  return camera_translation_mat.size() == cv::Size(1, 3) &&
140  (double *)camera_translation_mat.data == &base->camera_translation[0] &&
141 
142  camera_rotation_mat.size() == cv::Size(3, 3) &&
143  (double *)camera_rotation_mat.data == &base->camera_rotation[0][0] &&
144 
145  camera_essential_mat.size() == cv::Size(3, 3) &&
146  (double *)camera_essential_mat.data == &base->camera_essential[0][0] &&
147 
148  camera_fundamental_mat.size() == cv::Size(3, 3) &&
149  (double *)camera_fundamental_mat.data == &base->camera_fundamental[0][0] &&
150 
151  view[0].isDataStorageValid() && view[1].isDataStorageValid();
152  }
153 };
154 
155 
156 /*!
157  * @brief An x,y pair of matrices for the remap() function.
158  *
159  * @see calibration_get_undistort_map
160  */
161 struct RemapPair
162 {
163  cv::Mat remap_x;
164  cv::Mat remap_y;
165 };
166 
167 /*!
168  * @brief Prepare undistortion/normalization remap structures for a rectilinear
169  * or fisheye image.
170  *
171  * @param calib A single camera calibration structure.
172  * @param rectify_transform_optional A rectification transform to apply, if
173  * desired.
174  * @param new_camera_matrix_optional Unlike OpenCV, the default/empty matrix
175  * here uses the input camera matrix as your output camera matrix.
176  */
177 RemapPair
179  cv::InputArray rectify_transform_optional = cv::noArray(),
180  cv::Mat new_camera_matrix_optional = cv::Mat());
181 
182 /*!
183  * @brief Rectification, rotation, projection data for a single view in a stereo
184  * pair.
185  *
186  * @see StereoRectificationMaps
187  */
189 {
190  RemapPair rectify;
191  cv::Mat rotation_mat = {};
192  cv::Mat projection_mat = {};
193 };
194 
195 /*!
196  * @brief Rectification maps as well as transforms for a stereo camera.
197  *
198  * Computed in the constructor from saved calibration data.
199  */
201 {
202  ViewRectification view[2];
203 
204  //! Disparity and position to camera world coordinates.
206 
207  /*!
208  * @brief Constructor - produces rectification data for a stereo camera
209  * based on calibration data.
210  */
212 };
213 
214 
215 /*!
216  * @brief Provides cached, precomputed normalized image coordinates from original, distorted ones.
217  *
218  * Populates internal structures using cv::undistortPoints() and performs
219  * subpixel sampling to interpolate for each query. Essentially, this class lets
220  * you perform cv::undistortPoints() while caching the initial setup work
221  * required for that function.
222  */
224 {
225 public:
226  /*!
227  * @brief Set up the precomputed cache for a given camera.
228  *
229  * @param size Size of the image in pixels
230  * @param intrinsics Camera intrinsics matrix
231  * @param distortion Distortion coefficients
232  *
233  * This overload applies no rectification (`R`) and uses a
234  * normalized/identity new camera matrix (`P`).
235  */
236  NormalizedCoordsCache(cv::Size size, const cv::Matx33d &intrinsics, const cv::Matx<double, 5, 1> &distortion);
237  /*!
238  * @brief Set up the precomputed cache for a given camera (overload for
239  * rectification and new camera matrix)
240  *
241  * @param size Size of the image in pixels
242  * @param intrinsics Camera intrinsics matrix
243  * @param distortion Distortion coefficients
244  * @param rectification Rectification matrix - corresponds to parameter
245  * `R` to cv::undistortPoints().
246  * @param new_camera_matrix A 3x3 new camera matrix - corresponds to
247  * parameter `P` to cv::undistortPoints().
248  */
249  NormalizedCoordsCache(cv::Size size,
250  const cv::Matx33d &intrinsics,
251  const cv::Matx<double, 5, 1> &distortion,
252  const cv::Matx33d &rectification,
253  const cv::Matx33d &new_camera_matrix);
254 
255  /*!
256  * @brief Set up the precomputed cache for a given camera. (overload for
257  * rectification and new projection matrix)
258  *
259  * @param size Size of the image in pixels
260  * @param intrinsics Camera intrinsics matrix
261  * @param distortion Distortion coefficients
262  * @param rectification Rectification matrix - corresponds to parameter
263  * `R` to cv::undistortPoints().
264  * @param new_projection_matrix A 3x4 new projection matrix -
265  * corresponds to parameter `P` to cv::undistortPoints().
266  */
267  NormalizedCoordsCache(cv::Size size,
268  const cv::Matx33d &intrinsics,
269  const cv::Matx<double, 5, 1> &distortion,
270  const cv::Matx33d &rectification,
271  const cv::Matx<double, 3, 4> &new_projection_matrix);
272 
273  /*!
274  * @brief Set up the precomputed cache for a given camera.
275  *
276  * Less-strongly-typed overload.
277  *
278  * @overload
279  *
280  * This overload applies no rectification (`R`) and uses a
281  * normalized/identity new camera matrix (`P`).
282  */
283  NormalizedCoordsCache(cv::Size size, const cv::Mat &intrinsics, const cv::Mat &distortion);
284 
285  /*!
286  * @brief Get normalized, undistorted coordinates from a point in the
287  * original (distorted, etc.) image.
288  *
289  * @param origCoords Image coordinates in original image
290  *
291  * @return Corresponding undistorted coordinates in a "normalized" image
292  */
293  cv::Vec2f
294  getNormalizedImageCoords(cv::Point2f origCoords) const;
295 
296  /*!
297  * @brief Get normalized vector in the camera-space direction
298  * corresponding to the original (distorted, etc.) image coordinates.
299  *
300  * Note that the Z component will be negative by convention.
301  */
302  cv::Vec3f
303  getNormalizedVector(cv::Point2f origCoords) const;
304 
305 private:
306  cv::Mat_<float> cacheX_;
307  cv::Mat_<float> cacheY_;
308 };
309 
310 } // namespace xrt::auxiliary::tracking
Provides cached, precomputed normalized image coordinates from original, distorted ones.
Definition: t_calibration_opencv.hpp:224
cv::Vec3f getNormalizedVector(cv::Point2f origCoords) const
Get normalized vector in the camera-space direction corresponding to the original (distorted,...
Definition: t_calibration.cpp:1490
NormalizedCoordsCache(cv::Size size, const cv::Matx33d &intrinsics, const cv::Matx< double, 5, 1 > &distortion)
Set up the precomputed cache for a given camera.
Definition: t_calibration.cpp:1414
cv::Vec2f getNormalizedImageCoords(cv::Point2f origCoords) const
Get normalized, undistorted coordinates from a point in the original (distorted, etc....
Definition: t_calibration.cpp:1469
#define U_LOG_W(...)
Log a message at U_LOGGING_WARN level, conditional on the global log level.
Definition: u_logging.h:298
static size_t t_num_params_from_distortion_model(const enum t_camera_distortion_model model)
Returns the number of parameters needed for this t_camera_distortion_model to be held by an OpenCV Ma...
Definition: t_tracking.h:161
t_camera_distortion_model
The distortion model this camera calibration falls under.
Definition: t_tracking.h:63
@ T_DISTORTION_OPENCV_RADTAN_8
OpenCV's radial-tangential distortion model.
Definition: t_tracking.h:82
@ T_DISTORTION_FISHEYE_KB4
Juho Kannalla and Sami Sebastian Brandt's fisheye distortion model.
Definition: t_tracking.h:116
@ T_DISTORTION_WMR
Windows Mixed Reality headsets' camera model.
Definition: t_tracking.h:131
Essential calibration data for a single camera, or single lens/sensor of a stereo camera.
Definition: t_tracking.h:223
double intrinsics[3][3]
Camera intrinsics matrix.
Definition: t_tracking.h:228
struct xrt_size image_size_pixels
Source image size.
Definition: t_tracking.h:225
enum t_camera_distortion_model distortion_model
Distortion model that this camera uses.
Definition: t_tracking.h:241
Stereo camera calibration data to be given to trackers.
Definition: t_tracking.h:248
double camera_essential[3][3]
Essential matrix.
Definition: t_tracking.h:261
double camera_translation[3]
Translation from first to second in the stereo pair.
Definition: t_tracking.h:256
struct t_camera_calibration view[2]
Calibration of individual views/sensor.
Definition: t_tracking.h:253
double camera_rotation[3][3]
Rotation matrix from first to second in the stereo pair.
Definition: t_tracking.h:258
double camera_fundamental[3][3]
Fundamental matrix.
Definition: t_tracking.h:263
Definition: comp_scratch.c:122
Essential calibration data wrapped for C++.
Definition: t_calibration_opencv.hpp:44
bool isDataStorageValid() const noexcept
Try to verify nothing was reallocated.
Definition: t_calibration_opencv.hpp:70
An x,y pair of matrices for the remap() function.
Definition: t_calibration_opencv.hpp:162
Essential stereo calibration data wrapped for C++.
Definition: t_calibration_opencv.hpp:89
Rectification maps as well as transforms for a stereo camera.
Definition: t_calibration_opencv.hpp:201
StereoRectificationMaps(t_stereo_camera_calibration *data)
Constructor - produces rectification data for a stereo camera based on calibration data.
Definition: t_file.cpp:112
cv::Mat disparity_to_depth_mat
Disparity and position to camera world coordinates.
Definition: t_calibration_opencv.hpp:205
Rectification, rotation, projection data for a single view in a stereo pair.
Definition: t_calibration_opencv.hpp:189
Image size.
Definition: xrt_defines.h:409
RemapPair calibration_get_undistort_map(t_camera_calibration &calib, cv::InputArray rectify_transform_optional=cv::noArray(), cv::Mat new_camera_matrix_optional=cv::Mat())
Prepare undistortion/normalization remap structures for a rectilinear or fisheye image.
Definition: t_file.cpp:71
Tracking API interface.