map_to_image_node.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2011, Stefan Kohlbrecher, TU Darmstadt
00003 // All rights reserved.
00004 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Simulation, Systems Optimization and Robotics
00013 //       group, TU Darmstadt nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //=================================================================================================
00028 
00029 #include "ros/ros.h"
00030 
00031 #include <nav_msgs/GetMap.h>
00032 #include <geometry_msgs/Quaternion.h>
00033 #include <geometry_msgs/PoseStamped.h>
00034 #include <sensor_msgs/image_encodings.h>
00035 
00036 
00037 #include <cv_bridge/cv_bridge.h>        
00038 
00039 #include <image_transport/image_transport.h>
00040 #include <Eigen/Geometry>
00041 
00042 #include <HectorMapTools.h>
00043 #include <math.h>
00044 #include <tf/transform_datatypes.h>
00045 
00046 using namespace std;
00047 using namespace cv_bridge;
00048 using namespace cv;
00049 
00054 class MapAsImageProvider
00055 {
00056 public:
00057   MapAsImageProvider()
00058     : pn_("~")
00059   {
00060 
00061     image_transport_ = new image_transport::ImageTransport(n_);
00062     image_transport_publisher_full_position_ = image_transport_->advertise("map_image/full_with_position", 1);
00063     image_transport_publisher_full_ = image_transport_->advertise("map_image/full", 1);
00064     image_transport_publisher_tile_ = image_transport_->advertise("map_image/tile", 1);
00065 
00066     pose_sub_ = n_.subscribe("pose", 1, &MapAsImageProvider::poseCallback, this);
00067     map_sub_ = n_.subscribe("map", 1, &MapAsImageProvider::mapCallback, this);
00068 
00069     //Which frame_id makes sense?
00070     cv_img_full_with_position_.header.frame_id = "map_image";
00071     cv_img_full_with_position_.encoding = sensor_msgs::image_encodings::RGB8;
00072 
00073     cv_img_full_.header.frame_id = "map_image";
00074     cv_img_full_.encoding = sensor_msgs::image_encodings::MONO8;
00075 
00076     cv_img_tile_.header.frame_id = "map_image";
00077     cv_img_tile_.encoding = sensor_msgs::image_encodings::RGB8;
00078 
00079     //Fixed cell width for tile based image, use dynamic_reconfigure for this later
00080     p_size_tiled_map_image_x_ = 64;
00081     p_size_tiled_map_image_y_ = 64;
00082 
00083     ROS_INFO("Map to Image node started.");
00084   }
00085 
00086   ~MapAsImageProvider()
00087   {
00088     delete image_transport_;
00089   }
00090 
00091   //We assume the robot position is available as a PoseStamped here (querying tf would be the more general option)
00092   void poseCallback(const geometry_msgs::PoseStampedConstPtr& pose)
00093   {
00094     pose_ptr_ = pose;
00095   }
00096 
00097   //The map->image conversion runs every time a new map is received at the moment
00098   void mapCallback(const nav_msgs::OccupancyGridConstPtr& map)
00099   {
00100     int size_x = map->info.width;
00101     int size_y = map->info.height;
00102 
00103     if ((size_x < 3) || (size_y < 3) ){
00104       ROS_INFO("Map size is only x: %d,  y: %d . Not running map to image conversion", size_x, size_y);
00105       return;
00106     }
00107 
00108     // Only if someone is subscribed to it, do work and publish full map image
00109     if (image_transport_publisher_full_.getNumSubscribers() > 0  && (pose_ptr_)){
00110       Mat* map_mat  = &cv_img_full_.image;
00111       Mat* map_mat_position  = &cv_img_full_with_position_.image;
00112 
00113       // resize cv image if it doesn't have the same dimensions as the map
00114       if ( (map_mat->rows != size_y) && (map_mat->cols != size_x)){
00115         *map_mat = Mat(size_y, size_x, CV_8U);
00116         *map_mat_position = Mat(size_y, size_x, CV_8UC3);
00117       }
00118 
00119       const std::vector<int8_t>& map_data (map->data);
00120 
00121       unsigned char *map_mat_data_p=(unsigned char*) map_mat->data;
00122       unsigned char *map_mat_position_data_p=(unsigned char*) map_mat_position->data;
00123 
00124       //We have to flip around the y axis, y for image starts at the top and y for map at the bottom
00125       int size_y_rev = size_y-1;
00126 
00127       for (int y = size_y_rev; y >= 0; --y){
00128 
00129         int idx_map_y = size_x * (size_y -y);
00130         int idx_img_y = size_x * y;
00131 
00132         for (int x = 0; x < size_x; ++x){
00133 
00134           int idx = idx_img_y + x;
00135 
00136           switch (map_data[idx_map_y + x])
00137           {
00138           case -1:
00139             map_mat_position_data_p[idx*3] = 127;
00140             map_mat_position_data_p[idx*3+1] = 127;
00141             map_mat_position_data_p[idx*3+2] = 127;
00142             map_mat_data_p[idx] = 127;
00143             break;
00144 
00145           case 0:
00146             map_mat_position_data_p[idx*3] = 255;
00147             map_mat_position_data_p[idx*3+1] = 255;
00148             map_mat_position_data_p[idx*3+2] = 255;
00149             map_mat_data_p[idx] = 255;
00150             break;
00151 
00152           case 100:
00153             map_mat_position_data_p[idx*3] = 0;
00154             map_mat_position_data_p[idx*3+1] = 0;
00155             map_mat_position_data_p[idx*3+2] = 0;
00156             map_mat_data_p[idx] = 0;
00157             break;
00158           }
00159         }
00160       }
00161 
00162       image_transport_publisher_full_.publish(cv_img_full_.toImageMsg());
00163 
00164       world_map_transformer_.setTransforms(*map);
00165 
00166       Eigen::Vector2f rob_position_world (pose_ptr_->pose.position.x, pose_ptr_->pose.position.y);
00167       Eigen::Vector2f rob_position_map (world_map_transformer_.getC2Coords(rob_position_world));
00168 
00169       Eigen::Vector2i rob_position_mapi (rob_position_map.cast<int>());
00170 
00171         double yaw = tf::getYaw(pose_ptr_->pose.orientation);
00172         double radius = size_x / 100;
00173         circle(*map_mat_position, cvPoint(rob_position_mapi[0],size_y - rob_position_mapi[1]), radius, Scalar(255,0,0),3);
00174         line(*map_mat_position, cvPoint(rob_position_mapi[0],size_y - rob_position_mapi[1]), cvPoint(rob_position_mapi[0] + radius*cos(yaw),size_y - rob_position_mapi[1] - radius * sin(yaw)), Scalar(255,0,0),3);
00175 
00176         image_transport_publisher_full_position_.publish(cv_img_full_with_position_.toImageMsg());
00177     }
00178 
00179     // Only if someone is subscribed to it, do work and publish tile-based map image Also check if pose_ptr_ is valid
00180     if ((image_transport_publisher_tile_.getNumSubscribers() > 0) && (pose_ptr_)){
00181 
00182       world_map_transformer_.setTransforms(*map);
00183 
00184       Eigen::Vector2f rob_position_world (pose_ptr_->pose.position.x, pose_ptr_->pose.position.y);
00185       Eigen::Vector2f rob_position_map (world_map_transformer_.getC2Coords(rob_position_world));
00186 
00187       Eigen::Vector2i rob_position_mapi (rob_position_map.cast<int>());
00188 
00189       Eigen::Vector2i tile_size_lower_halfi (p_size_tiled_map_image_x_ / 2, p_size_tiled_map_image_y_ / 2);
00190 
00191       Eigen::Vector2i min_coords_map (rob_position_mapi - tile_size_lower_halfi);
00192 
00193       //Clamp to lower map coords
00194       if (min_coords_map[0] < 0){
00195         min_coords_map[0] = 0;
00196       }
00197 
00198       if (min_coords_map[1] < 0){
00199         min_coords_map[1] = 0;
00200       }
00201 
00202       Eigen::Vector2i max_coords_map (min_coords_map + Eigen::Vector2i(p_size_tiled_map_image_x_,p_size_tiled_map_image_y_));
00203 
00204       //Clamp to upper map coords
00205       if (max_coords_map[0] > size_x){
00206 
00207         int diff = max_coords_map[0] - size_x;
00208         min_coords_map[0] -= diff;
00209 
00210         max_coords_map[0] = size_x;
00211       }
00212 
00213       if (max_coords_map[1] > size_y){
00214 
00215         int diff = max_coords_map[1] - size_y;
00216         min_coords_map[1] -= diff;
00217 
00218         max_coords_map[1] = size_y;
00219       }
00220 
00221       //Clamp lower again (in case the map is smaller than the selected visualization window)
00222       if (min_coords_map[0] < 0){
00223         min_coords_map[0] = 0;
00224       }
00225 
00226       if (min_coords_map[1] < 0){
00227         min_coords_map[1] = 0;
00228       }
00229 
00230       Eigen::Vector2i actual_map_dimensions(max_coords_map - min_coords_map);
00231 
00232       Mat* map_mat  = &cv_img_tile_.image;
00233 
00234       // resize cv image if it doesn't have the same dimensions as the selected visualization window
00235       if ( (map_mat->rows != actual_map_dimensions[0]) || (map_mat->cols != actual_map_dimensions[1])){
00236         *map_mat = Mat(actual_map_dimensions[0], actual_map_dimensions[1], CV_8U);
00237       }
00238 
00239       const std::vector<int8_t>& map_data (map->data);
00240 
00241       unsigned char *map_mat_data_p=(unsigned char*) map_mat->data;
00242 
00243       //We have to flip around the y axis, y for image starts at the top and y for map at the bottom
00244       int y_img = max_coords_map[1]-1;
00245 
00246       for (int y = min_coords_map[1]; y < max_coords_map[1];++y){
00247 
00248         int idx_map_y = y_img-- * size_x;
00249         int idx_img_y = (y-min_coords_map[1]) * actual_map_dimensions.x();
00250 
00251         for (int x = min_coords_map[0]; x < max_coords_map[0];++x){
00252 
00253           int img_index = idx_img_y + (x-min_coords_map[0]);
00254 
00255           switch (map_data[idx_map_y+x])
00256           {
00257           case 0:
00258             map_mat_data_p[img_index] = 255;
00259             break;
00260 
00261           case -1:
00262             map_mat_data_p[img_index] = 127;
00263             break;
00264 
00265           case 100:
00266             map_mat_data_p[img_index] = 0;
00267             break;
00268           }
00269         }        
00270       }
00271       image_transport_publisher_tile_.publish(cv_img_tile_.toImageMsg());
00272     }
00273   }
00274 
00275   ros::Subscriber map_sub_;
00276   ros::Subscriber pose_sub_;
00277 
00278   image_transport::Publisher image_transport_publisher_full_;
00279   image_transport::Publisher image_transport_publisher_full_position_;
00280   image_transport::Publisher image_transport_publisher_tile_;
00281 
00282   image_transport::ImageTransport* image_transport_;
00283 
00284   geometry_msgs::PoseStampedConstPtr pose_ptr_;
00285 
00286   CvImage cv_img_full_;
00287   CvImage cv_img_full_with_position_;
00288   CvImage cv_img_tile_;
00289 
00290   ros::NodeHandle n_;
00291   ros::NodeHandle pn_;
00292 
00293   int p_size_tiled_map_image_x_;
00294   int p_size_tiled_map_image_y_;
00295 
00296   HectorMapTools::CoordinateTransformer<float> world_map_transformer_;
00297 
00298 };
00299 
00300 int main(int argc, char** argv)
00301 {
00302   ros::init(argc, argv, "map_to_image_node");
00303 
00304   MapAsImageProvider map_image_provider;
00305 
00306   ros::spin();
00307 
00308   return 0;
00309 }


corobot_map_to_jpeg
Author(s): Morgan Cormier
autogenerated on Tue Jan 7 2014 11:39:07