NDT建圖--apollo

/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/random.hpp>
#include <string>
#include <vector>
#include "modules/localization/msf/common/io/velodyne_utility.h"
#include "modules/localization/msf/common/util/extract_ground_plane.h"
#include "modules/localization/msf/common/util/system_utility.h"
#include "modules/localization/msf/local_pyramid_map/ndt_map/ndt_map.h"
#include "modules/localization/msf/local_pyramid_map/ndt_map/ndt_map_pool.h"

int main(int argc, char** argv) {
  boost::program_options::options_description boost_desc("Allowed options");
  boost_desc.add_options()("help", "produce help message")(
      "pcd_folders", boost::program_options::value<std::vector<std::string>>(),
      "provide the pcd folders")(
      "pose_files", boost::program_options::value<std::vector<std::string>>(),
      "provide pose files")("map_folder",
                            boost::program_options::value<std::string>(),
                            "provide map folder")(
      "resolution_type", boost::program_options::value<std::string>(),
      "map resolution type: single or multi")(
      "resolution", boost::program_options::value<float>(),
      "provide map resolution")(
      "resolution_z",
      boost::program_options::value<float>()->default_value(0.03125),
      "provide map resolution of z")(
      "zone_id", boost::program_options::value<int>(), "provide zone id")(
      "set_road_cells",
      boost::program_options::value<bool>()->default_value(true),
      "whether enable setting road cells, default true")(
      "pool_size",
      boost::program_options::value<unsigned int>()->default_value(20),
      "set pool size");

  boost::program_options::variables_map boost_args;
  boost::program_options::store(
      boost::program_options::parse_command_line(argc, argv, boost_desc),
      boost_args);
  boost::program_options::notify(boost_args);

  if (boost_args.count("help")) {
    std::cout << boost_desc << std::endl;
    return 0;
  }

  const std::vector<std::string> pcd_folder_paths =
      boost_args["pcd_folders"].as<std::vector<std::string>>();
  const std::vector<std::string> pose_files =
      boost_args["pose_files"].as<std::vector<std::string>>();
  if (pcd_folder_paths.size() != pose_files.size()) {
    std::cerr << "the count of pcd folders is not equal pose files"
              << std::endl;
    return -1;
  }
  const std::string map_base_folder =
      boost_args["map_folder"].as<std::string>();
  const int zone_id = boost_args["zone_id"].as<int>();
  const unsigned int pool_size = boost_args["pool_size"].as<unsigned int>();

  const std::string resolution_type =
      boost_args["resolution_type"].as<std::string>();
  if (strcasecmp(resolution_type.c_str(), "single") != 0 &&
      strcasecmp(resolution_type.c_str(), "multi") != 0) {
    std::cerr << "map resolution type invalid. (single or multi)" << std::endl;
    return -1;
  }

  float single_resolution_map = boost_args["resolution"].as<float>();
  if (fabs(single_resolution_map - 0.03125) > 1e-8 &&
      fabs(single_resolution_map - 0.0625) > 1e-8 &&
      fabs(single_resolution_map - 0.125) < 1e-8 &&
      fabs(single_resolution_map - 0.25) < 1e-8 &&
      fabs(single_resolution_map - 0.5) < 1e-8 &&
      fabs(single_resolution_map - 1.0) < 1e-8 &&
      fabs(single_resolution_map - 2.0) < 1e-8 &&
      fabs(single_resolution_map - 4.0) < 1e-8 &&
      fabs(single_resolution_map - 8.0) < 1e-8 &&
      fabs(single_resolution_map - 16.0) < 1e-8) {
    std::cerr << "map resolution can only be: 0.03125, "
              << "0.0625, 0.125, 0.25, 0.5, 1.0, 2.0, "
              << "4.0, 8.0 or 16.0." << std::endl;
  }
  float single_resolution_map_z = boost_args["resolution_z"].as<float>();
  std::cout << "single_resolution_map_z: " << single_resolution_map_z
            << std::endl;

  // load all poses
  std::vector<std::vector<Eigen::Affine3d>> pcd_poses(pcd_folder_paths.size());
  std::vector<std::vector<double>> time_stamps(pcd_folder_paths.size());
  std::vector<std::vector<unsigned int>> pcd_indices(pcd_folder_paths.size());
  for (std::size_t i = 0; i < pose_files.size(); ++i) {
    apollo::localization::msf::velodyne::LoadPcdPoses(
        pose_files[i], &pcd_poses[i], &time_stamps[i], &pcd_indices[i]);
  }

  if (!apollo::localization::msf::system::IsExists(map_base_folder)) {
    if (apollo::localization::msf::system::CreateDirectory(map_base_folder)) {
      std::cerr << "Create map directory failed." << std::endl;
    }
  }

  // Output Config file
  apollo::localization::msf::pyramid_map::NdtMapConfig ndt_map_config(
      "map_ndt_v01");
  if (strcasecmp(resolution_type.c_str(), "single") == 0) {
    ndt_map_config.SetSingleResolutions(single_resolution_map);
    ndt_map_config.SetSingleResolutionZ(single_resolution_map_z);
  } else {
    ndt_map_config.SetMultiResolutions();
    ndt_map_config.SetMultiResolutionsZ();
  }
  float distance = 1024 * 0.125;
  unsigned int node_size =
      static_cast<unsigned int>(distance / ndt_map_config.map_resolutions_[0]);
  std::cout << "Node size: " << node_size << std::endl;
  ndt_map_config.map_node_size_x_ = node_size;
  ndt_map_config.map_node_size_y_ = node_size;

  ndt_map_config.map_datasets_.insert(ndt_map_config.map_datasets_.end(),
                                      pcd_folder_paths.begin(),
                                      pcd_folder_paths.end());
  char file_buf[1024];
  snprintf(file_buf, sizeof(file_buf), "%s/config.xml",
           map_base_folder.c_str());
  ndt_map_config.Save(file_buf);

  // Initialize map and pool
  apollo::localization::msf::pyramid_map::NdtMap ndt_map(&ndt_map_config);
  unsigned int thread_size = 4;
  apollo::localization::msf::pyramid_map::NdtMapNodePool ndt_map_node_pool(
      pool_size, thread_size);
  ndt_map_node_pool.Initial(&ndt_map_config);
  ndt_map.InitMapNodeCaches(pool_size / 2, pool_size);
  ndt_map.AttachMapNodePool(&ndt_map_node_pool);
  ndt_map.SetMapFolderPath(map_base_folder);

  // Plane extractor
  apollo::localization::msf::FeatureXYPlane plane_extractor;

  for (unsigned int i = 0; i < pcd_folder_paths.size(); ++i) {
    const std::vector<Eigen::Affine3d>& pcd_poses_i = pcd_poses[i];
    for (unsigned int frame_idx = 0; frame_idx < pcd_poses_i.size();
         ++frame_idx) {
      apollo::localization::msf::velodyne::VelodyneFrame velodyne_frame;
      std::string pcd_file_path;
      std::ostringstream ss;
      ss << pcd_indices[i][frame_idx];
      pcd_file_path = pcd_folder_paths[i] + "/" + ss.str() + ".pcd";
      Eigen::Affine3d pcd_pose = pcd_poses_i[frame_idx];
      // Load pcd
      apollo::localization::msf::velodyne::LoadPcds(
          pcd_file_path, pcd_indices[i][frame_idx], pcd_pose, &velodyne_frame,
          false);

      std::cout << "Loaded " << velodyne_frame.pt3ds.size()
                << "3D Points at Trial: " << i
                << " Frame: " << pcd_indices[i][frame_idx] << "." << std::endl;

      // Process the point cloud
      for (size_t k = 0; k < velodyne_frame.pt3ds.size(); ++k) {
        Eigen::Vector3d& pt3d_local = velodyne_frame.pt3ds[k];
        unsigned char intensity = velodyne_frame.intensities[k];
        Eigen::Vector3d pt3d_global = velodyne_frame.pose * pt3d_local;

        for (size_t res = 0; res < ndt_map_config.map_resolutions_.size();
             ++res) {
          apollo::localization::msf::pyramid_map::MapNodeIndex index =
              apollo::localization::msf::pyramid_map::MapNodeIndex::
                  GetMapNodeIndex(ndt_map_config, pt3d_global,
                                  static_cast<unsigned int>(res), zone_id);

          apollo::localization::msf::pyramid_map::NdtMapNode* ndt_map_node =
              static_cast<apollo::localization::msf::pyramid_map::NdtMapNode*>(
                  ndt_map.GetMapNodeSafe(index));
          apollo::localization::msf::pyramid_map::NdtMapMatrix& ndt_map_matrix =
              static_cast<
                  apollo::localization::msf::pyramid_map::NdtMapMatrix&>(
                  ndt_map_node->GetMapCellMatrix());

          Eigen::Vector2d coord2d;
          coord2d[0] = pt3d_global[0];
          coord2d[1] = pt3d_global[1];
          unsigned int x = 0;
          unsigned int y = 0;
          ndt_map_node->GetCoordinate(coord2d, &x, &y);

          // get the centroid
          Eigen::Vector2d left_top_corner = ndt_map_node->GetLeftTopCorner();
          float resolution = ndt_map_node->GetMapResolution();
          Eigen::Vector3f centroid;
          centroid[0] = static_cast<float>(coord2d[0]) -
                        static_cast<float>(left_top_corner[0]) -
                        resolution * static_cast<float>(x);
          centroid[1] = static_cast<float>(coord2d[1]) -
                        static_cast<float>(left_top_corner[1]) -
                        resolution * static_cast<float>(y);
          apollo::localization::msf::pyramid_map::NdtMapCells& ndt_map_cell =
              ndt_map_matrix.GetMapCell(y, x);
          int altitude_index = ndt_map_cell.CalAltitudeIndex(
              ndt_map_config.map_resolutions_z_[res],
              static_cast<float>(pt3d_global[2]));
          centroid[2] = static_cast<float>(pt3d_global[2]) -
                        static_cast<float>(altitude_index) *
                            ndt_map_config.map_resolutions_z_[res];

          ndt_map_cell.AddSample(intensity, static_cast<float>(pt3d_global[2]),
                                 ndt_map_config.map_resolutions_z_[res],
                                 centroid, false);
          ndt_map_node->SetIsChanged(true);
        }
      }
    }
  }

  return 0;
}

 

發佈了41 篇原創文章 · 獲贊 4 · 訪問量 5423
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章