map_to_image_node.cpp
Go to the documentation of this file.
1 //=================================================================================================
2 // Copyright (c) 2011, Stefan Kohlbrecher, TU Darmstadt
3 // All rights reserved.
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the Simulation, Systems Optimization and Robotics
13 // group, TU Darmstadt nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without
15 // specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //=================================================================================================
28 
29 #include "ros/ros.h"
30 
31 #include <nav_msgs/GetMap.h>
32 #include <geometry_msgs/Quaternion.h>
33 #include <geometry_msgs/PoseStamped.h>
35 
36 #include <cv_bridge/cv_bridge.h>
38 #include <Eigen/Geometry>
39 
41 
42 using namespace std;
43 
49 {
50 public:
52  : pn_("~")
53  {
54 
55  image_transport_ = new image_transport::ImageTransport(n_);
56  image_transport_publisher_full_ = image_transport_->advertise("map_image/full", 1);
57  image_transport_publisher_tile_ = image_transport_->advertise("map_image/tile", 1);
58 
59  pose_sub_ = n_.subscribe("pose", 1, &MapAsImageProvider::poseCallback, this);
60  map_sub_ = n_.subscribe("map", 1, &MapAsImageProvider::mapCallback, this);
61 
62  //Which frame_id makes sense?
63  cv_img_full_.header.frame_id = "map_image";
64  cv_img_full_.encoding = sensor_msgs::image_encodings::MONO8;
65 
66  cv_img_tile_.header.frame_id = "map_image";
67  cv_img_tile_.encoding = sensor_msgs::image_encodings::MONO8;
68 
69  //Fixed cell width for tile based image, use dynamic_reconfigure for this later
70  p_size_tiled_map_image_x_ = 64;
71  p_size_tiled_map_image_y_ = 64;
72 
73  ROS_INFO("Map to Image node started.");
74  }
75 
77  {
78  delete image_transport_;
79  }
80 
81  //We assume the robot position is available as a PoseStamped here (querying tf would be the more general option)
82  void poseCallback(const geometry_msgs::PoseStampedConstPtr& pose)
83  {
84  pose_ptr_ = pose;
85  }
86 
87  //The map->image conversion runs every time a new map is received at the moment
88  void mapCallback(const nav_msgs::OccupancyGridConstPtr& map)
89  {
90  int size_x = map->info.width;
91  int size_y = map->info.height;
92 
93  if ((size_x < 3) || (size_y < 3) ){
94  ROS_INFO("Map size is only x: %d, y: %d . Not running map to image conversion", size_x, size_y);
95  return;
96  }
97 
98  // Only if someone is subscribed to it, do work and publish full map image
99  if (image_transport_publisher_full_.getNumSubscribers() > 0){
100  cv::Mat* map_mat = &cv_img_full_.image;
101 
102  // resize cv image if it doesn't have the same dimensions as the map
103  if ( (map_mat->rows != size_y) || (map_mat->cols != size_x)){
104  *map_mat = cv::Mat(size_y, size_x, CV_8U);
105  }
106 
107  const std::vector<int8_t>& map_data (map->data);
108 
109  unsigned char *map_mat_data_p=(unsigned char*) map_mat->data;
110 
111  //We have to flip around the y axis, y for image starts at the top and y for map at the bottom
112  int size_y_rev = size_y-1;
113 
114  for (int y = size_y_rev; y >= 0; --y){
115 
116  int idx_map_y = size_x * (size_y_rev -y);
117  int idx_img_y = size_x * y;
118 
119  for (int x = 0; x < size_x; ++x){
120 
121  int idx = idx_img_y + x;
122 
123  switch (map_data[idx_map_y + x])
124  {
125  case -1:
126  map_mat_data_p[idx] = 127;
127  break;
128 
129  case 0:
130  map_mat_data_p[idx] = 255;
131  break;
132 
133  case 100:
134  map_mat_data_p[idx] = 0;
135  break;
136  }
137  }
138  }
139  image_transport_publisher_full_.publish(cv_img_full_.toImageMsg());
140  }
141 
142  // Only if someone is subscribed to it, do work and publish tile-based map image Also check if pose_ptr_ is valid
143  if ((image_transport_publisher_tile_.getNumSubscribers() > 0) && (pose_ptr_)){
144 
145  world_map_transformer_.setTransforms(*map);
146 
147  Eigen::Vector2f rob_position_world (pose_ptr_->pose.position.x, pose_ptr_->pose.position.y);
148  Eigen::Vector2f rob_position_map (world_map_transformer_.getC2Coords(rob_position_world));
149 
150  Eigen::Vector2i rob_position_mapi (rob_position_map.cast<int>());
151 
152  Eigen::Vector2i tile_size_lower_halfi (p_size_tiled_map_image_x_ / 2, p_size_tiled_map_image_y_ / 2);
153 
154  Eigen::Vector2i min_coords_map (rob_position_mapi - tile_size_lower_halfi);
155 
156  //Clamp to lower map coords
157  if (min_coords_map[0] < 0){
158  min_coords_map[0] = 0;
159  }
160 
161  if (min_coords_map[1] < 0){
162  min_coords_map[1] = 0;
163  }
164 
165  Eigen::Vector2i max_coords_map (min_coords_map + Eigen::Vector2i(p_size_tiled_map_image_x_,p_size_tiled_map_image_y_));
166 
167  //Clamp to upper map coords
168  if (max_coords_map[0] > size_x){
169 
170  int diff = max_coords_map[0] - size_x;
171  min_coords_map[0] -= diff;
172 
173  max_coords_map[0] = size_x;
174  }
175 
176  if (max_coords_map[1] > size_y){
177 
178  int diff = max_coords_map[1] - size_y;
179  min_coords_map[1] -= diff;
180 
181  max_coords_map[1] = size_y;
182  }
183 
184  //Clamp lower again (in case the map is smaller than the selected visualization window)
185  if (min_coords_map[0] < 0){
186  min_coords_map[0] = 0;
187  }
188 
189  if (min_coords_map[1] < 0){
190  min_coords_map[1] = 0;
191  }
192 
193  Eigen::Vector2i actual_map_dimensions(max_coords_map - min_coords_map);
194 
195  cv::Mat* map_mat = &cv_img_tile_.image;
196 
197  // resize cv image if it doesn't have the same dimensions as the selected visualization window
198  if ( (map_mat->rows != actual_map_dimensions[0]) || (map_mat->cols != actual_map_dimensions[1])){
199  *map_mat = cv::Mat(actual_map_dimensions[0], actual_map_dimensions[1], CV_8U);
200  }
201 
202  const std::vector<int8_t>& map_data (map->data);
203 
204  unsigned char *map_mat_data_p=(unsigned char*) map_mat->data;
205 
206  //We have to flip around the y axis, y for image starts at the top and y for map at the bottom
207  int y_img = max_coords_map[1]-1;
208 
209  for (int y = min_coords_map[1]; y < max_coords_map[1];++y){
210 
211  int idx_map_y = y_img-- * size_x;
212  int idx_img_y = (y-min_coords_map[1]) * actual_map_dimensions.x();
213 
214  for (int x = min_coords_map[0]; x < max_coords_map[0];++x){
215 
216  int img_index = idx_img_y + (x-min_coords_map[0]);
217 
218  switch (map_data[idx_map_y+x])
219  {
220  case 0:
221  map_mat_data_p[img_index] = 255;
222  break;
223 
224  case -1:
225  map_mat_data_p[img_index] = 127;
226  break;
227 
228  case 100:
229  map_mat_data_p[img_index] = 0;
230  break;
231  }
232  }
233  }
234  image_transport_publisher_tile_.publish(cv_img_tile_.toImageMsg());
235  }
236  }
237 
240 
243 
245 
246  geometry_msgs::PoseStampedConstPtr pose_ptr_;
247 
250 
253 
256 
258 
259 };
260 
261 int main(int argc, char** argv)
262 {
263  ros::init(argc, argv, "map_to_image_node");
264 
265  MapAsImageProvider map_image_provider;
266 
267  ros::spin();
268 
269  return 0;
270 }
geometry_msgs::PoseStampedConstPtr pose_ptr_
HectorMapTools::CoordinateTransformer< float > world_map_transformer_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
This node provides occupancy grid maps as images via image_transport, so the transmission consumes le...
ROSCPP_DECL void spin(Spinner &spinner)
cv_bridge::CvImage cv_img_full_
#define ROS_INFO(...)
image_transport::Publisher image_transport_publisher_tile_
int main(int argc, char **argv)
image_transport::Publisher image_transport_publisher_full_
image_transport::ImageTransport * image_transport_
ros::Subscriber pose_sub_
void mapCallback(const nav_msgs::OccupancyGridConstPtr &map)
ros::Subscriber map_sub_
cv_bridge::CvImage cv_img_tile_
void poseCallback(const geometry_msgs::PoseStampedConstPtr &pose)


hector_compressed_map_transport
Author(s): Stefan Kohlbrecher
autogenerated on Sun Nov 3 2019 03:18:31