compressed_subscriber.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 20012, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 #include <boost/endian/arithmetic.hpp>
38 #include <cv_bridge/cv_bridge.h>
39 #include <opencv2/highgui/highgui.hpp>
40 #include <opencv2/imgproc/imgproc.hpp>
41 #include <turbojpeg.h>
42 
44 
45 #include <limits>
46 #include <vector>
47 
48 using namespace cv;
49 
51 
53 {
54 
55 CompressedSubscriber::CompressedSubscriber()
56  : tj_(0)
57 {}
58 
60 {
61  if (tj_)
62  tjDestroy(tj_);
63 }
64 
65 void CompressedSubscriber::subscribeImpl(ros::NodeHandle& nh, const std::string& base_topic, uint32_t queue_size,
66  const Callback& callback, const ros::VoidPtr& tracked_object,
67  const image_transport::TransportHints& transport_hints)
68 {
70  Base::subscribeImpl(nh, base_topic, queue_size, callback, tracked_object, transport_hints);
71 
72  // Set up reconfigure server for this topic
73  reconfigure_server_ = boost::make_shared<ReconfigureServer>(this->nh());
74  ReconfigureServer::CallbackType f = boost::bind(&CompressedSubscriber::configCb, this, _1, _2);
75  reconfigure_server_->setCallback(f);
76 }
77 
78 
79 void CompressedSubscriber::configCb(Config& config, uint32_t level)
80 {
81  config_ = config;
82  if (config_.mode == compressed_image_transport::CompressedSubscriber_gray) {
83  imdecode_flag_ = cv::IMREAD_GRAYSCALE;
84  } else if (config_.mode == compressed_image_transport::CompressedSubscriber_color) {
85  imdecode_flag_ = cv::IMREAD_COLOR;
86  } else /*if (config_.mode == compressed_image_transport::CompressedSubscriber_unchanged)*/ {
87  imdecode_flag_ = cv::IMREAD_UNCHANGED;
88  }
89 }
90 
92 {
93  reconfigure_server_.reset();
95 }
96 
97 sensor_msgs::ImagePtr CompressedSubscriber::decompressJPEG(const std::vector<uint8_t>& data, const std::string& source_encoding, const std_msgs::Header& header)
98 {
99  if (!tj_)
100  tj_ = tjInitDecompress();
101 
102  int width, height, jpegSub, jpegColor;
103 
104  // Old TurboJPEG require a const_cast here. This was fixed in TurboJPEG 1.5.
105  uint8_t* src = const_cast<uint8_t*>(data.data());
106 
107  if (tjDecompressHeader3(tj_, src, data.size(), &width, &height, &jpegSub, &jpegColor) != 0)
108  return sensor_msgs::ImagePtr(); // If we cannot decode the JPEG header, silently fall back to OpenCV
109 
110  sensor_msgs::ImagePtr ret(new sensor_msgs::Image);
111  ret->header = header;
112  ret->width = width;
113  ret->height = height;
114  ret->encoding = source_encoding;
115  // consistent with cv_bridge
116  ret->is_bigendian = (boost::endian::order::native == boost::endian::order::big); // NOLINT
117 
118  int pixelFormat;
119 
120  if (source_encoding == enc::MONO8)
121  {
122  ret->data.resize(height*width);
123  ret->step = ret->width;
124  pixelFormat = TJPF_GRAY;
125  }
126  else if (source_encoding == enc::RGB8)
127  {
128  ret->data.resize(height*width*3);
129  ret->step = width*3;
130  pixelFormat = TJPF_RGB;
131  }
132  else if (source_encoding == enc::BGR8)
133  {
134  ret->data.resize(height*width*3);
135  ret->step = width*3;
136  pixelFormat = TJPF_BGR;
137  }
138  else if (source_encoding == enc::RGBA8)
139  {
140  ret->data.resize(height*width*4);
141  ret->step = width*4;
142  pixelFormat = TJPF_RGBA;
143  }
144  else if (source_encoding == enc::BGRA8)
145  {
146  ret->data.resize(height*width*4);
147  ret->step = width*4;
148  pixelFormat = TJPF_BGRA;
149  }
150  else if (source_encoding.empty())
151  {
152  // Autodetect based on image
153  if(jpegColor == TJCS_GRAY)
154  {
155  ret->data.resize(height*width);
156  ret->step = width;
157  ret->encoding = enc::MONO8;
158  pixelFormat = TJPF_GRAY;
159  }
160  else
161  {
162  ret->data.resize(height*width*3);
163  ret->step = width*3;
164  ret->encoding = enc::RGB8;
165  pixelFormat = TJPF_RGB;
166  }
167  }
168  else
169  {
170  ROS_WARN_THROTTLE(10.0, "Encountered a source encoding that is not supported by TurboJPEG: '%s'", source_encoding.c_str());
171  return sensor_msgs::ImagePtr();
172  }
173 
174  if (tjDecompress2(tj_, src, data.size(), ret->data.data(), width, 0, height, pixelFormat, 0) != 0)
175  {
176  ROS_WARN_THROTTLE(10.0, "Could not decompress data using TurboJPEG, falling back to OpenCV");
177  return sensor_msgs::ImagePtr();
178  }
179 
180  return ret;
181 }
182 
183 void CompressedSubscriber::internalCallback(const sensor_msgs::CompressedImageConstPtr& message,
184  const Callback& user_cb)
185 
186 {
187  // Parse format field
188  std::string image_encoding;
189  std::string compressed_encoding;
190  {
191  const size_t split_pos = message->format.find(';');
192  if (split_pos != std::string::npos)
193  {
194  image_encoding = message->format.substr(0, split_pos);
195  compressed_encoding = message->format.substr(split_pos);
196  }
197  }
198 
199  // Try TurboJPEG first (if the first bytes look like JPEG)
200  if(message->data.size() > 4 && message->data[0] == 0xFF && message->data[1] == 0xD8)
201  {
202  sensor_msgs::ImagePtr decoded = decompressJPEG(message->data, image_encoding, message->header);
203  if(decoded)
204  {
205  user_cb(decoded);
206  return;
207  }
208  }
209 
210  // Otherwise, try our luck with OpenCV.
212 
213  // Copy message header
214  cv_ptr->header = message->header;
215 
216  // Decode color/mono image
217  try
218  {
219  cv_ptr->image = cv::imdecode(cv::Mat(message->data), imdecode_flag_);
220 
221  // Assign image encoding string
222  if (image_encoding.empty())
223  {
224  // Older version of compressed_image_transport does not signal image format
225  switch (cv_ptr->image.channels())
226  {
227  case 1:
228  cv_ptr->encoding = enc::MONO8;
229  break;
230  case 3:
231  cv_ptr->encoding = enc::BGR8;
232  break;
233  default:
234  ROS_ERROR("Unsupported number of channels: %i", cv_ptr->image.channels());
235  break;
236  }
237  } else
238  {
239  cv_ptr->encoding = image_encoding;
240 
241  if ( enc::isColor(image_encoding))
242  {
243  bool compressed_bgr_image = (compressed_encoding.find("compressed bgr") != std::string::npos);
244 
245  // Revert color transformation
246  if (compressed_bgr_image)
247  {
248  // if necessary convert colors from bgr to rgb
249  if ((image_encoding == enc::RGB8) || (image_encoding == enc::RGB16))
250  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_BGR2RGB);
251 
252  if ((image_encoding == enc::RGBA8) || (image_encoding == enc::RGBA16))
253  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_BGR2RGBA);
254 
255  if ((image_encoding == enc::BGRA8) || (image_encoding == enc::BGRA16))
256  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_BGR2BGRA);
257  } else
258  {
259  // if necessary convert colors from rgb to bgr
260  if ((image_encoding == enc::BGR8) || (image_encoding == enc::BGR16))
261  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_RGB2BGR);
262 
263  if ((image_encoding == enc::BGRA8) || (image_encoding == enc::BGRA16))
264  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_RGB2BGRA);
265 
266  if ((image_encoding == enc::RGBA8) || (image_encoding == enc::RGBA16))
267  cv::cvtColor(cv_ptr->image, cv_ptr->image, CV_RGB2RGBA);
268  }
269  }
270  }
271  }
272  catch (cv::Exception& e)
273  {
274  ROS_ERROR("%s", e.what());
275  }
276 
277  size_t rows = cv_ptr->image.rows;
278  size_t cols = cv_ptr->image.cols;
279 
280  if ((rows > 0) && (cols > 0))
281  // Publish message to user callback
282  user_cb(cv_ptr->toImageMsg());
283 }
284 
285 } //namespace compressed_image_transport
sensor_msgs::ImagePtr decompressJPEG(const std::vector< uint8_t > &data, const std::string &source_encoding, const std_msgs::Header &header)
f
compressed_image_transport::CompressedSubscriberConfig Config
boost::function< void(const sensor_msgs::ImageConstPtr &)> Callback
virtual void subscribeImpl(ros::NodeHandle &nh, const std::string &base_topic, uint32_t queue_size, const Callback &callback, const ros::VoidPtr &tracked_object, const image_transport::TransportHints &transport_hints)
#define ROS_WARN_THROTTLE(period,...)
virtual void internalCallback(const sensor_msgs::CompressedImageConstPtr &message, const Callback &user_cb)
#define ROS_ERROR(...)
boost::shared_ptr< ReconfigureServer > reconfigure_server_


compressed_image_transport
Author(s): Patrick Mihelich, Julius Kammerl, David Gossow
autogenerated on Fri Feb 10 2023 03:31:21