occupancy_grid_file_io.cpp
Go to the documentation of this file.
00001 // Copyright 2017 Intermodalics All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 #include "tango_ros_native/occupancy_grid_file_io.h"
00015 
00016 #include <cmath>
00017 #include <fstream>
00018 #include <iostream>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021 
00022 #include <geometry_msgs/Quaternion.h>
00023 #include <tf/LinearMath/Matrix3x3.h>
00024 
00025 #include <glog/logging.h>
00026 
00027 #include <yaml-cpp/yaml.h>
00028 
00029 namespace {
00030 void AddTrailingSlashToDirectoryPathIfNeeded(std::string* directory_path) {
00031   if (!directory_path->empty() && directory_path->back() != '/') {
00032     (*directory_path) += '/';
00033   }
00034 }
00035 bool DirectoryPathExists(const std::string& path) {
00036   struct stat st;
00037   return (stat(path.c_str(), &st) == 0 && (st.st_mode & S_IFDIR));
00038 }
00039 bool MakeDirectoryPath(const std::string& input_path, mode_t mode) {
00040   if (input_path.empty()) {
00041     // Path is empty, there is nothing to create so we return success.
00042     return 0;
00043   }
00044 
00045   size_t previous_slash_pos = 0;
00046   size_t current_slash_pos;
00047   std::string dir;
00048   int make_dir_status = 0;
00049 
00050   std::string path = input_path;
00051   AddTrailingSlashToDirectoryPathIfNeeded(&path);
00052 
00053   while ((current_slash_pos = path.find_first_of('/', previous_slash_pos)) !=
00054          std::string::npos) {
00055     dir = path.substr(0, current_slash_pos++);
00056     previous_slash_pos = current_slash_pos;
00057     if (dir.empty() || dir == ".")
00058       continue;  // If leading / first time is 0 length.
00059 
00060     if ((make_dir_status = mkdir(dir.c_str(), mode)) && errno != EEXIST) {
00061       return false;
00062     }
00063   }
00064   return true;
00065 }
00066 } // namespace
00067 
00068 namespace occupancy_grid_file_io {
00069 bool SaveOccupancyGridToFiles(
00070     const std::string& map_name, const std::string& map_uuid,
00071     const std::string& map_directory, const nav_msgs::OccupancyGrid& occupancy_grid) {
00072   return SaveOccupancyGridDataToPgmFile(map_name, map_directory, occupancy_grid)
00073       && SaveOccupancyGridMetadataToYamlFile(map_name, map_uuid, map_directory, occupancy_grid.info);
00074 }
00075 
00076 bool SaveOccupancyGridDataToPgmFile(
00077     const std::string& map_name, const std::string& map_directory,
00078     const nav_msgs::OccupancyGrid& occupancy_grid) {
00079   std::string map_directory_with_trailing_slash = map_directory;
00080   AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00081   if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
00082     LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
00083     if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
00084       LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
00085       return false;
00086     }
00087   }
00088 
00089   std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
00090   FILE* pgm_file = fopen(map_pgm_file_path.c_str(), "w");
00091   if (!pgm_file) {
00092     LOG(ERROR) << "Could no open file " << map_pgm_file_path;
00093     return false;
00094   }
00095 
00096   fprintf(pgm_file, "P5\n# CREATOR: TangoRosStreamer %.3f m/pix\n%d %d\n255\n",
00097           occupancy_grid.info.resolution,
00098           occupancy_grid.info.width, occupancy_grid.info.height);
00099   for (size_t i = 0; i < occupancy_grid.info.height; ++i) {
00100     for (size_t j = 0; j < occupancy_grid.info.width; ++j) {
00101       // Need to invert the ordering of the cells to
00102       // produce an image with pixel (0,0) in the top-left corner.
00103       int value = occupancy_grid.data[j + (occupancy_grid.info.height - i - 1) * occupancy_grid.info.width];
00104       if (value == 0) {
00105         fputc(254, pgm_file);
00106       } else if (value == +100) {
00107         fputc(000, pgm_file);
00108       } else {
00109         fputc(205, pgm_file);
00110       }
00111     }
00112   }
00113   fclose(pgm_file);
00114   LOG(INFO) << "Map image successfully saved to " << map_pgm_file_path;
00115   return true;
00116 }
00117 
00118 bool SaveOccupancyGridMetadataToYamlFile(
00119     const std::string& map_name, const std::string& map_uuid,
00120     const std::string& map_directory, const nav_msgs::MapMetaData& map_metadata) {
00121   std::string map_directory_with_trailing_slash = map_directory;
00122   AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00123   if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
00124     LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
00125     if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
00126       LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
00127       return false;
00128     }
00129   }
00130 
00131   std::string image_name = map_name;
00132   if (image_name.empty())
00133     image_name = "\"\"";
00134   std::string uuid = map_uuid;
00135   if (uuid.empty())
00136     uuid = "\"\"";
00137 
00138   std::string map_yaml_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
00139   FILE* yaml_file = fopen(map_yaml_file_path.c_str(), "w");
00140   if (!yaml_file) {
00141     LOG(ERROR) << "Could no open file " << map_yaml_file_path;
00142     return false;
00143   }
00144 
00145   tf::Matrix3x3 mat(tf::Quaternion(map_metadata.origin.orientation.x,
00146                                    map_metadata.origin.orientation.y,
00147                                    map_metadata.origin.orientation.z,
00148                                    map_metadata.origin.orientation.w));
00149   double yaw, pitch, roll;
00150   mat.getEulerYPR(yaw, pitch, roll);
00151   if (std::isnan(yaw))
00152     yaw = 0.0;
00153 
00154   fprintf(yaml_file, "image: %s.pgm\nresolution: %f\norigin: [%f, %f, %f]\nnegate: 0\n"
00155       "occupied_thresh: 0.65\nfree_thresh: 0.196\nuuid: %s\n\n",
00156       map_name.c_str(), map_metadata.resolution, map_metadata.origin.position.x,
00157       map_metadata.origin.position.y, yaw, uuid.c_str());
00158 
00159   fclose(yaml_file);
00160   LOG(INFO) << "Map yaml file successfully saved to " << map_yaml_file_path;
00161   return true;
00162 }
00163 
00164 bool LoadOccupancyGridFromFiles(
00165     const std::string&  map_name, const std::string& map_directory,
00166     nav_msgs::OccupancyGrid* occupancy_grid, std::string* map_uuid) {
00167   int negate;
00168   double occupied_threshold;
00169   double free_threshold;
00170   bool result = LoadOccupancyGridMetadataFromYamlFile(
00171       map_name, map_directory, &(occupancy_grid->info), &negate,
00172       &occupied_threshold, &free_threshold, map_uuid);
00173   return result && LoadOccupancyGridDataFromPgmFile(
00174       map_name, map_directory, negate, occupied_threshold, free_threshold,
00175       occupancy_grid);
00176 }
00177 
00178 bool LoadOccupancyGridDataFromPgmFile(
00179     const std::string&  map_name, const std::string& map_directory,
00180     bool negate, double occupied_threshold, double free_threshold,
00181     nav_msgs::OccupancyGrid* occupancy_grid) {
00182   std::string map_directory_with_trailing_slash = map_directory;
00183   AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00184 
00185   std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
00186   std::ifstream pgm_file(map_pgm_file_path, std::ios::binary);
00187   if (pgm_file.fail()) {
00188     LOG(ERROR) << "Could no open file " << map_pgm_file_path;
00189     return false;
00190   }
00191 
00192   // First line contains file type.
00193   std::string file_type;
00194   getline(pgm_file, file_type);
00195   LOG(INFO) << file_type;
00196   if (file_type.compare("P5") != 0) {
00197     LOG(ERROR) << "Pgm file type error. Type is " << file_type
00198         << " while supported type is P5.";
00199     return false;
00200   }
00201   // Second line contains comment.
00202   std::string comment;
00203   getline(pgm_file, comment);
00204   LOG(INFO) << comment;
00205   // Third line contains size.
00206   std::string image_size;
00207   getline(pgm_file, image_size);
00208   std::stringstream size_stream(image_size);
00209   size_stream >> occupancy_grid->info.width >> occupancy_grid->info.height;
00210   LOG(INFO) << "Image size is " << occupancy_grid->info.width << "x" << occupancy_grid->info.height;
00211   // Fourth line contains max value.
00212   std::string max_value_string;
00213   getline(pgm_file, max_value_string);
00214   std::stringstream max_val_stream(max_value_string);
00215   int max_value = 0;
00216   max_val_stream >> max_value;
00217   // Following lines contain binary data.
00218   int pixel_array[occupancy_grid->info.height * occupancy_grid->info.width];
00219   for (size_t i = 0; i < occupancy_grid->info.height * occupancy_grid->info.width; ++i) {
00220     char pixel = pgm_file.get();
00221     pixel_array[i] = static_cast<int>(pixel);
00222   }
00223   // Need to invert the ordering of the pixels to
00224   // produce a map with cell (0,0) in the lower-left corner.
00225   occupancy_grid->data.reserve(occupancy_grid->info.height * occupancy_grid->info.width);
00226   for (size_t i = 0; i < occupancy_grid->info.height; ++i) {
00227     for (size_t j = 0; j < occupancy_grid->info.width; ++j) {
00228       int value = pixel_array[j + (occupancy_grid->info.height - i - 1) * occupancy_grid->info.width];
00229       if (negate)
00230         value = max_value - value;
00231       double occupancy = (max_value - value) / static_cast<double>(max_value);
00232       if (occupancy < free_threshold) {
00233         occupancy_grid->data.push_back(0);
00234       } else if (occupancy > occupied_threshold) {
00235         occupancy_grid->data.push_back(100);
00236       } else {
00237         occupancy_grid->data.push_back(-1);
00238       }
00239     }
00240   }
00241   pgm_file.close();
00242   LOG(INFO) << "Map image successfully loaded from " << map_pgm_file_path;
00243   return true;
00244 }
00245 
00246 bool LoadOccupancyGridMetadataFromYamlFile(
00247     const std::string&  map_name, const std::string& map_directory,
00248     nav_msgs::MapMetaData* map_metadata, int* negate,
00249     double* occupied_threshold, double* free_threshold, std::string* map_uuid) {
00250   std::string map_directory_with_trailing_slash = map_directory;
00251   AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00252 
00253   std::string map_yam_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
00254   std::ifstream yaml_file(map_yam_file_path.c_str());
00255   if (yaml_file.fail()) {
00256     LOG(ERROR) << "Could no open file " << map_yam_file_path;
00257     return false;
00258   }
00259 
00260   YAML::Node node = YAML::Load(yaml_file);
00261   try {
00262     map_metadata->resolution = node["resolution"].as<double>();
00263   } catch (YAML::RepresentationException& e) {
00264     LOG(ERROR) << "The map does not contain a resolution tag or it is invalid. " << e.msg;
00265     return false;
00266   }
00267   try {
00268     *negate = node["negate"].as<int>();
00269   } catch (YAML::RepresentationException& e) {
00270     LOG(ERROR) << "The map does not contain a negate tag or it is invalid. " << e.msg;
00271     return false;
00272   }
00273   try {
00274     *occupied_threshold = node["occupied_thresh"].as<double>();
00275   } catch (YAML::RepresentationException& e) {
00276     LOG(ERROR) << "The map does not contain an occupied_thresh tag or it is invalid. " << e.msg;
00277     return false;
00278   }
00279   try {
00280     *free_threshold = node["free_thresh"].as<double>();
00281   } catch (YAML::RepresentationException& e) {
00282     LOG(ERROR) << "The map does not contain a free_thresh tag or it is invalid. " << e.msg;
00283     return false;
00284   }
00285   try {
00286     map_metadata->origin.position.x = node["origin"][0].as<double>();
00287     map_metadata->origin.position.y = node["origin"][1].as<double>();
00288     map_metadata->origin.position.z = 0.0;
00289     tf::Quaternion quaternion;
00290     double yaw = node["origin"][2].as<double>();
00291     quaternion.setRPY(0., 0., yaw);
00292     map_metadata->origin.orientation.x = quaternion.x();
00293     map_metadata->origin.orientation.y = quaternion.y();
00294     map_metadata->origin.orientation.z = quaternion.z();
00295     map_metadata->origin.orientation.w = quaternion.w();
00296   } catch (YAML::RepresentationException& e) {
00297     LOG(ERROR) << "The map does not contain an origin tag or it is invalid. " << e.msg;
00298     return false;
00299   }
00300   try {
00301     *map_uuid = node["uuid"].as<std::string>();
00302   } catch (YAML::RepresentationException& e) {
00303     LOG(WARNING) << "The map does not contain a uuid tag or it is invalid. " << e.msg;
00304   }
00305   yaml_file.close();
00306   LOG(INFO) << "Map yaml file successfully loaded from " << map_yam_file_path;
00307   return true;
00308 }
00309 } // namespace occupancy_grid_file_io


tango_ros_native
Author(s):
autogenerated on Thu Jun 6 2019 19:49:54