rgbd
conversions.cpp
Go to the documentation of this file.
1 #include "rgbd/ros/conversions.h"
2 
3 #include <boost/iostreams/filtering_streambuf.hpp>
4 #include <boost/iostreams/copy.hpp>
5 #include <boost/iostreams/filter/gzip.hpp>
6 #include <boost/iostreams/filter/zstd.hpp>
7 
8 #include <cv_bridge/cv_bridge.h>
9 
12 
13 #include <opencv2/core/core.hpp>
14 #include <opencv2/imgcodecs.hpp>
15 
16 #include <ros/console.h>
17 
18 #include <sensor_msgs/distortion_models.h>
19 
21 
22 #include <sstream>
23 
24 #include "rgbd/serialization.h"
25 
26 
27 namespace rgbd
28 {
29 
30 // ----------------------------------------------------------------------------------------------------
31 
32 bool convert(const cv::Mat& image, sensor_msgs::Image& image_msg)
33 {
34  cv_bridge::CvImage image_cv_bridge;
35 
36  if (image.type() == CV_32FC1) // Depth image
37  image_cv_bridge.encoding = "32FC1";
38  else if (image.type() == CV_8UC3) // RGB image;
39  image_cv_bridge.encoding = "bgr8";
40  else
41  return false;
42 
43  image_cv_bridge.image = image;
44  image_cv_bridge.toImageMsg(image_msg);
45 
46  return true;
47 }
48 
49 // ----------------------------------------------------------------------------------------------------
50 
51 bool convert(const cv::Mat& image,
52  const geo::DepthCamera& cam_model,
53  sensor_msgs::Image& image_msg,
54  sensor_msgs::CameraInfo& cam_model_msg)
55 {
56  geo::convert(cam_model, cam_model_msg);
57  int width = static_cast<int>(cam_model_msg.width);
58  int height = static_cast<int>(cam_model_msg.height);
59 
60  cv_bridge::CvImage image_cv_bridge;
61 
62  cv::Mat img_rect;
63  if (image.type() == CV_32FC1) // Depth image
64  {
65  image_cv_bridge.encoding = "32FC1";
66  img_rect = cv::Mat(height, width, CV_32FC1, cv::Scalar(0.));
67  }
68  else if (image.type() == CV_8UC3) // RGB image
69  {
70  image_cv_bridge.encoding = "bgr8";
71  img_rect = cv::Mat(height, width, CV_8UC3, cv::Scalar(0, 0, 0));
72  }
73  else
74  return false;
75 
76  // Create a ROI for the part of the image that we need to copy
77  cv::Rect crop_rect(0, 0, std::min(img_rect.cols, image.cols), std::min(img_rect.rows, image.rows));
78  image(crop_rect).copyTo(img_rect.rowRange(0, crop_rect.height).colRange(0, crop_rect.width));
79 
80  image_cv_bridge.image = img_rect;
81  image_cv_bridge.toImageMsg(image_msg);
82 
83  return true;
84 }
85 
86 // ----------------------------------------------------------------------------------------------------
87 
88 bool convert(const rgbd_msgs::RGBDConstPtr& msg, rgbd::Image*& image)
89 {
90  if (!image)
91  image = new rgbd::Image;
92 
93  if (msg->version == 1)
94  {
95  // - - - - - - - - - - - - - - - - RGB IMAGE - - - - - - - - - - - - - - - -
96 
97  image->rgb_image_ = cv::imdecode(cv::Mat(msg->rgb), cv::IMREAD_UNCHANGED);
98 
99  // - - - - - - - - - - - - - - - - DEPTH IMAGE - - - - - - - - - - - - - - - -
100 
101  float depthQuantA = static_cast<float>(msg->params[0]);
102  float depthQuantB = static_cast<float>(msg->params[1]);
103 
104  cv::Mat decompressed = cv::imdecode(msg->depth, cv::IMREAD_UNCHANGED);
105  image->depth_image_ = cv::Mat(decompressed.size(), CV_32FC1);
106 
107  // Depth conversion
108  cv::MatIterator_<float> itDepthImg = image->depth_image_.begin<float>(),
109  itDepthImg_end = image->depth_image_.end<float>();
110  cv::MatConstIterator_<unsigned short> itInvDepthImg = decompressed.begin<unsigned short>(),
111  itInvDepthImg_end = decompressed.end<unsigned short>();
112 
113  for (; (itDepthImg != itDepthImg_end) && (itInvDepthImg != itInvDepthImg_end); ++itDepthImg, ++itInvDepthImg)
114  {
115  // check for NaN & max depth
116  if (*itInvDepthImg)
117  {
118  *itDepthImg = depthQuantA / (static_cast<float>(*itInvDepthImg) - depthQuantB);
119  } else{
121  }
122  }
123 
124  // - - - - - - - - - - - - - - - - CAMERA INFO - - - - - - - - - - - - - - - -
125 
126  sensor_msgs::CameraInfo cam_info_msg;
127 
128  cam_info_msg.D.resize(5, 0.0);
129  cam_info_msg.K.fill(0.0);
130  cam_info_msg.K[0] = msg->cam_info[0]; // fx
131  cam_info_msg.K[2] = msg->cam_info[2]; // cx
132  cam_info_msg.K[4] = msg->cam_info[1]; // fy
133  cam_info_msg.K[5] = msg->cam_info[3]; // cy
134  cam_info_msg.K[8] = 1.0;
135 
136  cam_info_msg.R.fill(0.0);
137  cam_info_msg.R[0] = 1.0;
138  cam_info_msg.R[4] = 1.0;
139  cam_info_msg.R[8] = 1.0;
140 
141  cam_info_msg.P.fill(0.0);
142  cam_info_msg.P[0] = msg->cam_info[0]; // fx
143  cam_info_msg.P[2] = msg->cam_info[2]; // cx
144  cam_info_msg.P[3] = msg->cam_info[4]; // Tx
145  cam_info_msg.P[5] = msg->cam_info[1]; // fy
146  cam_info_msg.P[6] = msg->cam_info[3]; // cy
147  cam_info_msg.P[7] = msg->cam_info[5]; // cy
148  cam_info_msg.P[10] = 1.0;
149 
150  cam_info_msg.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
151  cam_info_msg.width = static_cast<unsigned int>(image->rgb_image_.cols);
152  cam_info_msg.height = static_cast<unsigned int>(image->rgb_image_.rows);
153  image_geometry::PinholeCameraModel cam_model;
154  cam_model.fromCameraInfo(cam_info_msg);
155 
156  image->cam_model_ = cam_model;
157  image->timestamp_ = msg->header.stamp.toSec();
158  image->frame_id_ = msg->header.frame_id;
159  return true;
160  }
161  else if (msg->version == 2)
162  {
163  std::stringstream stream;
164  tue::serialization::convert(msg->rgb, stream);
166  return rgbd::deserialize(a, *image);
167  }
168  else if (msg->version == 3)
169  {
170  std::stringstream compressed, decompressed;
171  tue::serialization::convert(msg->rgb, compressed);
172  boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
173  in.push(boost::iostreams::gzip_decompressor());
174  in.push(compressed);
175  boost::iostreams::copy(in, decompressed);
176  tue::serialization::InputArchive a(decompressed);
177  return rgbd::deserialize(a, *image);
178  }
179  else if (msg->version == 4)
180  {
181  std::stringstream compressed, decompressed;
182  tue::serialization::convert(msg->rgb, compressed);
183  boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
184  in.push(boost::iostreams::zstd_decompressor());
185  in.push(compressed);
186  boost::iostreams::copy(in, decompressed);
187  tue::serialization::InputArchive a(decompressed);
188  return rgbd::deserialize(a, *image);
189  }
190  else
191  {
192  ROS_ERROR_STREAM_NAMED("conversions", "convert: version '" << msg->version << "' not supported");
193  return false;
194  }
195 }
196 
197 }
sstream
rgbd::Image::cam_model_
image_geometry::PinholeCameraModel cam_model_
Camera model Header in camera info should always be empty to prevent inconsistent behaviour of equali...
Definition: image.h:179
DepthCamera.h
a
void a()
std::numeric_limits::quiet_NaN
T quiet_NaN(T... args)
rgbd::deserialize
bool deserialize(tue::serialization::InputArchive &a, Image &image)
Definition: serialization.cpp:174
std::stringstream
conversions.h
tue::serialization::convert
void convert(Archive &a, std::vector< unsigned char > &data)
rgbd::Image::frame_id_
std::string frame_id_
Definition: image.h:181
rgbd::Image
Definition: image.h:43
rgbd
Definition: client.h:24
geo::convert
void convert(const geo::DepthCamera &cam_model, sensor_msgs::CameraInfo &msg)
std::min
T min(T... args)
tue::serialization::InputArchive
rgbd::Image::depth_image_
cv::Mat depth_image_
Definition: image.h:173
rgbd::convert
bool convert(const cv::Mat &image, sensor_msgs::Image &image_msg)
Convert either a rgb or depth image, cv::Mat, to an image message.
Definition: conversions.cpp:32
rgbd::Image::timestamp_
double timestamp_
Definition: image.h:182
geo::DepthCamera
serialization.h
conversions.h
rgbd::Image::rgb_image_
cv::Mat rgb_image_
Definition: image.h:172
msg_conversions.h