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 Ryan Pavlik <ryan.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 
24 /*!
25  * @brief Essential calibration data wrapped for C++.
26  *
27  * Just like the cv::Mat that it holds, this object does not own all the memory
28  * it points to!
29  */
31 {
33  xrt_size &image_size_pixels;
34  const cv::Size image_size_pixels_cv;
35  cv::Mat_<double> intrinsics_mat;
36  cv::Mat_<double> distortion_mat;
37  cv::Mat_<double> distortion_fisheye_mat;
38  bool &use_fisheye;
39 
41  : base(calib), image_size_pixels(calib.image_size_pixels),
42  image_size_pixels_cv(calib.image_size_pixels.w,
43  calib.image_size_pixels.h),
44  intrinsics_mat(3, 3, &calib.intrinsics[0][0]),
45  distortion_mat(XRT_DISTORTION_MAX_DIM, 1, &calib.distortion[0]),
46  distortion_fisheye_mat(4, 1, &calib.distortion_fisheye[0]),
47  use_fisheye(calib.use_fisheye)
48  {
49  assert(isDataStorageValid());
50  }
51 
52  //! Try to verify nothing was reallocated.
53  bool
54  isDataStorageValid() const noexcept
55  {
56  return intrinsics_mat.size() == cv::Size(3, 3) &&
57  (double *)intrinsics_mat.data ==
58  &(base.intrinsics[0][0]) &&
59 
60  distortion_mat.size() ==
61  cv::Size(1, XRT_DISTORTION_MAX_DIM) &&
62  (double *)distortion_mat.data == &(base.distortion[0]) &&
63 
64  distortion_fisheye_mat.size() == cv::Size(1, 4) &&
65  (double *)distortion_fisheye_mat.data ==
66  &(base.distortion_fisheye[0]);
67  }
68 };
69 
70 
71 /*!
72  * @brief Essential stereo calibration data wrapped for C++.
73  *
74  * Just like the cv::Mat that it holds, this object does not own (all) the
75  * memory it points to!
76  */
78 {
81  cv::Mat_<double> camera_translation_mat;
82  cv::Mat_<double> camera_rotation_mat;
83  cv::Mat_<double> camera_essential_mat;
84  cv::Mat_<double> camera_fundamental_mat;
85 
86 
88  allocData()
89  {
90  t_stereo_camera_calibration *data_ptr = NULL;
92  return data_ptr;
93  }
94 
96  : base(stereo), view{CameraCalibrationWrapper{stereo->view[0]},
97  CameraCalibrationWrapper{stereo->view[1]}},
98  camera_translation_mat(3, 1, &stereo->camera_translation[0]),
99  camera_rotation_mat(3, 3, &stereo->camera_rotation[0][0]),
100  camera_essential_mat(3, 3, &stereo->camera_essential[0][0]),
101  camera_fundamental_mat(3, 3, &stereo->camera_fundamental[0][0])
102  {
103  // Correct reference counting.
104  t_stereo_camera_calibration *temp = NULL;
105  t_stereo_camera_calibration_reference(&temp, stereo);
106 
107  assert(isDataStorageValid());
108  }
109 
111  : StereoCameraCalibrationWrapper(allocData())
112  {
113 
114  // The function allocData returns with a ref count of one,
115  // the constructor increments the refcount with one,
116  // so to correct it we need to decrement the ref count with one.
117  t_stereo_camera_calibration *tmp = base;
118  t_stereo_camera_calibration_reference(&tmp, NULL);
119  }
120 
122  {
123  t_stereo_camera_calibration_reference(&base, NULL);
124  }
125 
126  bool
127  isDataStorageValid() const noexcept
128  {
129  return camera_translation_mat.size() == cv::Size(1, 3) &&
130  (double *)camera_translation_mat.data ==
131  &base->camera_translation[0] &&
132 
133  camera_rotation_mat.size() == cv::Size(3, 3) &&
134  (double *)camera_rotation_mat.data ==
135  &base->camera_rotation[0][0] &&
136 
137  camera_essential_mat.size() == cv::Size(3, 3) &&
138  (double *)camera_essential_mat.data ==
139  &base->camera_essential[0][0] &&
140 
141  camera_fundamental_mat.size() == cv::Size(3, 3) &&
142  (double *)camera_fundamental_mat.data ==
143  &base->camera_fundamental[0][0] &&
144 
145  view[0].isDataStorageValid() &&
146  view[1].isDataStorageValid();
147  }
148 };
149 
150 
151 /*!
152  * @brief An x,y pair of matrices for the remap() function.
153  *
154  * @see calibration_get_undistort_map
155  */
156 struct RemapPair
157 {
158  cv::Mat remap_x;
159  cv::Mat remap_y;
160 };
161 
162 /*!
163  * @brief Prepare undistortion/normalization remap structures for a rectilinear
164  * or fisheye image.
165  *
166  * @param calib A single camera calibration structure.
167  * @param rectify_transform_optional A rectification transform to apply, if
168  * desired.
169  * @param new_camera_matrix_optional Unlike OpenCV, the default/empty matrix
170  * here uses the input camera matrix as your output camera matrix.
171  */
172 RemapPair
174  t_camera_calibration &calib,
175  cv::InputArray rectify_transform_optional = cv::noArray(),
176  cv::Mat new_camera_matrix_optional = cv::Mat());
177 
178 /*!
179  * @brief Rectification, rotation, projection data for a single view in a stereo
180  * pair.
181  *
182  * @see StereoRectificationMaps
183  */
185 {
186  RemapPair rectify;
187  cv::Mat rotation_mat = {};
188  cv::Mat projection_mat = {};
189 };
190 
191 /*!
192  * @brief Rectification maps as well as transforms for a stereo camera.
193  *
194  * Computed in the constructor from saved calibration data.
195  */
197 {
198  ViewRectification view[2];
199 
200  //! Disparity and position to camera world coordinates.
201  cv::Mat disparity_to_depth_mat = {};
202 
203  /*!
204  * @brief Constructor - produces rectification data for a stereo camera
205  * based on calibration data.
206  */
208 };
209 
210 
211 /*!
212  * @brief Provides cached, precomputed access to normalized image coordinates
213  * from original, distorted ones.
214  *
215  * Populates internal structures using cv::undistortPoints() and performs
216  * subpixel sampling to interpolate for each query. Essentially, this class lets
217  * you perform cv::undistortPoints() while caching the initial setup work
218  * required for that function.
219  */
221 {
222 public:
223  /*!
224  * @brief Set up the precomputed cache for a given camera.
225  *
226  * @param size Size of the image in pixels
227  * @param intrinsics Camera intrinsics matrix
228  * @param distortion Distortion coefficients
229  *
230  * This overload applies no rectification (`R`) and uses a
231  * normalized/identity new camera matrix (`P`).
232  */
233  NormalizedCoordsCache(cv::Size size,
234  const cv::Matx33d &intrinsics,
235  const cv::Matx<double, 5, 1> &distortion);
236  /*!
237  * @brief Set up the precomputed cache for a given camera (overload for
238  * rectification and new camera matrix)
239  *
240  * @param size Size of the image in pixels
241  * @param intrinsics Camera intrinsics matrix
242  * @param distortion Distortion coefficients
243  * @param rectification Rectification matrix - corresponds to parameter
244  * `R` to cv::undistortPoints().
245  * @param new_camera_matrix A 3x3 new camera matrix - corresponds to
246  * parameter `P` to cv::undistortPoints().
247  */
248  NormalizedCoordsCache(cv::Size size,
249  const cv::Matx33d &intrinsics,
250  const cv::Matx<double, 5, 1> &distortion,
251  const cv::Matx33d &rectification,
252  const cv::Matx33d &new_camera_matrix);
253 
254  /*!
255  * @brief Set up the precomputed cache for a given camera. (overload for
256  * rectification and new projection matrix)
257  *
258  * @param size Size of the image in pixels
259  * @param intrinsics Camera intrinsics matrix
260  * @param distortion Distortion coefficients
261  * @param rectification Rectification matrix - corresponds to parameter
262  * `R` to cv::undistortPoints().
263  * @param new_projection_matrix A 3x4 new projection matrix -
264  * corresponds to parameter `P` to cv::undistortPoints().
265  */
267  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,
284  const cv::Mat &intrinsics,
285  const cv::Mat &distortion);
286 
287  /*!
288  * @brief Get normalized, undistorted coordinates from a point in the
289  * original (distorted, etc.) image.
290  *
291  * @param origCoords Image coordinates in original image
292  *
293  * @return Corresponding undistorted coordinates in a "normalized" image
294  */
295  cv::Vec2f
296  getNormalizedImageCoords(cv::Point2f origCoords) const;
297 
298  /*!
299  * @brief Get normalized vector in the camera-space direction
300  * corresponding to the original (distorted, etc.) image coordinates.
301  *
302  * Note that the Z component will be negative by convention.
303  */
304  cv::Vec3f
305  getNormalizedVector(cv::Point2f origCoords) const;
306 
307 private:
308  cv::Mat_<float> cacheX_;
309  cv::Mat_<float> cacheY_;
310 };
struct t_camera_calibration view[2]
Calibration of individual views/sensor.
Definition: t_tracking.h:117
Essential stereo calibration data wrapped for C++.
Definition: t_calibration_opencv.hpp:77
double distortion[XRT_DISTORTION_MAX_DIM]
Rectilinear distortion coefficients: k1, k2, p1, p2[, k3[, k4, k5, k6[, s1, s2, s3, s4]].
Definition: t_tracking.h:99
Rectification maps as well as transforms for a stereo camera.
Definition: t_calibration_opencv.hpp:196
Essential calibration data for a single camera, or single lens/sensor of a stereo camera...
Definition: t_tracking.h:89
double camera_rotation[3][3]
Rotation matrix from first to second in the stereo pair.
Definition: t_tracking.h:122
void t_stereo_camera_calibration_alloc(struct t_stereo_camera_calibration **out_c)
Allocates a new stereo calibration data, unreferences the old calib.
Definition: t_data_utils.c:17
double camera_translation[3]
Translation from first to second in the stereo pair.
Definition: t_tracking.h:120
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:39
double distortion_fisheye[4]
Fisheye camera distortion coefficients.
Definition: t_tracking.h:102
Provides cached, precomputed access to normalized image coordinates from original, distorted ones.
Definition: t_calibration_opencv.hpp:220
Stereo camera calibration data to be given to trackers.
Definition: t_tracking.h:111
Essential calibration data wrapped for C++.
Definition: t_calibration_opencv.hpp:30
Image size.
Definition: xrt_defines.h:216
#define XRT_DISTORTION_MAX_DIM
Maximum size of rectilinear distortion coefficient array.
Definition: t_tracking.h:83
double camera_fundamental[3][3]
Fundamental matrix.
Definition: t_tracking.h:127
double intrinsics[3][3]
Camera intrinsics matrix.
Definition: t_tracking.h:95
bool use_fisheye
Is the camera fisheye?
Definition: t_tracking.h:105
Rectification, rotation, projection data for a single view in a stereo pair.
Definition: t_calibration_opencv.hpp:184
double camera_essential[3][3]
Essential matrix.
Definition: t_tracking.h:125
An x,y pair of matrices for the remap() function.
Definition: t_calibration_opencv.hpp:156
struct xrt_size image_size_pixels
Source image size.
Definition: t_tracking.h:92
Tracking API interface.
bool isDataStorageValid() const noexcept
Try to verify nothing was reallocated.
Definition: t_calibration_opencv.hpp:54