|
Point Cloud Library (PCL)
1.5.1
|
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2010, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Willow Garage, Inc. nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 * $Id: conversions.h 4702 2012-02-23 09:39:33Z gedikli $ 00035 * 00036 */ 00037 00038 #ifndef PCL_ROS_CONVERSIONS_H_ 00039 #define PCL_ROS_CONVERSIONS_H_ 00040 00041 #include <sensor_msgs/PointField.h> 00042 #include <sensor_msgs/PointCloud2.h> 00043 #include <sensor_msgs/Image.h> 00044 #include <pcl/point_cloud.h> 00045 #include <pcl/point_traits.h> 00046 #include <pcl/for_each_type.h> 00047 #include <pcl/exceptions.h> 00048 #include <pcl/console/print.h> 00049 #include <boost/foreach.hpp> 00050 00051 namespace pcl 00052 { 00053 namespace detail 00054 { 00055 // For converting template point cloud to message. 00056 template<typename PointT> 00057 struct FieldAdder 00058 { 00059 FieldAdder (std::vector<sensor_msgs::PointField>& fields) : fields_ (fields) {}; 00060 00061 template<typename U> void operator() () 00062 { 00063 sensor_msgs::PointField f; 00064 f.name = traits::name<PointT, U>::value; 00065 f.offset = traits::offset<PointT, U>::value; 00066 f.datatype = traits::datatype<PointT, U>::value; 00067 f.count = traits::datatype<PointT, U>::size; 00068 fields_.push_back (f); 00069 } 00070 00071 std::vector<sensor_msgs::PointField>& fields_; 00072 }; 00073 00074 // For converting message to template point cloud. 00075 template<typename PointT> 00076 struct FieldMapper 00077 { 00078 FieldMapper (const std::vector<sensor_msgs::PointField>& fields, 00079 std::vector<FieldMapping>& map) 00080 : fields_ (fields), map_ (map) 00081 { 00082 } 00083 00084 template<typename Tag> void operator() () 00085 { 00086 const char* name = traits::name<PointT, Tag>::value; 00087 BOOST_FOREACH(const sensor_msgs::PointField& field, fields_) 00088 { 00089 if (field.name == name) 00090 { 00091 typedef traits::datatype<PointT, Tag> Data; 00092 assert (Data::value == field.datatype); 00093 //@todo: Talk to Patrick about this 00094 //assert (Data::size == field.count); 00095 00096 FieldMapping mapping; 00097 mapping.serialized_offset = field.offset; 00098 mapping.struct_offset = traits::offset<PointT, Tag>::value; 00099 mapping.size = sizeof (typename Data::type); 00100 map_.push_back (mapping); 00101 return; 00102 } 00103 } 00104 // didn't find it... 00105 std::stringstream ss; 00106 ss << "Failed to find a field named: '" << name 00107 << "'. Cannot convert message to PCL type."; 00108 PCL_ERROR ("%s\n", ss.str().c_str()); 00109 throw pcl::InvalidConversionException(ss.str()); 00110 } 00111 00112 const std::vector<sensor_msgs::PointField>& fields_; 00113 std::vector<FieldMapping>& map_; 00114 }; 00115 00116 inline bool fieldOrdering(const FieldMapping& a, const FieldMapping& b) 00117 { 00118 return a.serialized_offset < b.serialized_offset; 00119 } 00120 00121 } //namespace detail 00122 00123 template<typename PointT> void 00124 createMapping (const std::vector<sensor_msgs::PointField>& msg_fields, MsgFieldMap& field_map) 00125 { 00126 // Create initial 1-1 mapping between serialized data segments and struct fields 00127 detail::FieldMapper<PointT> mapper (msg_fields, field_map); 00128 for_each_type< typename traits::fieldList<PointT>::type > (mapper); 00129 00130 // Coalesce adjacent fields into single memcpy's where possible 00131 if (field_map.size() > 1) 00132 { 00133 std::sort(field_map.begin(), field_map.end(), detail::fieldOrdering); 00134 MsgFieldMap::iterator i = field_map.begin(), j = i + 1; 00135 while (j != field_map.end()) 00136 { 00137 // This check is designed to permit padding between adjacent fields. 00140 if (j->serialized_offset - i->serialized_offset == j->struct_offset - i->struct_offset) 00141 { 00142 i->size += (j->struct_offset + j->size) - (i->struct_offset + i->size); 00143 j = field_map.erase(j); 00144 } 00145 else 00146 { 00147 ++i; 00148 ++j; 00149 } 00150 } 00151 } 00152 } 00153 00167 template <typename PointT> void 00168 fromROSMsg (const sensor_msgs::PointCloud2& msg, pcl::PointCloud<PointT>& cloud, 00169 const MsgFieldMap& field_map) 00170 { 00171 // Copy info fields 00172 cloud.header = msg.header; 00173 cloud.width = msg.width; 00174 cloud.height = msg.height; 00175 cloud.is_dense = msg.is_dense == 1; 00176 00177 // Copy point data 00178 uint32_t num_points = msg.width * msg.height; 00179 cloud.points.resize (num_points); 00180 uint8_t* cloud_data = reinterpret_cast<uint8_t*>(&cloud.points[0]); 00181 00182 // Check if we can copy adjacent points in a single memcpy 00183 if (field_map.size() == 1 && 00184 field_map[0].serialized_offset == 0 && 00185 field_map[0].struct_offset == 0 && 00186 msg.point_step == sizeof(PointT)) 00187 { 00188 uint32_t cloud_row_step = sizeof(PointT) * cloud.width; 00189 const uint8_t* msg_data = &msg.data[0]; 00190 // Should usually be able to copy all rows at once 00191 if (msg.row_step == cloud_row_step) 00192 { 00193 memcpy (cloud_data, msg_data, msg.data.size ()); 00194 } 00195 else 00196 { 00197 for (uint32_t i = 0; i < msg.height; ++i, cloud_data += cloud_row_step, msg_data += msg.row_step) 00198 memcpy (cloud_data, msg_data, cloud_row_step); 00199 } 00200 00201 } 00202 else 00203 { 00204 // If not, memcpy each group of contiguous fields separately 00205 for (uint32_t row = 0; row < msg.height; ++row) 00206 { 00207 const uint8_t* row_data = &msg.data[row * msg.row_step]; 00208 for (uint32_t col = 0; col < msg.width; ++col) 00209 { 00210 const uint8_t* msg_data = row_data + col * msg.point_step; 00211 BOOST_FOREACH (const detail::FieldMapping& mapping, field_map) 00212 { 00213 memcpy (cloud_data + mapping.struct_offset, msg_data + mapping.serialized_offset, mapping.size); 00214 } 00215 cloud_data += sizeof (PointT); 00216 } 00217 } 00218 } 00219 } 00220 00225 template<typename PointT> void 00226 fromROSMsg (const sensor_msgs::PointCloud2& msg, pcl::PointCloud<PointT>& cloud) 00227 { 00228 MsgFieldMap field_map; 00229 createMapping<PointT> (msg.fields, field_map); 00230 fromROSMsg (msg, cloud, field_map); 00231 } 00232 00237 template<typename PointT> void 00238 toROSMsg (const pcl::PointCloud<PointT>& cloud, sensor_msgs::PointCloud2& msg) 00239 { 00240 // Ease the user's burden on specifying width/height for unorganized datasets 00241 if (cloud.width == 0 && cloud.height == 0) 00242 { 00243 msg.width = (uint32_t) cloud.points.size (); 00244 msg.height = 1; 00245 } 00246 else 00247 { 00248 assert (cloud.points.size () == cloud.width * cloud.height); 00249 msg.height = cloud.height; 00250 msg.width = cloud.width; 00251 } 00252 00253 // Fill point cloud binary data (padding and all) 00254 size_t data_size = sizeof (PointT) * cloud.points.size (); 00255 msg.data.resize (data_size); 00256 memcpy (&msg.data[0], &cloud.points[0], data_size); 00257 00258 // Fill fields metadata 00259 msg.fields.clear (); 00260 for_each_type< typename traits::fieldList<PointT>::type > (detail::FieldAdder<PointT>(msg.fields)); 00261 00262 msg.header = cloud.header; 00263 msg.point_step = sizeof (PointT); 00264 msg.row_step = sizeof (PointT) * msg.width; 00265 msg.is_dense = cloud.is_dense; 00267 } 00268 00275 template<typename CloudT> void 00276 toROSMsg(const CloudT& cloud, sensor_msgs::Image& msg) 00277 { 00278 // Ease the user's burden on specifying width/height for unorganized datasets 00279 if (cloud.width == 0 && cloud.height == 0) 00280 throw std::runtime_error("Needs to be a dense like cloud!!"); 00281 else 00282 { 00283 if(cloud.points.size () != cloud.width * cloud.height){ 00284 throw std::runtime_error("The width and height do not match the cloud size!"); 00285 } 00286 msg.height = cloud.height; 00287 msg.width = cloud.width; 00288 } 00289 00290 // ensor_msgs::image_encodings::BGR8; 00291 msg.encoding = "bgr8"; 00292 msg.step = msg.width * sizeof(uint8_t) * 3; 00293 msg.data.resize(msg.step * msg.height); 00294 for (size_t y = 0; y < cloud.height; y++) 00295 { 00296 for (size_t x = 0; x < cloud.width; x++) 00297 { 00298 uint8_t * pixel = &(msg.data[y * msg.step + x * 3]); 00299 memcpy(pixel, &cloud (x, y).rgb, 3 * sizeof(uint8_t)); 00300 } 00301 } 00302 } 00303 00309 inline void 00310 toROSMsg (const sensor_msgs::PointCloud2& cloud, sensor_msgs::Image& msg) 00311 { 00312 int rgb_index = -1; 00313 // Get the index we need 00314 for (size_t d = 0; d < cloud.fields.size (); ++d) 00315 if (cloud.fields[d].name == "rgb") 00316 { 00317 rgb_index = (int) d; 00318 break; 00319 } 00320 00321 if(rgb_index == -1) 00322 throw std::runtime_error ("No rgb field!!"); 00323 if (cloud.width == 0 && cloud.height == 0) 00324 throw std::runtime_error ("Needs to be a dense like cloud!!"); 00325 else 00326 { 00327 msg.height = cloud.height; 00328 msg.width = cloud.width; 00329 } 00330 int rgb_offset = cloud.fields[rgb_index].offset; 00331 int point_step = cloud.point_step; 00332 00333 // sensor_msgs::image_encodings::BGR8; 00334 msg.encoding = "bgr8"; 00335 msg.step = msg.width * sizeof(uint8_t) * 3; 00336 msg.data.resize (msg.step * msg.height); 00337 00338 for (size_t y = 0; y < cloud.height; y++) 00339 { 00340 for (size_t x = 0; x < cloud.width; x++, rgb_offset += point_step) 00341 { 00342 uint8_t * pixel = &(msg.data[y * msg.step + x * 3]); 00343 memcpy (pixel, &(cloud.data[rgb_offset]), 3 * sizeof (uint8_t)); 00344 } 00345 } 00346 } 00347 } 00348 00349 #endif //#ifndef PCL_ROS_CONVERSIONS_H_
1.8.0