00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <rqt_map_merger/map_merger.h>
00034
00035 #include <pluginlib/class_list_macros.h>
00036 #include <ros/master.h>
00037 #include <sensor_msgs/image_encodings.h>
00038
00039 #include <cv_bridge/cv_bridge.h>
00040 #include <opencv2/imgproc/imgproc.hpp>
00041
00042 #include <QMessageBox>
00043 #include <QPainter>
00044 #include <opencv/cv.h>
00045 #include <opencv/highgui.h>
00046 #include <geometry_msgs/Transform.h>
00047 #include "hector_mapstitch/mapstitch.h"
00048 #include "hector_mapstitch/utils.h"
00049 #include <std_msgs/String.h>
00050 #include <sstream>
00051
00052 namespace rqt_map_merger {
00053
00054 MapMerger::MapMerger()
00055 : rqt_gui_cpp::Plugin()
00056 , widget_(0)
00057 {
00058 setObjectName("MapMerger");
00059 }
00060
00061 void MapMerger::initPlugin(qt_gui_cpp::PluginContext& context)
00062 {
00063 std::cout << "started map merging plugin " <<std::endl;
00064 widget_ = new QWidget();
00065 ui_.setupUi(widget_);
00066
00067 if (context.serialNumber() > 1)
00068 {
00069 widget_->setWindowTitle(widget_->windowTitle() + " (" + QString::number(context.serialNumber()) + ")");
00070 }
00071 context.addWidget(widget_);
00072
00073 ui_.map2_label->installEventFilter(this);
00074 ui_.map1_label->installEventFilter(this);
00075
00076 map_1_sub_= my_nh_.subscribe("/original_map_robot_1", 1, &MapMerger::map1Callback,this);
00077 map_2_sub_= my_nh_.subscribe("/original_map_robot_2", 1, &MapMerger::map2Callback,this);
00078
00079 map_1_to_use_pub_ = my_nh_.advertise<nav_msgs::OccupancyGrid>("/map_to_use_1",10,true);
00080 map_2_to_use_pub_ = my_nh_.advertise<nav_msgs::OccupancyGrid>("/map_to_use_2",10,true);
00081
00082 hector_command_pub_ = my_nh_.advertise<std_msgs::String>("/syscommand", 10,true);
00083
00084
00085
00086
00087
00088
00089 connect(ui_.map_hector1_horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(onSlider1Moved(int)));
00090 connect(ui_.map_hector2_horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(onSlider2Moved(int)));
00091 connect(ui_.merge_button, SIGNAL(pressed()), this, SLOT(onMergePressed()));
00092 connect(ui_.save_geotiff_button, SIGNAL(pressed()), this, SLOT(onSaveGeotiffPressed()));
00093 connect(ui_.use_stored_transform_checkBox, SIGNAL(stateChanged(int)), this, SLOT(onStateUseTransformChanged(int)));
00094 connect(ui_.store_current_transform_button, SIGNAL(pressed()), this, SLOT(onGetTransform()));
00095
00096 redraw_Label_1();
00097 redraw_Label_2();
00098 map_save_timer_ = my_nh_.createTimer(ros::Duration(20.0), &MapMerger::timerCallback, this, false );
00099 current_idx_1_ = 0;
00100 current_idx_2_ = 0;
00101 stored_idx_1_ = 0;
00102 stored_idx_2_ = 0;
00103 use_stored_transform_ = false;
00104 first_map_1_received =0;
00105 first_map_2_received =0;
00106
00107 std::stringstream sstr;
00108 sstr << stored_idx_1_ << " | " << stored_idx_2_;
00109
00110 ui_.stored_transform_text->setText(sstr.str().c_str());
00111 }
00112
00113 void MapMerger::timerCallback(const ros::TimerEvent& e){
00114 qimages_1_.push_back(qimage_1_);
00115 qimages_2_.push_back(qimage_2_);
00116 cv_maps_1_.push_back(cv_map_1_);
00117 cv_maps_2_.push_back(cv_map_2_);
00118 og_maps_1_.push_back(og_map_1_);
00119 og_maps_2_.push_back(og_map_2_);
00120 ui_.map_hector1_horizontalSlider->setRange(0,qimages_1_.size()-1);
00121 ui_.map_hector2_horizontalSlider->setRange(0,qimages_2_.size()-1);
00122 }
00123
00124
00125
00126 void MapMerger::onSlider1Moved(int idx){
00127 current_idx_1_ = idx;
00128
00129 std::stringstream sstr;
00130 sstr << idx;
00131
00132 ui_.map_1_text->setText(sstr.str().c_str());
00133 redraw_Label_1();
00134 }
00135
00136 void MapMerger::onSlider2Moved(int idx){
00137 current_idx_2_ = idx;
00138
00139 std::stringstream sstr;
00140 sstr << idx;
00141
00142 ui_.map_2_text->setText(sstr.str().c_str());
00143 redraw_Label_2();
00144 }
00145
00146 void MapMerger::onMergePressed(){
00147 redraw_Label_merged();
00148 }
00149
00150 void MapMerger::onStateUseTransformChanged(int checked){
00151 use_stored_transform_ = checked;
00152 stored_transform = current_transform;
00153
00154 }
00155
00156 void MapMerger::onGetTransform(){
00157 std::cout << "1" <<stored_idx_1_ <<"2" <<stored_idx_2_ << std::endl;
00158 stored_transform = current_transform;
00159 stored_idx_1_ = current_idx_1_;
00160 stored_idx_2_ = current_idx_2_;
00161 std::stringstream sstr;
00162 sstr << stored_idx_1_ << " | " << stored_idx_2_;
00163
00164 ui_.stored_transform_text->setText(sstr.str().c_str());
00165 }
00166
00167 void MapMerger::onSaveGeotiffPressed(){
00168 std_msgs::String geo_string;
00169 geo_string.data = "savegeotiff";
00170 hector_command_pub_.publish(geo_string);
00171 }
00172
00173 void MapMerger::redraw_Label_1(){
00174 if (qimages_1_.size()>0)
00175 {
00176
00177 qimage_mutex_.lock();
00178
00179 QImage image_scaled = qimages_1_[current_idx_1_].scaled(ui_.map1_label->width(), ui_.map1_label->height(), Qt::IgnoreAspectRatio );
00180 ui_.map1_label->setPixmap(QPixmap::fromImage(image_scaled));
00181
00182 qimage_mutex_.unlock();
00183
00184
00185 } else {
00186 ROS_INFO("no map for robot1 known");
00187 }
00188
00189
00190 }
00191
00192 void MapMerger::redraw_Label_2(){
00193
00194 if (qimages_2_.size()>0)
00195 {
00196 qimage_mutex_.lock();
00197
00198
00199 QImage image_scaled = qimages_2_[current_idx_2_].scaled(ui_.map2_label->width(), ui_.map2_label->height(), Qt::IgnoreAspectRatio );
00200 ui_.map2_label->setPixmap(QPixmap::fromImage(image_scaled));
00201 qimage_mutex_.unlock();
00202
00203 } else {
00204 ROS_INFO("no map for robot2 known");
00205
00206
00207 }
00208
00209
00210 }
00211
00212 void MapMerger::redraw_Label_merged(){
00213
00214 if (cv_maps_1_.size() > 0 && cv_maps_2_.size()>0 && og_maps_1_.size()>0 && og_maps_2_.size()>0){
00215
00216 StitchedMap stitched_map(cv_maps_1_[stored_idx_1_], cv_maps_2_[stored_idx_2_],stored_transform);
00217 if (!use_stored_transform_){
00218 stitched_map =StitchedMap(cv_maps_1_[current_idx_1_], cv_maps_2_[current_idx_2_]);
00219 }
00220
00221
00222 if(stitched_map.isValid())
00223 {
00224 ui_.merge_button->setText("merging ...");
00225 cv::Mat stitched_cv_map = stitched_map.get_stitch();
00226 ui_.merge_button->setText("merge");
00227 cv::Mat gray;
00228 stitched_cv_map.convertTo(gray, CV_8UC1);
00229 cv::Mat temp;
00230 cv::cvtColor(gray, temp, CV_GRAY2RGB);
00231
00232
00233 QImage image(temp.data, temp.cols, temp.rows, QImage::Format_RGB888);
00234 QImage image_scaled = image.scaled(ui_.merged_map_label->width(), ui_.merged_map_label->height(), Qt::IgnoreAspectRatio );
00235 ui_.merged_map_label->setPixmap(QPixmap::fromImage(image_scaled));
00236
00237 map_1_to_use_pub_.publish(og_maps_1_[current_idx_1_]);
00238 map_2_to_use_pub_.publish(og_maps_2_[current_idx_2_]);
00239
00240
00241 current_transform = stitched_map.getRigidTransform().clone();
00242 }
00243
00244 }
00245 }
00246
00247 bool MapMerger::eventFilter(QObject* watched, QEvent* event)
00248 {
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 return QObject::eventFilter(watched, event);
00269 }
00270
00271 void MapMerger::shutdownPlugin()
00272 {
00273
00274 }
00275
00276 void MapMerger::map1Callback(nav_msgs::OccupancyGridConstPtr const & map)
00277 {
00278 cv::Mat map1_cv = occupancyGridToCvMat(map.get());
00279 cv::Mat gray;
00280 map1_cv.convertTo(gray, CV_8UC1);
00281 cv::cvtColor(gray, conversion_mat_, CV_GRAY2RGB);
00282
00283
00284 QImage image(conversion_mat_.data, conversion_mat_.cols, conversion_mat_.rows, QImage::Format_RGB888);
00285
00286 qimage_mutex_.lock();
00287 qimage_1_ = image.copy();
00288 qimage_mutex_.unlock();
00289
00290 cv_map_1_ = map1_cv;
00291 og_map_1_ = *map;
00292
00293
00294
00295
00296
00297
00298 }
00299
00300 void MapMerger::map2Callback(nav_msgs::OccupancyGridConstPtr const & map)
00301 {
00302 cv::Mat map2_cv = occupancyGridToCvMat(map.get());
00303 cv::Mat gray;
00304 map2_cv.convertTo(gray, CV_8UC1);
00305 cv::cvtColor(gray, conversion_mat_, CV_GRAY2RGB);
00306 QImage image(conversion_mat_.data, conversion_mat_.cols, conversion_mat_.rows, QImage::Format_RGB888);
00307
00308 qimage_mutex_.lock();
00309 qimage_2_ = image.copy();
00310 qimage_mutex_.unlock();
00311
00312 cv_map_2_ = map2_cv;
00313 og_map_2_ = *map;
00314
00315 if (!first_map_2_received){
00316
00317 first_map_2_received = true;
00318 redraw_Label_2();
00319 }
00320
00321
00322 }
00323
00324 nav_msgs::OccupancyGrid MapMerger::cvMatToOccupancyGrid(const cv::Mat * im)
00325 {
00326 nav_msgs::OccupancyGrid map;
00327
00328 map.info.height = im->rows;
00329 map.info.width = im->cols;
00330
00331 map.data.resize(map.info.width * map.info.height);
00332
00333 for(size_t i = 0; i < map.data.size(); ++i)
00334 {
00335 uint8_t map_val = im->data[i];
00336 if(map_val == 0) map.data[i] = 100;
00337 else if(map_val == 254) map.data[i] = 0;
00338 else map.data[i] = -1;
00339 }
00340
00341 return map;
00342 }
00343
00344
00345 cv::Mat MapMerger::occupancyGridToCvMat(const nav_msgs::OccupancyGrid *map)
00346 {
00347 uint8_t *data = (uint8_t*) map->data.data(),
00348 testpoint = data[0];
00349 bool mapHasPoints = false;
00350
00351 cv::Mat im(map->info.height, map->info.width, CV_8UC1);
00352
00353
00354 for (size_t i=0; i<map->data.size(); i++)
00355 {
00356 if (data[i] == 0) im.data[i] = 254;
00357 else if (data[i] == 100) im.data[i] = 0;
00358 else im.data[i] = 205;
00359
00360
00361 if (i!=0) mapHasPoints = mapHasPoints || (data[i] != testpoint);
00362 testpoint = data[i];
00363 }
00364
00365
00366 if (!mapHasPoints) { ROS_WARN("map is empty, ignoring update."); }
00367
00368 return im;
00369 }
00370
00371 }
00372 PLUGINLIB_EXPORT_CLASS(rqt_map_merger::MapMerger, rqt_gui_cpp::Plugin)
00373