serialization_format_migration.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright 2018 The Cartographer Authors
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "cartographer/io/serialization_format_migration.h"
00018 
00019 #include <vector>
00020 
00021 #include "absl/container/flat_hash_map.h"
00022 #include "cartographer/mapping/3d/submap_3d.h"
00023 #include "cartographer/mapping/internal/3d/scan_matching/rotational_scan_matcher.h"
00024 #include "cartographer/mapping/probability_values.h"
00025 #include "cartographer/mapping/proto/internal/legacy_serialized_data.pb.h"
00026 #include "cartographer/mapping/proto/internal/legacy_submap.pb.h"
00027 #include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
00028 #include "glog/logging.h"
00029 
00030 namespace cartographer {
00031 namespace io {
00032 namespace {
00033 
00034 using mapping::proto::SerializedData;
00035 using ProtoMap = absl::flat_hash_map<int, std::vector<SerializedData>>;
00036 
00037 bool ReadPoseGraph(cartographer::io::ProtoStreamReaderInterface* const input,
00038                    ProtoMap* proto_map) {
00039   auto& pose_graph_vec = (*proto_map)[SerializedData::kPoseGraph];
00040   pose_graph_vec.emplace_back();
00041   return input->ReadProto(pose_graph_vec.back().mutable_pose_graph());
00042 }
00043 
00044 bool ReadBuilderOptions(
00045     cartographer::io::ProtoStreamReaderInterface* const input,
00046     ProtoMap* proto_map) {
00047   auto& options_vec =
00048       (*proto_map)[SerializedData::kAllTrajectoryBuilderOptions];
00049   options_vec.emplace_back();
00050   return input->ReadProto(
00051       options_vec.back().mutable_all_trajectory_builder_options());
00052 }
00053 
00054 mapping::proto::Submap MigrateLegacySubmap2d(
00055     const mapping::proto::LegacySubmap& submap_in) {
00056   mapping::proto::Submap2D submap_2d;
00057 
00058   // Convert probability grid to generalized grid.
00059   *submap_2d.mutable_grid()->mutable_limits() =
00060       submap_in.submap_2d().probability_grid().limits();
00061   *submap_2d.mutable_grid()->mutable_cells() =
00062       submap_in.submap_2d().probability_grid().cells();
00063   for (auto& cell : *submap_2d.mutable_grid()->mutable_cells()) {
00064     cell = -1 * cell;
00065   }
00066   // CellBox can't be trivially copied because the protobuf
00067   // serialization field number doesn't match.
00068   submap_2d.mutable_grid()->mutable_known_cells_box()->set_max_x(
00069       submap_in.submap_2d().probability_grid().known_cells_box().max_x());
00070   submap_2d.mutable_grid()->mutable_known_cells_box()->set_max_y(
00071       submap_in.submap_2d().probability_grid().known_cells_box().max_y());
00072   submap_2d.mutable_grid()->mutable_known_cells_box()->set_min_x(
00073       submap_in.submap_2d().probability_grid().known_cells_box().min_x());
00074   submap_2d.mutable_grid()->mutable_known_cells_box()->set_min_y(
00075       submap_in.submap_2d().probability_grid().known_cells_box().min_y());
00076 
00077   // Correspondence costs can be safely set to standard values.
00078   // Otherwise, this would be done during the next deserialization, but with a
00079   // warning, which we can avoid by setting it already here.
00080   submap_2d.mutable_grid()->set_max_correspondence_cost(
00081       mapping::kMaxCorrespondenceCost);
00082   submap_2d.mutable_grid()->set_min_correspondence_cost(
00083       mapping::kMinCorrespondenceCost);
00084   submap_2d.mutable_grid()->mutable_probability_grid_2d();
00085   *submap_2d.mutable_local_pose() = submap_in.submap_2d().local_pose();
00086   submap_2d.set_num_range_data(submap_in.submap_2d().num_range_data());
00087   submap_2d.set_finished(submap_in.submap_2d().finished());
00088 
00089   mapping::proto::Submap submap_out;
00090   *submap_out.mutable_submap_2d() = submap_2d;
00091   *submap_out.mutable_submap_id() = submap_in.submap_id();
00092   return submap_out;
00093 }
00094 
00095 mapping::proto::Submap MigrateLegacySubmap3d(
00096     const mapping::proto::LegacySubmap& submap_in) {
00097   mapping::proto::Submap3D submap_3d;
00098   *submap_3d.mutable_local_pose() = submap_in.submap_3d().local_pose();
00099   submap_3d.set_num_range_data(submap_in.submap_3d().num_range_data());
00100   submap_3d.set_finished(submap_in.submap_3d().finished());
00101   *submap_3d.mutable_high_resolution_hybrid_grid() =
00102       submap_in.submap_3d().high_resolution_hybrid_grid();
00103   *submap_3d.mutable_low_resolution_hybrid_grid() =
00104       submap_in.submap_3d().low_resolution_hybrid_grid();
00105 
00106   mapping::proto::Submap submap_out;
00107   *submap_out.mutable_submap_3d() = submap_3d;
00108   *submap_out.mutable_submap_id() = submap_in.submap_id();
00109   return submap_out;
00110 }
00111 
00112 bool DeserializeNext(cartographer::io::ProtoStreamReaderInterface* const input,
00113                      ProtoMap* proto_map) {
00114   mapping::proto::LegacySerializedData legacy_data;
00115   if (!input->ReadProto(&legacy_data)) return false;
00116 
00117   if (legacy_data.has_submap()) {
00118     LOG_FIRST_N(INFO, 1) << "Migrating submap data.";
00119     if (legacy_data.submap().has_submap_2d()) {
00120       CHECK(legacy_data.submap().submap_2d().grid().has_probability_grid_2d() ||
00121             legacy_data.submap().submap_2d().grid().has_tsdf_2d())
00122           << "\nThe legacy data contains a 2D submap, but it's not using the "
00123              "expected grid format. Try to migrate the grid format instead.";
00124     }
00125     auto& output_vector = (*proto_map)[SerializedData::kSubmapFieldNumber];
00126     output_vector.emplace_back();
00127     *output_vector.back().mutable_submap() = legacy_data.submap();
00128   }
00129   if (legacy_data.has_node()) {
00130     LOG_FIRST_N(INFO, 1) << "Migrating node data.";
00131     auto& output_vector = (*proto_map)[SerializedData::kNodeFieldNumber];
00132     output_vector.emplace_back();
00133     *output_vector.back().mutable_node() = legacy_data.node();
00134   }
00135   if (legacy_data.has_trajectory_data()) {
00136     LOG_FIRST_N(INFO, 1) << "Migrating trajectory data.";
00137     auto& output_vector =
00138         (*proto_map)[SerializedData::kTrajectoryDataFieldNumber];
00139     output_vector.emplace_back();
00140     *output_vector.back().mutable_trajectory_data() =
00141         legacy_data.trajectory_data();
00142   }
00143   if (legacy_data.has_imu_data()) {
00144     LOG_FIRST_N(INFO, 1) << "Migrating IMU data.";
00145     auto& output_vector = (*proto_map)[SerializedData::kImuDataFieldNumber];
00146     output_vector.emplace_back();
00147     *output_vector.back().mutable_imu_data() = legacy_data.imu_data();
00148   }
00149   if (legacy_data.has_odometry_data()) {
00150     LOG_FIRST_N(INFO, 1) << "Migrating odometry data.";
00151     auto& output_vector = (*proto_map)[SerializedData::kOdometryData];
00152     output_vector.emplace_back();
00153     *output_vector.back().mutable_odometry_data() = legacy_data.odometry_data();
00154   }
00155   if (legacy_data.has_fixed_frame_pose_data()) {
00156     LOG_FIRST_N(INFO, 1) << "Migrating fixed frame pose data.";
00157     auto& output_vector =
00158         (*proto_map)[SerializedData::kFixedFramePoseDataFieldNumber];
00159     output_vector.emplace_back();
00160     *output_vector.back().mutable_fixed_frame_pose_data() =
00161         legacy_data.fixed_frame_pose_data();
00162   }
00163   if (legacy_data.has_landmark_data()) {
00164     LOG_FIRST_N(INFO, 1) << "Migrating landmark data.";
00165     auto& output_vector =
00166         (*proto_map)[SerializedData::kLandmarkDataFieldNumber];
00167     output_vector.emplace_back();
00168     *output_vector.back().mutable_landmark_data() = legacy_data.landmark_data();
00169   }
00170   return true;
00171 }
00172 
00173 bool DeserializeNextAndMigrateGridFormat(
00174     cartographer::io::ProtoStreamReaderInterface* const input,
00175     ProtoMap* proto_map) {
00176   mapping::proto::LegacySerializedDataLegacySubmap legacy_data;
00177   if (!input->ReadProto(&legacy_data)) return false;
00178 
00179   if (legacy_data.has_submap()) {
00180     LOG_FIRST_N(INFO, 1) << "Migrating submap data.";
00181     auto& output_vector = (*proto_map)[SerializedData::kSubmapFieldNumber];
00182     output_vector.emplace_back();
00183     if (legacy_data.submap().has_submap_2d()) {
00184       CHECK(legacy_data.submap().submap_2d().has_probability_grid())
00185           << "\nThe legacy data contains a 2D submap, but it has no legacy "
00186              "probability grid that can be migrated to the new grid format.";
00187       *output_vector.back().mutable_submap() =
00188           MigrateLegacySubmap2d(legacy_data.submap());
00189     } else {
00190       *output_vector.back().mutable_submap() =
00191           MigrateLegacySubmap3d(legacy_data.submap());
00192     }
00193   }
00194   if (legacy_data.has_node()) {
00195     LOG_FIRST_N(INFO, 1) << "Migrating node data.";
00196     auto& output_vector = (*proto_map)[SerializedData::kNodeFieldNumber];
00197     output_vector.emplace_back();
00198     *output_vector.back().mutable_node() = legacy_data.node();
00199   }
00200   if (legacy_data.has_trajectory_data()) {
00201     LOG_FIRST_N(INFO, 1) << "Migrating trajectory data.";
00202     auto& output_vector =
00203         (*proto_map)[SerializedData::kTrajectoryDataFieldNumber];
00204     output_vector.emplace_back();
00205     *output_vector.back().mutable_trajectory_data() =
00206         legacy_data.trajectory_data();
00207   }
00208   if (legacy_data.has_imu_data()) {
00209     LOG_FIRST_N(INFO, 1) << "Migrating IMU data.";
00210     auto& output_vector = (*proto_map)[SerializedData::kImuDataFieldNumber];
00211     output_vector.emplace_back();
00212     *output_vector.back().mutable_imu_data() = legacy_data.imu_data();
00213   }
00214   if (legacy_data.has_odometry_data()) {
00215     LOG_FIRST_N(INFO, 1) << "Migrating odometry data.";
00216     auto& output_vector = (*proto_map)[SerializedData::kOdometryData];
00217     output_vector.emplace_back();
00218     *output_vector.back().mutable_odometry_data() = legacy_data.odometry_data();
00219   }
00220   if (legacy_data.has_fixed_frame_pose_data()) {
00221     LOG_FIRST_N(INFO, 1) << "Migrating fixed frame pose data.";
00222     auto& output_vector =
00223         (*proto_map)[SerializedData::kFixedFramePoseDataFieldNumber];
00224     output_vector.emplace_back();
00225     *output_vector.back().mutable_fixed_frame_pose_data() =
00226         legacy_data.fixed_frame_pose_data();
00227   }
00228   if (legacy_data.has_landmark_data()) {
00229     LOG_FIRST_N(INFO, 1) << "Migrating landmark data.";
00230     auto& output_vector =
00231         (*proto_map)[SerializedData::kLandmarkDataFieldNumber];
00232     output_vector.emplace_back();
00233     *output_vector.back().mutable_landmark_data() = legacy_data.landmark_data();
00234   }
00235   return true;
00236 }
00237 
00238 ProtoMap ParseLegacyData(
00239     cartographer::io::ProtoStreamReaderInterface* const input,
00240     bool migrate_grid_format) {
00241   ProtoMap proto_map;
00242   CHECK(ReadPoseGraph(input, &proto_map))
00243       << "Input stream seems to differ from original stream format. Could "
00244          "not "
00245          "read PoseGraph as first message.";
00246   CHECK(ReadBuilderOptions(input, &proto_map))
00247       << "Input stream seems to differ from original stream format. Could "
00248          "not "
00249          "read AllTrajectoryBuilderOptions as second message.";
00250   if (migrate_grid_format) {
00251     do {
00252     } while (DeserializeNextAndMigrateGridFormat(input, &proto_map));
00253   } else {
00254     do {
00255     } while (DeserializeNext(input, &proto_map));
00256   }
00257   return proto_map;
00258 }
00259 
00260 mapping::proto::SerializationHeader CreateSerializationHeader() {
00261   constexpr uint32_t kVersion1 = 1;
00262   mapping::proto::SerializationHeader header;
00263   header.set_format_version(kVersion1);
00264   return header;
00265 }
00266 
00267 void SerializeToVersion1Format(
00268     const ProtoMap& deserialized_data,
00269     cartographer::io::ProtoStreamWriterInterface* const output) {
00270   const std::vector<int> kFieldSerializationOrder = {
00271       SerializedData::kPoseGraphFieldNumber,
00272       SerializedData::kAllTrajectoryBuilderOptionsFieldNumber,
00273       SerializedData::kSubmapFieldNumber,
00274       SerializedData::kNodeFieldNumber,
00275       SerializedData::kTrajectoryDataFieldNumber,
00276       SerializedData::kImuDataFieldNumber,
00277       SerializedData::kOdometryDataFieldNumber,
00278       SerializedData::kFixedFramePoseDataFieldNumber,
00279       SerializedData::kLandmarkDataFieldNumber};
00280 
00281   LOG(INFO) << "Writing proto stream.";
00282   output->WriteProto(CreateSerializationHeader());
00283   for (auto field_index : kFieldSerializationOrder) {
00284     const auto proto_vector_it = deserialized_data.find(field_index);
00285     if (proto_vector_it == deserialized_data.end()) continue;
00286     for (const auto& proto : proto_vector_it->second) {
00287       output->WriteProto(proto);
00288     }
00289   }
00290 }
00291 }  // namespace
00292 
00293 void MigrateStreamFormatToVersion1(
00294     cartographer::io::ProtoStreamReaderInterface* const input,
00295     cartographer::io::ProtoStreamWriterInterface* const output,
00296     bool migrate_grid_format) {
00297   SerializeToVersion1Format(ParseLegacyData(input, migrate_grid_format),
00298                             output);
00299 }
00300 
00301 mapping::MapById<mapping::SubmapId, mapping::proto::Submap>
00302 MigrateSubmapFormatVersion1ToVersion2(
00303     const mapping::MapById<mapping::SubmapId, mapping::proto::Submap>&
00304         submap_id_to_submap,
00305     mapping::MapById<mapping::NodeId, mapping::proto::Node>& node_id_to_node,
00306     const mapping::proto::PoseGraph& pose_graph_proto) {
00307   using namespace mapping;
00308   if (submap_id_to_submap.empty() ||
00309       submap_id_to_submap.begin()->data.has_submap_2d()) {
00310     return submap_id_to_submap;
00311   }
00312 
00313   MapById<SubmapId, proto::Submap> migrated_submaps = submap_id_to_submap;
00314   for (const proto::PoseGraph::Constraint& constraint_proto :
00315        pose_graph_proto.constraint()) {
00316     if (constraint_proto.tag() == proto::PoseGraph::Constraint::INTRA_SUBMAP) {
00317       NodeId node_id{constraint_proto.node_id().trajectory_id(),
00318                      constraint_proto.node_id().node_index()};
00319       CHECK(node_id_to_node.Contains(node_id));
00320       const TrajectoryNode::Data node_data =
00321           FromProto(node_id_to_node.at(node_id).node_data());
00322       const Eigen::VectorXf& rotational_scan_matcher_histogram_in_gravity =
00323           node_data.rotational_scan_matcher_histogram;
00324 
00325       SubmapId submap_id{constraint_proto.submap_id().trajectory_id(),
00326                          constraint_proto.submap_id().submap_index()};
00327       CHECK(migrated_submaps.Contains(submap_id));
00328       proto::Submap& migrated_submap_proto = migrated_submaps.at(submap_id);
00329       CHECK(migrated_submap_proto.has_submap_3d());
00330 
00331       proto::Submap3D* submap_3d_proto =
00332           migrated_submap_proto.mutable_submap_3d();
00333       const double submap_yaw_from_gravity =
00334           transform::GetYaw(transform::ToRigid3(submap_3d_proto->local_pose())
00335                                 .inverse()
00336                                 .rotation() *
00337                             node_data.local_pose.rotation() *
00338                             node_data.gravity_alignment.inverse());
00339       const Eigen::VectorXf rotational_scan_matcher_histogram_in_submap =
00340           scan_matching::RotationalScanMatcher::RotateHistogram(
00341               rotational_scan_matcher_histogram_in_gravity,
00342               submap_yaw_from_gravity);
00343 
00344       if (submap_3d_proto->rotational_scan_matcher_histogram_size() == 0) {
00345         for (Eigen::VectorXf::Index i = 0;
00346              i != rotational_scan_matcher_histogram_in_submap.size(); ++i) {
00347           submap_3d_proto->add_rotational_scan_matcher_histogram(
00348               rotational_scan_matcher_histogram_in_submap(i));
00349         }
00350       } else {
00351         auto submap_histogram =
00352             submap_3d_proto->mutable_rotational_scan_matcher_histogram();
00353         for (Eigen::VectorXf::Index i = 0;
00354              i != rotational_scan_matcher_histogram_in_submap.size(); ++i) {
00355           *submap_histogram->Mutable(i) +=
00356               rotational_scan_matcher_histogram_in_submap(i);
00357         }
00358       }
00359     }
00360   }
00361   return migrated_submaps;
00362 }
00363 
00364 }  // namespace io
00365 }  // namespace cartographer


cartographer
Author(s): The Cartographer Authors
autogenerated on Thu May 9 2019 02:27:36