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 = 0.0;
47  double y_scale = 0.0;
48  double cx_offset = 0.0;
49  double cy_offset = 0.0;
50 };
51 
52 ScaleT compute_scale(const crl::multisense::image::Config &config,
53  const crl::multisense::system::DeviceInfo& device_info)
54 {
55  const auto crop = config.camMode() == 2000 &&
58 
59  // crop mode causes the imager to behave completely like a CMV2000, but the device info imager height does not get modified
60  const auto imagerHeight = crop ? 1088 : device_info.imagerHeight;
61 
62  const double x_scale = 1.0 / ((static_cast<double>(device_info.imagerWidth) /
63  static_cast<double>(config.width())));
64 
65  const double y_scale = 1.0 / ((static_cast<double>(imagerHeight) /
66  static_cast<double>(config.height())));
67 
68  //
69  // In crop mode we want to offset our cx/cy values
70  // by the current crop offset. This is because the pixel size does not change in crop mode, and instead a cropped
71  // region of the original image is returned
72 
73  return ScaleT{x_scale,
74  y_scale,
75  0.0,
76  crop ? -config.offset()*y_scale : 0.0};
77 }
78 
79 }// namespace
80 
82  const crl::multisense::image::Header &chroma,
83  uint8_t *output)
84 {
85  const size_t rgb_stride = luma.width * 3;
86 
87  for(uint32_t y=0; y< luma.height; ++y)
88  {
89  const size_t row_offset = y * rgb_stride;
90 
91  for(uint32_t x=0; x< luma.width; ++x)
92  {
93  memcpy(output + row_offset + (3 * x), ycbcrToBgr<uint8_t>(luma, chroma, x, y).data(), 3);
94  }
95  }
96 }
97 
98 Eigen::Matrix4d makeQ(const crl::multisense::image::Config& config,
99  const crl::multisense::image::Calibration& calibration,
100  const crl::multisense::system::DeviceInfo& device_info)
101 {
102  Eigen::Matrix4d q_matrix = Eigen::Matrix4d::Zero();
103 
104  const auto scale = compute_scale(config, device_info);
105 
106  //
107  // Compute the Q matrix here, as image_geometery::StereoCameraModel does
108  // not allow for non-square pixels.
109  //
110  // FyTx 0 0 -FyCxTx
111  // 0 FxTx 0 -FxCyTx
112  // 0 0 0 FxFyTx
113  // 0 0 -Fy Fy(Cx - Cx')
114  //
115  const auto fx = calibration.left.P[0][0] * scale.x_scale;
116  const auto cx = calibration.left.P[0][2] * scale.x_scale + scale.cx_offset;
117  const auto fy = calibration.left.P[1][1] * scale.y_scale;
118  const auto cy = calibration.left.P[1][2] * scale.y_scale + scale.cy_offset;
119  const auto tx = calibration.right.P[0][3] / calibration.right.P[0][0];
120  const auto cx_prime = calibration.left.P[0][2] * scale.x_scale + scale.cx_offset;
121 
122  q_matrix(0,0) = fy * tx;
123  q_matrix(1,1) = fx * tx;
124  q_matrix(0,3) = -fy * cx * tx;
125  q_matrix(1,3) = -fx * cy * tx;
126  q_matrix(2,3) = fx * fy * tx;
127  q_matrix(3,2) = -fy;
128  q_matrix(3,3) = fy * (cx - cx_prime);
129 
130  return q_matrix;
131 }
132 
133 sensor_msgs::CameraInfo makeCameraInfo(const crl::multisense::image::Config& config,
135  const crl::multisense::system::DeviceInfo& device_info)
136 {
137  const auto scale = compute_scale(config, device_info);
138 
139  sensor_msgs::CameraInfo camera_info;
140 
141  camera_info.width = config.width();
142  camera_info.height = config.height();
143 
144  camera_info.P[0] = calibration.P[0][0] * scale.x_scale;
145  camera_info.P[1] = calibration.P[0][1];
146  camera_info.P[2] = calibration.P[0][2] * scale.x_scale + scale.cx_offset;
147  camera_info.P[3] = calibration.P[0][3] * scale.x_scale;
148  camera_info.P[4] = calibration.P[1][0];
149  camera_info.P[5] = calibration.P[1][1] * scale.y_scale;
150  camera_info.P[6] = calibration.P[1][2] * scale.y_scale + scale.cy_offset;
151  camera_info.P[7] = calibration.P[1][3];
152  camera_info.P[8] = calibration.P[2][0];
153  camera_info.P[9] = calibration.P[2][1];
154  camera_info.P[10] = calibration.P[2][2];
155  camera_info.P[11] = calibration.P[2][3];
156 
157  camera_info.K[0] = calibration.M[0][0] * scale.x_scale;
158  camera_info.K[1] = calibration.M[0][1];
159  camera_info.K[2] = calibration.M[0][2] * scale.x_scale + scale.cx_offset;
160  camera_info.K[3] = calibration.M[1][0];
161  camera_info.K[4] = calibration.M[1][1] * scale.y_scale;
162  camera_info.K[5] = calibration.M[1][2] * scale.y_scale + scale.cy_offset;
163  camera_info.K[6] = calibration.M[2][0];
164  camera_info.K[7] = calibration.M[2][1];
165  camera_info.K[8] = calibration.M[2][2];
166 
167  camera_info.R[0] = calibration.R[0][0];
168  camera_info.R[1] = calibration.R[0][1];
169  camera_info.R[2] = calibration.R[0][2];
170  camera_info.R[3] = calibration.R[1][0];
171  camera_info.R[4] = calibration.R[1][1];
172  camera_info.R[5] = calibration.R[1][2];
173  camera_info.R[6] = calibration.R[2][0];
174  camera_info.R[7] = calibration.R[2][1];
175  camera_info.R[8] = calibration.R[2][2];
176 
177  //
178  // Distortion coefficients follow OpenCV's convention.
179  // k1, k2, p1, p2, k3, k4, k5, k6
180 
181  camera_info.D.resize(8);
182  for (size_t i=0 ; i < 8 ; ++i)
183  {
184  camera_info.D[i] = calibration.D[i];
185  }
186 
187  //
188  // MultiSense cameras support both the full 8 parameter rational_polynomial
189  // model and the simplified 5 parameter plum_bob model. If the last 3
190  // parameters of the distortion model are 0 then the camera is using
191  // the simplified plumb_bob model
192 
193  if (calibration.D[7] == 0.0 && calibration.D[6] == 0.0 && calibration.D[5] == 0.0)
194  {
195  camera_info.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
196  }
197  else
198  {
199  camera_info.distortion_model = sensor_msgs::distortion_models::RATIONAL_POLYNOMIAL;
200  }
201 
202  return camera_info;
203 }
204 
207  const crl::multisense::system::DeviceInfo& device_info)
208 {
210 
211  const auto scale = compute_scale(config, device_info);
212 
213  const cv::Matx33d K(calibration.M[0][0] * scale.x_scale,
214  calibration.M[0][1],
215  calibration.M[0][2] * scale.x_scale + scale.cx_offset,
216  calibration.M[1][0],
217  calibration.M[1][1] * scale.y_scale,
218  calibration.M[1][2] * scale.y_scale + scale.cy_offset,
219  calibration.M[2][0],
220  calibration.M[2][1],
221  calibration.M[2][2]);
222 
223  const cv::Matx33d R(calibration.R[0][0],
224  calibration.R[0][1],
225  calibration.R[0][2],
226  calibration.R[1][0],
227  calibration.R[1][1],
228  calibration.R[1][2],
229  calibration.R[2][0],
230  calibration.R[2][1],
231  calibration.R[2][2]);
232 
233  const cv::Matx34d P(calibration.P[0][0] * scale.x_scale,
234  calibration.P[0][1],
235  calibration.P[0][2] * scale.x_scale + scale.cx_offset,
236  calibration.P[0][3] * scale.x_scale,
237  calibration.P[1][0],
238  calibration.P[1][1] * scale.y_scale,
239  calibration.P[1][2] * scale.y_scale + scale.cy_offset,
240  calibration.P[1][3],
241  calibration.P[2][0],
242  calibration.P[2][1],
243  calibration.P[2][2],
244  calibration.P[2][3]);
245 
246  const bool plumbob = calibration.D[7] == 0.0 && calibration.D[6] == 0.0 && calibration.D[5] == 0.0;
247 
248  cv::Mat D(plumbob ? 5 : 8, 1, CV_64FC1);
249  for (int i = 0; i < D.rows ; ++i)
250  {
251  D.at<double>(i) = calibration.D[i];
252  }
253 
254  cv::initUndistortRectifyMap(K, D, R, P, cv::Size(config.width(), config.height()), CV_32FC1, remap.map1, remap.map2);
255 
256  return remap;
257 }
258 
260  const crl::multisense::image::Calibration& calibration,
261  const crl::multisense::system::DeviceInfo& device_info):
262  config_(config),
263  calibration_(calibration),
264  device_info_(device_info),
265  q_matrix_(makeQ(config_, calibration_, device_info_)),
266  left_camera_info_(makeCameraInfo(config_, calibration_.left, device_info_)),
267  right_camera_info_(makeCameraInfo(config_, calibration_.right, device_info_)),
268  aux_camera_info_(makeCameraInfo(config_, calibration_.aux, device_info_)),
269  left_remap_(std::make_shared<RectificationRemapT>(makeRectificationRemap(config_, calibration_.left, device_info_))),
270  right_remap_(std::make_shared<RectificationRemapT>(makeRectificationRemap(config_, calibration_.right, device_info_)))
271 {
272 }
273 
275 {
276  //
277  // Only update the calibration if the resolution changed.
278 
279  if (config_.width() == config.width() && config_.height() == config.height())
280  {
281  std::lock_guard<std::mutex> lock(mutex_);
282  config_ = config;
283  return;
284  }
285 
286  auto q_matrix = makeQ(config, calibration_, device_info_);
287  auto left_camera_info = makeCameraInfo(config, calibration_.left, device_info_);
288  auto right_camera_info = makeCameraInfo(config, calibration_.right, device_info_);
290  auto left_remap = std::make_shared<RectificationRemapT>(makeRectificationRemap(config, calibration_.left, device_info_));
291  auto right_remap = std::make_shared<RectificationRemapT>(makeRectificationRemap(config, calibration_.right, device_info_));
292 
293  std::lock_guard<std::mutex> lock(mutex_);
294 
295  config_ = config;
296  q_matrix_ = std::move(q_matrix);
297  left_camera_info_ = std::move(left_camera_info);
298  right_camera_info_ = std::move(right_camera_info);
299  left_remap_ = left_remap;
300  right_remap_ = right_remap;
301 }
302 
304 {
305  std::lock_guard<std::mutex> lock(mutex_);
306 
307  return config_;
308 }
309 
310 Eigen::Matrix4d StereoCalibrationManger::Q() const
311 {
312  std::lock_guard<std::mutex> lock(mutex_);
313 
314  return q_matrix_;
315 }
316 
318 {
319  std::lock_guard<std::mutex> lock(mutex_);
320 
321  //
322  // The right camera projection matrix is of the form:
323  //
324  // [fx, 0, cx, t * fx]
325  // [ 0, fy, cy, 0 ]
326  // [ 0, 0, 1, 0 ]
327  //
328  // divide the t * fx term by fx to get t
329 
330  return right_camera_info_.P[3] / right_camera_info_.P[0];
331 }
332 
334 {
335  std::lock_guard<std::mutex> lock(mutex_);
336 
337  //
338  // The aux camera projection matrix is of the form:
339  //
340  // [fx, 0, cx, t * fx]
341  // [ 0, fy, cy, 0 ]
342  // [ 0, 0, 1, 0 ]
343  //
344  // divide the t * fx term by fx to get t
345 
346  return aux_camera_info_.P[3] / aux_camera_info_.P[0];
347 }
348 
350 {
351  return std::isfinite(aux_T());
352 }
353 
354 sensor_msgs::CameraInfo StereoCalibrationManger::leftCameraInfo(const std::string& frame_id,
355  const ros::Time& stamp) const
356 {
357  std::lock_guard<std::mutex> lock(mutex_);
358 
359  auto camera_info = left_camera_info_;
360  camera_info.header.frame_id = frame_id;
361  camera_info.header.stamp = stamp;
362 
363  return camera_info;
364 }
365 
366 sensor_msgs::CameraInfo StereoCalibrationManger::rightCameraInfo(const std::string& frame_id,
367  const ros::Time& stamp) const
368 {
369  std::lock_guard<std::mutex> lock(mutex_);
370 
371  auto camera_info = right_camera_info_;
372  camera_info.header.frame_id = frame_id;
373  camera_info.header.stamp = stamp;
374 
375  return camera_info;
376 }
377 
378 sensor_msgs::CameraInfo StereoCalibrationManger::auxCameraInfo(const std::string& frame_id,
379  const ros::Time& stamp) const
380 {
381  std::lock_guard<std::mutex> lock(mutex_);
382 
383  auto camera_info = aux_camera_info_;
384  camera_info.header.frame_id = frame_id;
385  camera_info.header.stamp = stamp;
386 
387  return camera_info;
388 }
389 
390 std::shared_ptr<RectificationRemapT> StereoCalibrationManger::leftRemap() const
391 {
392  std::lock_guard<std::mutex> lock(mutex_);
393 
394  return left_remap_;
395 }
396 
397 std::shared_ptr<RectificationRemapT> StereoCalibrationManger::rightRemap() const
398 {
399  std::lock_guard<std::mutex> lock(mutex_);
400 
401  return right_remap_;
402 }
403 
404 }// namespace
double T() const
Translation which transforms points from the right camera frame into the left camera frame...
sensor_msgs::CameraInfo auxCameraInfo(const std::string &frame_id, const ros::Time &stamp) const
double cx_offset
std::shared_ptr< RectificationRemapT > right_remap_
const std::string RATIONAL_POLYNOMIAL
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)
static CRL_CONSTEXPR uint32_t IMAGER_TYPE_CMV4000_COLOR
sensor_msgs::CameraInfo leftCameraInfo(const std::string &frame_id, const ros::Time &stamp) const
RectificationRemapT makeRectificationRemap(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration::Data &calibration, const crl::multisense::system::DeviceInfo &device_info)
bool validAux() const
Determine if the Aux calibration is valid.
double y_scale
crl::multisense::image::Config config_
crl::multisense::image::Config config() const
sensor_msgs::CameraInfo rightCameraInfo(const std::string &frame_id, const ros::Time &stamp) const
void updateConfig(const crl::multisense::image::Config &config)
const crl::multisense::system::DeviceInfo & device_info_
ROSCPP_DECL std::string remap(const std::string &name)
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)
static CRL_CONSTEXPR uint32_t IMAGER_TYPE_CMV4000_GREY
const crl::multisense::image::Calibration calibration_
double cy_offset
double aux_T() const
Translation which transforms points from the aux camera frame into the left camera frame...
std::shared_ptr< RectificationRemapT > rightRemap() const
EIGEN_MAKE_ALIGNED_OPERATOR_NEW StereoCalibrationManger(const crl::multisense::image::Config &config, const crl::multisense::image::Calibration &calibration, const crl::multisense::system::DeviceInfo &device_info)
std::shared_ptr< RectificationRemapT > left_remap_
std::shared_ptr< RectificationRemapT > leftRemap() const
double x_scale
Eigen::Matrix4d Q() const
Q stereo reprojection matrix see: https://docs.opencv.org/4.3.0/d9/d0c/group__calib3d.html#ga1bc1152bd57d63bc524204f21fde6e02.
sensor_msgs::CameraInfo right_camera_info_


multisense_ros
Author(s):
autogenerated on Sun Mar 14 2021 02:34:55