converter.cpp
Go to the documentation of this file.
00001 
00004 /*****************************************************************************
00005 ** Includes
00006 *****************************************************************************/
00007 
00008 #include <boost/thread/lock_guard.hpp>
00009 #include <cmath>
00010 #include <cost_map_core/cost_map_core.hpp>
00011 #include <cost_map_msgs/CostMap.h>
00012 #include <ecl/console.hpp>
00013 #include <limits>
00014 #include <map>
00015 #include <sensor_msgs/Image.h>
00016 #include <sensor_msgs/image_encodings.h>
00017 #include <std_msgs/UInt8MultiArray.h>
00018 #include <stdexcept>
00019 #include <string>
00020 #include "../../include/cost_map_ros/converter.hpp"
00021 
00022 #include <grid_map_costmap_2d/grid_map_costmap_2d.hpp>
00023 
00024 /*****************************************************************************
00025 ** Namespaces
00026 *****************************************************************************/
00027 
00028 namespace cost_map {
00029 
00030 /*****************************************************************************
00031 ** ROS Images
00032 *****************************************************************************/
00033 
00034 //
00035 // almost a carbon copy of grid_map::addLayerFromImage
00036 //
00037 bool addLayerFromROSImage(const sensor_msgs::Image& image,
00038                           const std::string& layer_name,
00039                           cost_map::CostMap& cost_map
00040                           )
00041 {
00042   cv_bridge::CvImagePtr cvPtrAlpha, cvPtrMono;
00043 
00044   // If alpha channel exist, read it.
00045   if (image.encoding == sensor_msgs::image_encodings::BGRA8
00046       || image.encoding == sensor_msgs::image_encodings::BGRA16) {
00047     try {
00048       cvPtrAlpha = cv_bridge::toCvCopy(image, image.encoding);
00049     } catch (cv_bridge::Exception& e) {
00050       std::cout << ecl::red << "[ERROR] cv_bridge exception: " << e.what() << ecl::reset << std::endl;
00051       return false;
00052     }
00053   }
00054 
00055   unsigned int depth;  // Convert color image to grayscale.
00056   try {
00057     if (image.encoding == sensor_msgs::image_encodings::BGRA8
00058         || image.encoding == sensor_msgs::image_encodings::BGR8
00059         || image.encoding == sensor_msgs::image_encodings::MONO8) {
00060       cvPtrMono = cv_bridge::toCvCopy(image,
00061                                       sensor_msgs::image_encodings::MONO8);
00062       depth = std::pow(2, 8);
00063       // std::cout << "Color image converted to mono8" << std::endl;
00064     } else if (image.encoding == sensor_msgs::image_encodings::BGRA16
00065         || image.encoding == sensor_msgs::image_encodings::BGR16
00066         || image.encoding == sensor_msgs::image_encodings::MONO16) {
00067       cvPtrMono = cv_bridge::toCvCopy(image,
00068                                       sensor_msgs::image_encodings::MONO16);
00069       depth = std::pow(2, 16);
00070       // std::cout << "Color image converted to mono16" << std::endl;
00071     } else {
00072       std::cout << ecl::red << "[ERROR] expected BGR, BGRA, or MONO image encoding." << ecl::reset << std::endl;
00073       return false;
00074     }
00075   } catch (cv_bridge::Exception& e) {
00076     std::cout << ecl::red << "[ERROR] cv_bridge exception: " << e.what() << ecl::reset << std::endl;
00077     return false;
00078   }
00079 
00080   cost_map.add(layer_name);
00081 
00082   if (cost_map.getSize()(0) != image.height
00083       || cost_map.getSize()(1) != image.width) {
00084     std::cout << ecl::red << "[ERROR] Image size does not correspond to grid map size!" << ecl::reset << std::endl;
00085     return false;
00086   }
00087 
00088   for (CostMapIterator iterator(cost_map); !iterator.isPastEnd(); ++iterator) {
00089     // skip transparent values (they will typically be set to the default (cv_map::NO_INFORMATION/255)
00090     if (image.encoding == sensor_msgs::image_encodings::BGRA8) {
00091       const auto& cvAlpha = cvPtrAlpha->image.at<cv::Vec4b>((*iterator)(0),
00092                                                             (*iterator)(1));
00093       unsigned int alpha = cvAlpha[3];
00094       if (cvAlpha[3] < depth / 2)
00095         continue;
00096     }
00097     if (image.encoding == sensor_msgs::image_encodings::BGRA16) {
00098       const auto& cvAlpha = cvPtrAlpha->image.at<cv::Vec<uchar, 8>>(
00099           (*iterator)(0), (*iterator)(1));
00100       int alpha = (cvAlpha[6] << 8) + cvAlpha[7];
00101       if (alpha < depth / 2)
00102         continue;
00103     }
00104 
00105     // Compute non-transparent values.
00106     unsigned int grayValue;
00107     if (depth == std::pow(2, 8)) {
00108       uchar cvGrayscale = cvPtrMono->image.at<uchar>((*iterator)(0),
00109                                                      (*iterator)(1));
00110       grayValue = cvGrayscale;
00111     }
00112     if (depth == std::pow(2, 16)) {
00113       const auto& cvGrayscale = cvPtrMono->image.at<cv::Vec2b>((*iterator)(0),
00114                                                                (*iterator)(1));
00115       grayValue = (cvGrayscale[0] << 8) + cvGrayscale[1];
00116     }
00117     // RULE 1 : scale only from 0-254 (remember 255 is reserved for NO_INFORMATION)
00118     // RULE 2 : invert the value as black on an image (grayscale: 0) typically represents an obstacle (cost: 254)
00119     cost_map::DataType value = static_cast<cost_map::DataType>(254.0 * ( 1.0 - (static_cast<double>(grayValue) / static_cast<double>(depth))));
00120     cost_map.at(layer_name, *iterator) = value;
00121   }
00122   return true;
00123 }
00124 
00125 /*****************************************************************************
00126 ** CostMap and GridMap
00127 *****************************************************************************/
00128 
00129 
00130 void toGridMap(const cost_map::CostMap cost_map, grid_map::GridMap& grid_map)
00131 {
00132   grid_map.setGeometry(cost_map.getLength(), cost_map.getResolution(), cost_map.getPosition());
00133   grid_map.setFrameId(cost_map.getFrameId());
00134   grid_map.setTimestamp(cost_map.getTimestamp());
00135   for (const std::string& layer_name : cost_map.getLayers()) {
00136     const cost_map::Matrix& cost_map_data = cost_map[layer_name];
00137     grid_map::Matrix grid_map_data(cost_map_data.rows(), cost_map_data.cols());
00138     const cost_map::DataType *cost_map_ptr = cost_map_data.data();
00139     float *grid_map_ptr = grid_map_data.data();
00140     for (unsigned int i = 0; i < cost_map_data.size(); ++i ) {
00141       *grid_map_ptr = 100.0 * static_cast<double>(*cost_map_ptr) / static_cast<double>(cost_map::NO_INFORMATION);
00142       ++cost_map_ptr; ++grid_map_ptr;
00143     }
00144     grid_map.add(layer_name, grid_map_data);
00145   }
00146 }
00147 
00148 /*****************************************************************************
00149 ** Messages
00150 *****************************************************************************/
00151 //
00152 // almost a carbon copy of grid_map::toMessage
00153 //
00154 void toMessage(const cost_map::CostMap& cost_map, cost_map_msgs::CostMap& message)
00155 {
00156   std::vector<std::string> layers = cost_map.getLayers();
00157 
00158   message.info.header.stamp.fromNSec(cost_map.getTimestamp());
00159   message.info.header.frame_id = cost_map.getFrameId();
00160   message.info.resolution = cost_map.getResolution();
00161   message.info.length_x = cost_map.getLength().x();
00162   message.info.length_y = cost_map.getLength().y();
00163   message.info.pose.position.x = cost_map.getPosition().x();
00164   message.info.pose.position.y = cost_map.getPosition().y();
00165   message.info.pose.position.z = 0.0;
00166   message.info.pose.orientation.x = 0.0;
00167   message.info.pose.orientation.y = 0.0;
00168   message.info.pose.orientation.z = 0.0;
00169   message.info.pose.orientation.w = 1.0;
00170 
00171   message.layers = layers;
00172   message.basic_layers = cost_map.getBasicLayers();
00173 
00174   message.data.clear();
00175   for (const auto& layer : layers) {
00176     const cost_map::Matrix& data = cost_map.get(layer);
00177     std_msgs::UInt8MultiArray data_array;
00178     grid_map::matrixEigenCopyToMultiArrayMessage(cost_map.get(layer), data_array);
00179     message.data.push_back(data_array);
00180   }
00181 
00182   message.outer_start_index = cost_map.getStartIndex()(0);
00183   message.inner_start_index = cost_map.getStartIndex()(1);
00184 }
00185 
00186 bool fromMessage(const cost_map_msgs::CostMap& message, cost_map::CostMap& cost_map)
00187 {
00188   cost_map.setTimestamp(message.info.header.stamp.toNSec());
00189   cost_map.setFrameId(message.info.header.frame_id);
00190   cost_map.setGeometry(Length(message.info.length_x, message.info.length_y), message.info.resolution,
00191                       Position(message.info.pose.position.x, message.info.pose.position.y));
00192 
00193   if (message.layers.size() != message.data.size()) {
00194     // ROS_ERROR("Different number of layers and data in grid map message.");
00195     return false;
00196   }
00197 
00198   for (unsigned int i = 0; i < message.layers.size(); i++) {
00199     Matrix data;
00200     // this is not a template function
00201     // grid_map::multiArrayMessageCopyToMatrixEigen(message.data[i], data); // TODO Could we use the data mapping (instead of copying) method here?
00202     grid_map::multiArrayMessageCopyToMatrixEigen(message.data[i], data);
00203     // TODO Check if size is good.   size_ << getRows(message.data[0]), getCols(message.data[0]);
00204     cost_map.add(message.layers[i], data);
00205   }
00206 
00207   cost_map.setBasicLayers(message.basic_layers);
00208   cost_map.setStartIndex(Index(message.outer_start_index, message.inner_start_index));
00209   return true;
00210 }
00211 
00212 /*****************************************************************************
00213 ** CostMap2DROS and Occupancy Grids
00214 *****************************************************************************/
00215 
00216 bool fromCostmap2DROS(costmap_2d::Costmap2DROS& ros_costmap,
00217                       const std::string& layer_name,
00218                       cost_map::CostMap& cost_map) {
00219 
00220   grid_map::Costmap2DConverter<cost_map::CostMap> converter;
00221   boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
00222   converter.initializeFromCostmap2D(ros_costmap, cost_map);
00223   if ( !converter.addLayerFromCostmap2D(ros_costmap, layer_name, cost_map) ) {
00224     return false;
00225   }
00226   return true;
00227 }
00228 
00229 bool fromCostmap2DROSAtRobotPose(costmap_2d::Costmap2DROS& ros_costmap,
00230                                  const cost_map::Length& geometry,
00231                                  const std::string& layer_name,
00232                                  cost_map::CostMap& cost_map)
00233 {
00234   grid_map::Costmap2DConverter<cost_map::CostMap> converter;
00235   boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
00236   if ( !converter.initializeFromCostmap2DAtRobotPose(ros_costmap, geometry, cost_map) ) {
00237     return false;
00238   }
00239   if (!converter.addLayerFromCostmap2DAtRobotPose(ros_costmap, layer_name, cost_map) ) {
00240     return false;
00241   }
00242   return true;
00243 }
00244 
00245 void toOccupancyGrid(const cost_map::CostMap& cost_map, const std::string& layer, nav_msgs::OccupancyGrid& msg) {
00246   msg.header.frame_id = cost_map.getFrameId();
00247   msg.header.stamp.fromNSec(cost_map.getTimestamp());
00248   msg.info.map_load_time = msg.header.stamp;  // Same as header stamp as we do not load the map.
00249   msg.info.resolution = cost_map.getResolution();
00250   msg.info.width = cost_map.getSize()(0);
00251   msg.info.height = cost_map.getSize()(1);
00252 
00253   // adjust for difference in center
00254   Position positionOfOrigin = cost_map.getPosition() - 0.5 * cost_map.getLength().matrix();
00255   msg.info.origin.position.x = positionOfOrigin.x();
00256   msg.info.origin.position.y = positionOfOrigin.y();
00257   msg.info.origin.position.z = 0.0;
00258   msg.info.origin.orientation.x = 0.0;
00259   msg.info.origin.orientation.y = 0.0;
00260   msg.info.origin.orientation.z = 0.0;
00261   msg.info.origin.orientation.w = 1.0;
00262   msg.data.resize(msg.info.width * msg.info.height);
00263 
00264   size_t nCells = cost_map.getSize().prod();
00265   msg.data.resize(nCells);
00266 
00267   // Occupancy probabilities are in the range [0,100].  Unknown is -1.
00268   const float cellMin = 0;
00269   const float cellMax = 98;
00270   const float cellRange = cellMax - cellMin;
00271 
00272   const float data_minimum = 0;
00273   const float data_maximum = 252;
00274   for (CostMapIterator iterator(cost_map); !iterator.isPastEnd(); ++iterator)
00275   {
00276     float value;
00277     if (cost_map.at(layer, *iterator) == cost_map::NO_INFORMATION) // 255
00278     {
00279       value = -1;
00280     }
00281     else if (cost_map.at(layer, *iterator) == cost_map::LETHAL_OBSTACLE) // 254
00282     {
00283       value = 100;
00284     }
00285     else if (cost_map.at(layer, *iterator) == cost_map::INSCRIBED_OBSTACLE) // 253
00286     {
00287       value = 99;
00288     }
00289     else
00290     {
00291       value = (cost_map.at(layer, *iterator) - data_minimum) / (data_maximum - data_minimum);
00292       value = cellMin + std::min(std::max(0.0f, value), 1.0f) * cellRange;
00293     }
00294     unsigned int index = grid_map::getLinearIndexFromIndex(*iterator, cost_map.getSize(), false);
00295     msg.data[nCells - index - 1] = value;
00296   }
00297 }
00298 Costmap2DROSServiceProvider::Costmap2DROSServiceProvider(costmap_2d::Costmap2DROS* ros_costmap,
00299                                                          const std::string& service_name)
00300 : ros_costmap(ros_costmap)
00301 {
00302   ros::NodeHandle private_nodehandle("~");
00303   service = private_nodehandle.advertiseService(service_name, &Costmap2DROSServiceProvider::callback, this);
00304 }
00305 
00306 Costmap2DROSServiceProvider::Costmap2DROSServiceProvider(costmap_2d::Costmap2DROS* ros_costmap,
00307                                                          ros::NodeHandle& node_handle,
00308                                                          const std::string& service_name)
00309 : ros_costmap(ros_costmap)
00310 {
00311   service = node_handle.advertiseService(service_name, &Costmap2DROSServiceProvider::callback, this);
00312 }
00313 
00314 bool Costmap2DROSServiceProvider::callback(
00315     cost_map_msgs::GetCostMap::Request  &request,
00316     cost_map_msgs::GetCostMap::Response &response)
00317 {
00318   CostMap cost_map;
00319   cost_map::Length geometry;
00320   geometry << request.length_x, request.length_y;
00321   if ( !fromCostmap2DROSAtRobotPose(*ros_costmap, geometry, "obstacle_costs", cost_map) ) {
00322     ROS_ERROR_STREAM("CostMap Service : failed to convert from Costmap2DROS");
00323   }
00324   toMessage(cost_map, response.map);
00325   return true;
00326 }
00327 
00328 /*****************************************************************************
00329  ** Trailers
00330  *****************************************************************************/
00331 
00332 } // namespace cost_map


cost_map_ros
Author(s): Daniel Stonier
autogenerated on Thu Jun 6 2019 20:27:54