camera_utilities.cpp
Go to the documentation of this file.
1 
34 #include <algorithm>
35 
37 
39 
40 namespace multisense_ros {
41 
42 namespace {
43 
44 struct ScaleT
45 {
46  double x_scale = 1.0;
47  double y_scale = 1.0;
48 };
49 
50 ScaleT compute_scale(const crl::multisense::image::Config &config,
51  const crl::multisense::system::DeviceInfo& device_info)
52 {
53  const auto imagerHeight = device_info.imagerHeight;
54 
55  const double x_scale = 1.0 / ((static_cast<double>(device_info.imagerWidth) /
56  static_cast<double>(config.width())));
57 
58  const double y_scale = 1.0 / ((static_cast<double>(imagerHeight) /
59  static_cast<double>(config.height())));
60 
61  return ScaleT{x_scale,
62  y_scale};
63 }
64 
65 }// namespace
66 
68  const crl::multisense::image::Header &chroma,
69  uint8_t *output)
70 {
71  const size_t rgb_stride = luma.width * 3;
72 
73  for(uint32_t y=0; y< luma.height; ++y)
74  {
75  const size_t row_offset = y * rgb_stride;
76 
77  for(uint32_t x=0; x< luma.width; ++x)
78  {
79  memcpy(output + row_offset + (3 * x), ycbcrToBgr<uint8_t>(luma, chroma, x, y).data(), 3);
80  }
81  }
82 }
83 
84 Eigen::Matrix4d makeQ(const crl::multisense::image::Config& config,
85  const crl::multisense::image::Calibration& calibration,
86  const crl::multisense::system::DeviceInfo& device_info)
87 {
88  Eigen::Matrix4d q_matrix = Eigen::Matrix4d::Zero();
89 
90  const auto scale = compute_scale(config, device_info);
91 
92  //
93  // Compute the Q matrix here, as image_geometery::StereoCameraModel does
94  // not allow for non-square pixels.
95  //
96  // FyTx 0 0 -FyCxTx
97  // 0 FxTx 0 -FxCyTx
98  // 0 0 0 FxFyTx
99  // 0 0 -Fy Fy(Cx - Cx')
100  //
101  const auto fx = calibration.left.P[0][0] * scale.x_scale;
102  const auto cx = calibration.left.P[0][2] * scale.x_scale;
103  const auto fy = calibration.left.P[1][1] * scale.y_scale;
104  const auto cy = calibration.left.P[1][2] * scale.y_scale;
105  const auto tx = calibration.right.P[0][3] / calibration.right.P[0][0];
106  const auto cx_prime = calibration.right.P[0][2] * scale.x_scale;
107 
108  q_matrix(0,0) = fy * tx;
109  q_matrix(1,1) = fx * tx;
110  q_matrix(0,3) = -fy * cx * tx;
111  q_matrix(1,3) = -fx * cy * tx;
112  q_matrix(2,3) = fx * fy * tx;
113  q_matrix(3,2) = -fy;
114  q_matrix(3,3) = fy * (cx - cx_prime);
115 
116  return q_matrix;
117 }
118 
119 sensor_msgs::CameraInfo makeCameraInfo(const crl::multisense::image::Config& config,
121  const ScaleT &scale)
122 {
123  sensor_msgs::CameraInfo camera_info;
124 
125  camera_info.width = config.width();
126  camera_info.height = config.height();
127 
128  camera_info.P[0] = calibration.P[0][0] * scale.x_scale;
129  camera_info.P[1] = calibration.P[0][1];
130  camera_info.P[2] = calibration.P[0][2] * scale.x_scale;
131  camera_info.P[3] = calibration.P[0][3] * scale.x_scale;
132  camera_info.P[4] = calibration.P[1][0];
133  camera_info.P[5] = calibration.P[1][1] * scale.y_scale;
134  camera_info.P[6] = calibration.P[1][2] * scale.y_scale;
135  camera_info.P[7] = calibration.P[1][3];
136  camera_info.P[8] = calibration.P[2][0];
137  camera_info.P[9] = calibration.P[2][1];
138  camera_info.P[10] = calibration.P[2][2];
139  camera_info.P[11] = calibration.P[2][3];
140 
141  camera_info.K[0] = calibration.M[0][0] * scale.x_scale;
142  camera_info.K[1] = calibration.M[0][1];
143  camera_info.K[2] = calibration.M[0][2] * scale.x_scale;
144  camera_info.K[3] = calibration.M[1][0];
145  camera_info.K[4] = calibration.M[1][1] * scale.y_scale;
146  camera_info.K[5] = calibration.M[1][2] * scale.y_scale;
147  camera_info.K[6] = calibration.M[2][0];
148  camera_info.K[7] = calibration.M[2][1];
149  camera_info.K[8] = calibration.M[2][2];
150 
151  camera_info.R[0] = calibration.R[0][0];
152  camera_info.R[1] = calibration.R[0][1];
153  camera_info.R[2] = calibration.R[0][2];
154  camera_info.R[3] = calibration.R[1][0];
155  camera_info.R[4] = calibration.R[1][1];
156  camera_info.R[5] = calibration.R[1][2];
157  camera_info.R[6] = calibration.R[2][0];
158  camera_info.R[7] = calibration.R[2][1];
159  camera_info.R[8] = calibration.R[2][2];
160 
161  //
162  // Distortion coefficients follow OpenCV's convention.
163  // k1, k2, p1, p2, k3, k4, k5, k6
164 
165  camera_info.D.resize(8);
166  for (size_t i=0 ; i < 8 ; ++i)
167  {
168  camera_info.D[i] = calibration.D[i];
169  }
170 
171  //
172  // MultiSense cameras support both the full 8 parameter rational_polynomial
173  // model and the simplified 5 parameter plum_bob model. If the last 3
174  // parameters of the distortion model are 0 then the camera is using
175  // the simplified plumb_bob model
176 
177  if (calibration.D[7] == 0.0 && calibration.D[6] == 0.0 && calibration.D[5] == 0.0)
178  {
179  camera_info.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
180  }
181  else
182  {
183  camera_info.distortion_model = sensor_msgs::distortion_models::RATIONAL_POLYNOMIAL;
184  }
185 
186  return camera_info;
187 }
188 
191  const crl::multisense::system::DeviceInfo& device_info)
192 {
194 
195  const auto scale = compute_scale(config, device_info);
196 
197  const cv::Matx33d K(calibration.M[0][0] * scale.x_scale,
198  calibration.M[0][1],
199  calibration.M[0][2] * scale.x_scale,
200  calibration.M[1][0],
201  calibration.M[1][1] * scale.y_scale,
202  calibration.M[1][2] * scale.y_scale,
203  calibration.M[2][0],
204  calibration.M[2][1],
205  calibration.M[2][2]);
206 
207  const cv::Matx33d R(calibration.R[0][0],
208  calibration.R[0][1],
209  calibration.R[0][2],
210  calibration.R[1][0],
211  calibration.R[1][1],
212  calibration.R[1][2],
213  calibration.R[2][0],
214  calibration.R[2][1],
215  calibration.R[2][2]);
216 
217  const cv::Matx34d P(calibration.P[0][0] * scale.x_scale,
218  calibration.P[0][1],
219  calibration.P[0][2] * scale.x_scale,
220  calibration.P[0][3] * scale.x_scale,
221  calibration.P[1][0],
222  calibration.P[1][1] * scale.y_scale,
223  calibration.P[1][2] * scale.y_scale,
224  calibration.P[1][3],
225  calibration.P[2][0],
226  calibration.P[2][1],
227  calibration.P[2][2],
228  calibration.P[2][3]);
229 
230  const bool plumbob = calibration.D[7] == 0.0 && calibration.D[6] == 0.0 && calibration.D[5] == 0.0;
231 
232  cv::Mat D(plumbob ? 5 : 8, 1, CV_64FC1);
233  for (int i = 0; i < D.rows ; ++i)
234  {
235  D.at<double>(i) = calibration.D[i];
236  }
237 
238  cv::initUndistortRectifyMap(K, D, R, P, cv::Size(config.width(), config.height()), CV_32FC1, remap.map1, remap.map2);
239 
240  return remap;
241 }
242 
244  const crl::multisense::image::Calibration& calibration,
245  const crl::multisense::system::DeviceInfo& device_info):
246  config_(config),
247  calibration_(calibration),
248  device_info_(device_info),
249  q_matrix_(makeQ(config_, calibration_, device_info_)),
250  left_camera_info_(makeCameraInfo(config_, calibration_.left, compute_scale(config_, device_info_))),
251  right_camera_info_(makeCameraInfo(config_, calibration_.right, compute_scale(config_, device_info_))),
252  aux_camera_info_(makeCameraInfo(config_, calibration_.aux, config_.cameraProfile() == crl::multisense::Full_Res_Aux_Cam ?
253  ScaleT{1., 1.} : compute_scale(config_, device_info_))),
254  left_remap_(std::make_shared<RectificationRemapT>(makeRectificationRemap(config_, calibration_.left, device_info_))),
255  right_remap_(std::make_shared<RectificationRemapT>(makeRectificationRemap(config_, calibration_.right, device_info_)))
256 {
257 }
258 
260 {
261  //
262  // Only update the calibration if the resolution changed.
263 
264  if (config_.width() == config.width() && config_.height() == config.height() && config_.cameraProfile() == config.cameraProfile())
265  {
266  std::lock_guard<std::mutex> lock(mutex_);
267  config_ = config;
268  return;
269  }
270 
271  auto q_matrix = makeQ(config, calibration_, device_info_);
272  auto left_camera_info = makeCameraInfo(config, calibration_.left, compute_scale(config, device_info_));
273  auto right_camera_info = makeCameraInfo(config, calibration_.right, compute_scale(config, device_info_));
274 
275  const ScaleT aux_scale = config.cameraProfile() == crl::multisense::Full_Res_Aux_Cam ?
276  ScaleT{1., 1.} : compute_scale(config, device_info_);
277 
278  auto aux_camera_info = makeCameraInfo(config, calibration_.aux, aux_scale);
279  auto left_remap = std::make_shared<RectificationRemapT>(makeRectificationRemap(config, calibration_.left, device_info_));
280  auto right_remap = std::make_shared<RectificationRemapT>(makeRectificationRemap(config, calibration_.right, device_info_));
281 
282  std::lock_guard<std::mutex> lock(mutex_);
283 
284  config_ = config;
285  q_matrix_ = std::move(q_matrix);
286  left_camera_info_ = std::move(left_camera_info);
287  right_camera_info_ = std::move(right_camera_info);
288  aux_camera_info_ = std::move(aux_camera_info);
289  left_remap_ = left_remap;
290  right_remap_ = right_remap;
291 }
292 
294 {
295  std::lock_guard<std::mutex> lock(mutex_);
296 
297  return config_;
298 }
299 
300 Eigen::Matrix4d StereoCalibrationManager::Q() const
301 {
302  std::lock_guard<std::mutex> lock(mutex_);
303 
304  return q_matrix_;
305 }
306 
308 {
309  std::lock_guard<std::mutex> lock(mutex_);
310 
311  //
312  // The right camera projection matrix is of the form:
313  //
314  // [fx, 0, cx, t * fx]
315  // [ 0, fy, cy, 0 ]
316  // [ 0, 0, 1, 0 ]
317  //
318  // divide the t * fx term by fx to get t
319 
320  return right_camera_info_.P[3] / right_camera_info_.P[0];
321 }
322 
323 Eigen::Vector3d StereoCalibrationManager::aux_T() const
324 {
325  std::lock_guard<std::mutex> lock(mutex_);
326 
327  //
328  // The aux camera projection matrix is of the form:
329  //
330  // [fx, 0, cx, tx * fx]
331  // [ 0, fy, cy, ty * fy]
332  // [ 0, 0, 1, tz ]
333  //
334  // divide the t * fx term by fx to get t
335 
336  return Eigen::Vector3d{aux_camera_info_.P[3] / aux_camera_info_.P[0],
338  aux_camera_info_.P[11]};
339 }
340 
341 Eigen::Vector3f StereoCalibrationManager::reproject(size_t u, size_t v, double d) const
342 {
343  std::lock_guard<std::mutex> lock(mutex_);
344 
346 }
347 
348 Eigen::Vector3f StereoCalibrationManager::reproject(size_t u,
349  size_t v,
350  double d,
351  const sensor_msgs::CameraInfo &left_camera_info,
352  const sensor_msgs::CameraInfo &right_camera_info) const
353 {
354  if (d == 0.0)
355  {
356  return Eigen::Vector3f{std::numeric_limits<float>::max(),
357  std::numeric_limits<float>::max(),
358  std::numeric_limits<float>::max()};
359  }
360 
361 
362  const double &fx = left_camera_info.P[0];
363  const double &fy = left_camera_info.P[5];
364  const double &cx = left_camera_info.P[2];
365  const double &cy = left_camera_info.P[6];
366  const double &cx_right = right_camera_info.P[2];
367  const double tx = right_camera_info.P[3] / right_camera_info.P[0];
368 
369  const double xB = ((fy * tx) * u) + (-fy * cx * tx);
370  const double yB = ((fx * tx) * v) + (-fx * cy * tx);
371  const double zB = (fx * fy * tx);
372  const double invB = 1. / (-fy * d) + (fy * (cx - cx_right));
373 
374  return Eigen::Vector3f{static_cast<float>(xB * invB), static_cast<float>(yB * invB), static_cast<float>(zB * invB)};
375 }
376 
377 Eigen::Vector2f StereoCalibrationManager::rectifiedAuxProject(const Eigen::Vector3f &left_rectified_point) const
378 {
379  std::lock_guard<std::mutex> lock(mutex_);
380 
381  return rectifiedAuxProject(left_rectified_point, aux_camera_info_);
382 }
383 
384 Eigen::Vector2f StereoCalibrationManager::rectifiedAuxProject(const Eigen::Vector3f &left_rectified_point,
385  const sensor_msgs::CameraInfo &aux_camera_info) const
386 {
387  const double &fx = aux_camera_info.P[0];
388  const double &fy = aux_camera_info.P[5];
389  const double &cx = aux_camera_info.P[2];
390  const double &cy = aux_camera_info.P[6];
391  const double &fxtx = aux_camera_info.P[3];
392  const double &fyty = aux_camera_info.P[7];
393  const double &tz = aux_camera_info.P[11];
394 
395  //
396  // Project the left_rectified_point into the aux image using the auxP matrix
397  //
398  const double uB = (fx * left_rectified_point(0) + (cx * left_rectified_point(2)) + fxtx);
399  const double vB = (fy * left_rectified_point(1) + (cy * left_rectified_point(2)) + fyty);
400  const double invB = 1.0 / (left_rectified_point(2) + tz);
401 
402  return Eigen::Vector2f{static_cast<float>(uB * invB), static_cast<float>(vB * invB)};
403 }
404 
406 {
407  std::lock_guard<std::mutex> lock(mutex_);
408 
410 }
411 
413 {
414  std::lock_guard<std::mutex> lock(mutex_);
415 
417  {
419  }
420 
421  const auto scale = compute_scale(config_, device_info_);
422 
423  return OperatingResolutionT{config_.width(), static_cast<size_t>(S30_AUX_CAM_HEIGHT * scale.y_scale)};
424 
425 }
426 
428 {
429  return std::isfinite(T());
430 }
431 
433 {
434  const Eigen::Vector3d auxT = aux_T();
435  return std::isfinite(auxT(0)) && std::isfinite(auxT(1)) && std::isfinite(auxT(2)) ;
436 }
437 
438 sensor_msgs::CameraInfo StereoCalibrationManager::leftCameraInfo(const std::string& frame_id,
439  const ros::Time& stamp) const
440 {
441  std::lock_guard<std::mutex> lock(mutex_);
442 
443  auto camera_info = left_camera_info_;
444  camera_info.header.frame_id = frame_id;
445  camera_info.header.stamp = stamp;
446 
447  return camera_info;
448 }
449 
450 sensor_msgs::CameraInfo StereoCalibrationManager::rightCameraInfo(const std::string& frame_id,
451  const ros::Time& stamp) const
452 {
453  std::lock_guard<std::mutex> lock(mutex_);
454 
455  auto camera_info = right_camera_info_;
456  camera_info.header.frame_id = frame_id;
457  camera_info.header.stamp = stamp;
458 
459  return camera_info;
460 }
461 sensor_msgs::CameraInfo StereoCalibrationManager::auxCameraInfo(const std::string& frame_id,
462  const ros::Time& stamp,
463  const OperatingResolutionT &resolution) const
464 {
465  return auxCameraInfo(frame_id, stamp, resolution.width, resolution.height);
466 }
467 
468 sensor_msgs::CameraInfo StereoCalibrationManager::auxCameraInfo(const std::string& frame_id,
469  const ros::Time& stamp,
470  size_t width,
471  size_t height) const
472 {
473  std::lock_guard<std::mutex> lock(mutex_);
474 
475  auto camera_info = aux_camera_info_;
476  camera_info.header.frame_id = frame_id;
477  camera_info.header.stamp = stamp;
478  camera_info.width = width;
479  camera_info.height = height;
480 
481  return camera_info;
482 }
483 
484 std::shared_ptr<RectificationRemapT> StereoCalibrationManager::leftRemap() const
485 {
486  std::lock_guard<std::mutex> lock(mutex_);
487 
488  return left_remap_;
489 }
490 
491 std::shared_ptr<RectificationRemapT> StereoCalibrationManager::rightRemap() const
492 {
493  std::lock_guard<std::mutex> lock(mutex_);
494 
495  return right_remap_;
496 }
497 
498 }// namespace
const std::string RATIONAL_POLYNOMIAL
Eigen::Matrix4d Q() const
Q stereo reprojection matrix see: https://docs.opencv.org/4.3.0/d9/d0c/group__calib3d.html#ga1bc1152bd57d63bc524204f21fde6e02.
static CRL_CONSTEXPR CameraProfile Full_Res_Aux_Cam
sensor_msgs::CameraInfo makeCameraInfo(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration::Data &calibration, const crl::multisense::system::DeviceInfo &device_info, bool scale_calibration)
sensor_msgs::CameraInfo auxCameraInfo(const std::string &frame_id, const ros::Time &stamp, const OperatingResolutionT &resolution) const
void updateConfig(const crl::multisense::image::Config &config)
OperatingResolutionT operatingStereoResolution() const
Get the current main stereo pair operating resolution. This resolution applies for both the mono and ...
const crl::multisense::system::DeviceInfo & device_info_
RectificationRemapT makeRectificationRemap(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration::Data &calibration, const crl::multisense::system::DeviceInfo &device_info)
static constexpr size_t S30_AUX_CAM_HEIGHT
OperatingResolutionT operatingAuxResolution() const
Get the current aux camera operating resolution. This resolution applies for just the mono topics...
bool validAux() const
Determine if the Aux calibration is valid.
double y_scale
data
EIGEN_MAKE_ALIGNED_OPERATOR_NEW StereoCalibrationManager(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration &calibration, const crl::multisense::system::DeviceInfo &device_info)
Eigen::Vector3f reproject(size_t u, size_t v, double d) const
Reproject disparity values into 3D.
sensor_msgs::CameraInfo leftCameraInfo(const std::string &frame_id, const ros::Time &stamp) const
static constexpr size_t S30_AUX_CAM_WIDTH
ROSCPP_DECL std::string remap(const std::string &name)
std::shared_ptr< RectificationRemapT > rightRemap() const
double T() const
Translation which transforms points from the rectified left camera frame into the recified right came...
Eigen::Matrix4d makeQ(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration &calibration, const crl::multisense::system::DeviceInfo &device_info)
constexpr Eigen::Matrix< T, 3, 1 > ycbcrToBgr(const crl::multisense::image::Header &luma, const crl::multisense::image::Header &chroma, size_t u, size_t v)
crl::multisense::image::Config config() const
const crl::multisense::image::Calibration calibration_
std::shared_ptr< RectificationRemapT > leftRemap() const
std::shared_ptr< RectificationRemapT > left_remap_
std::shared_ptr< RectificationRemapT > right_remap_
bool validRight() const
Determine if the Right calibration is valid.
crl::multisense::image::Config config_
CameraProfile cameraProfile() const
sensor_msgs::CameraInfo rightCameraInfo(const std::string &frame_id, const ros::Time &stamp) const
Eigen::Vector2f rectifiedAuxProject(const Eigen::Vector3f &left_rectified_point) const
Project points corresponding to disparity measurements in the left rectified image frame into the aux...
Eigen::Vector3d aux_T() const
Translation which transforms points from the rectified left camera frame into the rectified aux camer...
double x_scale


multisense_ros
Author(s):
autogenerated on Sat Jun 24 2023 03:01:30