Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
conversions.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: conversions.h 6126 2012-07-03 20:19:58Z aichim $
37  *
38  */
39 
40 #ifndef PCL_ROS_CONVERSIONS_H_
41 #define PCL_ROS_CONVERSIONS_H_
42 
43 #include <sensor_msgs/PointField.h>
45 #include <sensor_msgs/Image.h>
46 #include <pcl/point_cloud.h>
47 #include <pcl/point_traits.h>
48 #include <pcl/for_each_type.h>
49 #include <pcl/exceptions.h>
50 #include <pcl/console/print.h>
51 #include <boost/foreach.hpp>
52 
53 namespace pcl
54 {
55  namespace detail
56  {
57  // For converting template point cloud to message.
58  template<typename PointT>
59  struct FieldAdder
60  {
61  FieldAdder (std::vector<sensor_msgs::PointField>& fields) : fields_ (fields) {};
62 
63  template<typename U> void operator() ()
64  {
70  fields_.push_back (f);
71  }
72 
73  std::vector<sensor_msgs::PointField>& fields_;
74  };
75 
76  // For converting message to template point cloud.
77  template<typename PointT>
78  struct FieldMapper
79  {
80  FieldMapper (const std::vector<sensor_msgs::PointField>& fields,
81  std::vector<FieldMapping>& map)
82  : fields_ (fields), map_ (map)
83  {
84  }
85 
86  template<typename Tag> void
88  {
89  BOOST_FOREACH (const sensor_msgs::PointField& field, fields_)
90  {
91  if (FieldMatches<PointT, Tag>()(field))
92  {
93  FieldMapping mapping;
94  mapping.serialized_offset = field.offset;
96  mapping.size = sizeof (typename traits::datatype<PointT, Tag>::type);
97  map_.push_back (mapping);
98  return;
99  }
100  }
101  // Disable thrown exception per #595: http://dev.pointclouds.org/issues/595
102  PCL_WARN ("Failed to find match for field '%s'.\n", traits::name<PointT, Tag>::value);
103  //throw pcl::InvalidConversionException (ss.str ());
104  }
105 
106  const std::vector<sensor_msgs::PointField>& fields_;
107  std::vector<FieldMapping>& map_;
108  };
109 
110  inline bool
112  {
113  return (a.serialized_offset < b.serialized_offset);
114  }
115 
116  } //namespace detail
117 
118  template<typename PointT> void
119  createMapping (const std::vector<sensor_msgs::PointField>& msg_fields, MsgFieldMap& field_map)
120  {
121  // Create initial 1-1 mapping between serialized data segments and struct fields
122  detail::FieldMapper<PointT> mapper (msg_fields, field_map);
123  for_each_type< typename traits::fieldList<PointT>::type > (mapper);
124 
125  // Coalesce adjacent fields into single memcpy's where possible
126  if (field_map.size() > 1)
127  {
128  std::sort(field_map.begin(), field_map.end(), detail::fieldOrdering);
129  MsgFieldMap::iterator i = field_map.begin(), j = i + 1;
130  while (j != field_map.end())
131  {
132  // This check is designed to permit padding between adjacent fields.
135  if (j->serialized_offset - i->serialized_offset == j->struct_offset - i->struct_offset)
136  {
137  i->size += (j->struct_offset + j->size) - (i->struct_offset + i->size);
138  j = field_map.erase(j);
139  }
140  else
141  {
142  ++i;
143  ++j;
144  }
145  }
146  }
147  }
148 
162  template <typename PointT> void
164  const MsgFieldMap& field_map)
165  {
166  // Copy info fields
167  cloud.header = msg.header;
168  cloud.width = msg.width;
169  cloud.height = msg.height;
170  cloud.is_dense = msg.is_dense == 1;
171 
172  // Copy point data
173  uint32_t num_points = msg.width * msg.height;
174  cloud.points.resize (num_points);
175  uint8_t* cloud_data = reinterpret_cast<uint8_t*>(&cloud.points[0]);
176 
177  // Check if we can copy adjacent points in a single memcpy
178  if (field_map.size() == 1 &&
179  field_map[0].serialized_offset == 0 &&
180  field_map[0].struct_offset == 0 &&
181  msg.point_step == sizeof(PointT))
182  {
183  uint32_t cloud_row_step = static_cast<uint32_t> (sizeof (PointT) * cloud.width);
184  const uint8_t* msg_data = &msg.data[0];
185  // Should usually be able to copy all rows at once
186  if (msg.row_step == cloud_row_step)
187  {
188  memcpy (cloud_data, msg_data, msg.data.size ());
189  }
190  else
191  {
192  for (uint32_t i = 0; i < msg.height; ++i, cloud_data += cloud_row_step, msg_data += msg.row_step)
193  memcpy (cloud_data, msg_data, cloud_row_step);
194  }
195 
196  }
197  else
198  {
199  // If not, memcpy each group of contiguous fields separately
200  for (uint32_t row = 0; row < msg.height; ++row)
201  {
202  const uint8_t* row_data = &msg.data[row * msg.row_step];
203  for (uint32_t col = 0; col < msg.width; ++col)
204  {
205  const uint8_t* msg_data = row_data + col * msg.point_step;
206  BOOST_FOREACH (const detail::FieldMapping& mapping, field_map)
207  {
208  memcpy (cloud_data + mapping.struct_offset, msg_data + mapping.serialized_offset, mapping.size);
209  }
210  cloud_data += sizeof (PointT);
211  }
212  }
213  }
214  }
215 
220  template<typename PointT> void
222  {
223  MsgFieldMap field_map;
224  createMapping<PointT> (msg.fields, field_map);
225  fromROSMsg (msg, cloud, field_map);
226  }
227 
232  template<typename PointT> void
234  {
235  // Ease the user's burden on specifying width/height for unorganized datasets
236  if (cloud.width == 0 && cloud.height == 0)
237  {
238  msg.width = static_cast<uint32_t>(cloud.points.size ());
239  msg.height = 1;
240  }
241  else
242  {
243  assert (cloud.points.size () == cloud.width * cloud.height);
244  msg.height = cloud.height;
245  msg.width = cloud.width;
246  }
247 
248  // Fill point cloud binary data (padding and all)
249  size_t data_size = sizeof (PointT) * cloud.points.size ();
250  msg.data.resize (data_size);
251  memcpy (&msg.data[0], &cloud.points[0], data_size);
252 
253  // Fill fields metadata
254  msg.fields.clear ();
255  for_each_type<typename traits::fieldList<PointT>::type> (detail::FieldAdder<PointT>(msg.fields));
256 
257  msg.header = cloud.header;
258  msg.point_step = sizeof (PointT);
259  msg.row_step = static_cast<uint32_t> (sizeof (PointT) * msg.width);
260  msg.is_dense = cloud.is_dense;
262  }
263 
270  template<typename CloudT> void
271  toROSMsg (const CloudT& cloud, sensor_msgs::Image& msg)
272  {
273  // Ease the user's burden on specifying width/height for unorganized datasets
274  if (cloud.width == 0 && cloud.height == 0)
275  throw std::runtime_error("Needs to be a dense like cloud!!");
276  else
277  {
278  if (cloud.points.size () != cloud.width * cloud.height)
279  throw std::runtime_error("The width and height do not match the cloud size!");
280  msg.height = cloud.height;
281  msg.width = cloud.width;
282  }
283 
284  // ensor_msgs::image_encodings::BGR8;
285  msg.encoding = "bgr8";
286  msg.step = msg.width * sizeof (uint8_t) * 3;
287  msg.data.resize (msg.step * msg.height);
288  for (size_t y = 0; y < cloud.height; y++)
289  {
290  for (size_t x = 0; x < cloud.width; x++)
291  {
292  uint8_t * pixel = &(msg.data[y * msg.step + x * 3]);
293  memcpy (pixel, &cloud (x, y).rgb, 3 * sizeof(uint8_t));
294  }
295  }
296  }
297 
303  inline void
305  {
306  int rgb_index = -1;
307  // Get the index we need
308  for (size_t d = 0; d < cloud.fields.size (); ++d)
309  if (cloud.fields[d].name == "rgb")
310  {
311  rgb_index = static_cast<int>(d);
312  break;
313  }
314 
315  if(rgb_index == -1)
316  throw std::runtime_error ("No rgb field!!");
317  if (cloud.width == 0 && cloud.height == 0)
318  throw std::runtime_error ("Needs to be a dense like cloud!!");
319  else
320  {
321  msg.height = cloud.height;
322  msg.width = cloud.width;
323  }
324  int rgb_offset = cloud.fields[rgb_index].offset;
325  int point_step = cloud.point_step;
326 
327  // sensor_msgs::image_encodings::BGR8;
328  msg.encoding = "bgr8";
329  msg.step = static_cast<uint32_t>(msg.width * sizeof (uint8_t) * 3);
330  msg.data.resize (msg.step * msg.height);
331 
332  for (size_t y = 0; y < cloud.height; y++)
333  {
334  for (size_t x = 0; x < cloud.width; x++, rgb_offset += point_step)
335  {
336  uint8_t * pixel = &(msg.data[y * msg.step + x * 3]);
337  memcpy (pixel, &(cloud.data[rgb_offset]), 3 * sizeof (uint8_t));
338  }
339  }
340  }
341 }
342 
343 #endif //#ifndef PCL_ROS_CONVERSIONS_H_