From 188dcb57e5e9beefbc26705056fdd50ba70a2f4f Mon Sep 17 00:00:00 2001 From: Holger Rapp Date: Tue, 25 Oct 2016 12:27:58 +0200 Subject: [PATCH] Adds a class that can build a points processing pipeline out of a Lua configuration. (#94) --- cartographer/io/CMakeLists.txt | 16 +++++ .../io/points_processor_pipeline_builder.cc | 65 +++++++++++++++++ .../io/points_processor_pipeline_builder.h | 70 +++++++++++++++++++ cartographer/io/xray_points_processor.cc | 11 +++ cartographer/io/xray_points_processor.h | 6 ++ .../io/xyz_writing_points_processor.cc | 9 +++ .../io/xyz_writing_points_processor.h | 7 ++ scripts/update_cmakelists.py | 4 +- 8 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 cartographer/io/points_processor_pipeline_builder.cc create mode 100644 cartographer/io/points_processor_pipeline_builder.h diff --git a/cartographer/io/CMakeLists.txt b/cartographer/io/CMakeLists.txt index 1c6c099..84dbab1 100644 --- a/cartographer/io/CMakeLists.txt +++ b/cartographer/io/CMakeLists.txt @@ -48,6 +48,18 @@ google_library(io_points_processor io_points_batch ) +google_library(io_points_processor_pipeline_builder + SRCS + points_processor_pipeline_builder.cc + HDRS + points_processor_pipeline_builder.h + DEPENDS + common_lua_parameter_dictionary + common_make_unique + io_null_points_processor + io_points_processor +) + google_library(io_xray_points_processor USES_CAIRO USES_EIGEN @@ -56,6 +68,8 @@ google_library(io_xray_points_processor HDRS xray_points_processor.h DEPENDS + common_lua_parameter_dictionary + common_make_unique common_math io_cairo_types io_points_processor @@ -70,6 +84,8 @@ google_library(io_xyz_writing_points_processor HDRS xyz_writing_points_processor.h DEPENDS + common_lua_parameter_dictionary + common_make_unique io_points_processor ) diff --git a/cartographer/io/points_processor_pipeline_builder.cc b/cartographer/io/points_processor_pipeline_builder.cc new file mode 100644 index 0000000..afebc1f --- /dev/null +++ b/cartographer/io/points_processor_pipeline_builder.cc @@ -0,0 +1,65 @@ +/* + * Copyright 2016 The Cartographer Authors + * + * 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 "cartographer/io/points_processor_pipeline_builder.h" + +#include "cartographer/common/make_unique.h" +#include "cartographer/io/null_points_processor.h" + +namespace cartographer { +namespace io { + +PointsProcessorPipelineBuilder::PointsProcessorPipelineBuilder() {} + +PointsProcessorPipelineBuilder* PointsProcessorPipelineBuilder::instance() { + static PointsProcessorPipelineBuilder instance; + return &instance; +} + +void PointsProcessorPipelineBuilder::RegisterType(const std::string& name, + FactoryFunction factory) { + CHECK(factories_.count(name) == 0) << "A points processor with named '" + << name + << "' has already been registered."; + factories_[name] = factory; +} + +std::vector> +PointsProcessorPipelineBuilder::CreatePipeline( + common::LuaParameterDictionary* const dictionary) const { + std::vector> pipeline; + // The last consumer in the pipeline must exist, so that the one created after + // it (and being before it in the pipeline) has a valid 'next' to point to. + // The last consumer will just drop all points. + pipeline.emplace_back(common::make_unique()); + + std::vector> configurations = + dictionary->GetArrayValuesAsDictionaries(); + + // We construct the pipeline starting at the back. + for (auto it = configurations.rbegin(); it != configurations.rend(); it++) { + const string action = (*it)->GetString("action"); + auto factory_it = factories_.find(action); + CHECK(factory_it != factories_.end()) + << "Unknown action '" << action + << "'. Did you register the correspoinding PointsProcessor?"; + pipeline.push_back(factory_it->second(it->get(), pipeline.back().get())); + } + return pipeline; +} + +} // namespace io +} // namespace cartographer diff --git a/cartographer/io/points_processor_pipeline_builder.h b/cartographer/io/points_processor_pipeline_builder.h new file mode 100644 index 0000000..0b3d7d1 --- /dev/null +++ b/cartographer/io/points_processor_pipeline_builder.h @@ -0,0 +1,70 @@ +/* + * Copyright 2016 The Cartographer Authors + * + * 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. + */ + +#ifndef CARTOGRAPHER_IO_POINTS_PROCESSOR_PIPELINE_BUILDER_H_ +#define CARTOGRAPHER_IO_POINTS_PROCESSOR_PIPELINE_BUILDER_H_ + +#include +#include +#include + +#include "cartographer/common/lua_parameter_dictionary.h" +#include "cartographer/io/points_processor.h" + +namespace cartographer { +namespace io { + +// Singleton that knows how to build a points processor pipeline out of a Lua +// configuration. You can register new classes with this instance that must +// define its name and a way to build itself out of a LuaParameterDictionary. +// See the various 'PointsProcessor's for examples. +class PointsProcessorPipelineBuilder { + public: + PointsProcessorPipelineBuilder(const PointsProcessorPipelineBuilder&) = + delete; + PointsProcessorPipelineBuilder& operator=( + const PointsProcessorPipelineBuilder&) = delete; + + static PointsProcessorPipelineBuilder* instance(); + + template + void Register() { + instance()->RegisterType( + PointsProcessorType::kConfigurationFileActionName, + [](common::LuaParameterDictionary* const dictionary, + PointsProcessor* const next) -> std::unique_ptr { + return PointsProcessorType::FromDictionary(dictionary, next); + }); + } + + std::vector> CreatePipeline( + common::LuaParameterDictionary* dictionary) const; + + private: + using FactoryFunction = std::function( + common::LuaParameterDictionary*, PointsProcessor* next)>; + + PointsProcessorPipelineBuilder(); + + void RegisterType(const std::string& name, FactoryFunction factory); + + std::unordered_map factories_; +}; + +} // namespace io +} // namespace cartographer + +#endif // CARTOGRAPHER_IO_POINTS_PROCESSOR_PIPELINE_BUILDER_H_ diff --git a/cartographer/io/xray_points_processor.cc b/cartographer/io/xray_points_processor.cc index 278307b..3834e63 100644 --- a/cartographer/io/xray_points_processor.cc +++ b/cartographer/io/xray_points_processor.cc @@ -21,6 +21,8 @@ #include "Eigen/Core" #include "cairo/cairo.h" +#include "cartographer/common/lua_parameter_dictionary.h" +#include "cartographer/common/make_unique.h" #include "cartographer/common/math.h" #include "cartographer/io/cairo_types.h" #include "cartographer/mapping_3d/hybrid_grid.h" @@ -83,6 +85,15 @@ XRayPointsProcessor::XRayPointsProcessor(const double voxel_size, transform_(transform), voxels_(voxel_size, Eigen::Vector3f::Zero()) {} +std::unique_ptr XRayPointsProcessor::FromDictionary( + common::LuaParameterDictionary* dictionary, PointsProcessor* next) { + return common::make_unique( + dictionary->GetDouble("voxel_size"), + transform::FromDictionary(dictionary->GetDictionary("transform").get()) + .cast(), + dictionary->GetString("filename"), next); +} + void XRayPointsProcessor::Process(std::unique_ptr batch) { for (const auto& point : batch->points) { const Eigen::Vector3f camera_point = transform_ * point; diff --git a/cartographer/io/xray_points_processor.h b/cartographer/io/xray_points_processor.h index a3cea96..0464e1f 100644 --- a/cartographer/io/xray_points_processor.h +++ b/cartographer/io/xray_points_processor.h @@ -17,6 +17,7 @@ #ifndef CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_ #define CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_ +#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/io/points_processor.h" #include "cartographer/mapping_3d/hybrid_grid.h" #include "cartographer/transform/rigid_transform.h" @@ -30,9 +31,14 @@ namespace io { // combined into a movie. class XRayPointsProcessor : public PointsProcessor { public: + constexpr static const char* kConfigurationFileActionName = + "write_xray_image"; XRayPointsProcessor(double voxel_size, const transform::Rigid3f& transform, const string& output_filename, PointsProcessor* next); + static std::unique_ptr FromDictionary( + common::LuaParameterDictionary* dictionary, PointsProcessor* next); + ~XRayPointsProcessor() override {} void Process(std::unique_ptr batch) override; diff --git a/cartographer/io/xyz_writing_points_processor.cc b/cartographer/io/xyz_writing_points_processor.cc index de321ea..6d197ed 100644 --- a/cartographer/io/xyz_writing_points_processor.cc +++ b/cartographer/io/xyz_writing_points_processor.cc @@ -2,6 +2,7 @@ #include +#include "cartographer/common/make_unique.h" #include "glog/logging.h" namespace cartographer { @@ -21,6 +22,14 @@ XyzWriterPointsProcessor::XyzWriterPointsProcessor(const string& filename, file_ << std::setprecision(6); } +std::unique_ptr +XyzWriterPointsProcessor::FromDictionary( + common::LuaParameterDictionary* const dictionary, + PointsProcessor* const next) { + return common::make_unique( + dictionary->GetString("filename"), next); +} + PointsProcessor::FlushResult XyzWriterPointsProcessor::Flush() { file_.close(); CHECK(file_) << "Writing XYZ file failed."; diff --git a/cartographer/io/xyz_writing_points_processor.h b/cartographer/io/xyz_writing_points_processor.h index 761e13d..5443d30 100644 --- a/cartographer/io/xyz_writing_points_processor.h +++ b/cartographer/io/xyz_writing_points_processor.h @@ -20,6 +20,7 @@ #include #include +#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/io/points_processor.h" namespace cartographer { @@ -28,7 +29,13 @@ namespace io { // Writes ASCII xyz points. class XyzWriterPointsProcessor : public PointsProcessor { public: + constexpr static const char* kConfigurationFileActionName = "write_xyz"; + XyzWriterPointsProcessor(const string& filename, PointsProcessor* next); + + static std::unique_ptr FromDictionary( + common::LuaParameterDictionary* dictionary, PointsProcessor* next); + ~XyzWriterPointsProcessor() override {} XyzWriterPointsProcessor(const XyzWriterPointsProcessor&) = delete; diff --git a/scripts/update_cmakelists.py b/scripts/update_cmakelists.py index 0c99ac4..6d5820c 100755 --- a/scripts/update_cmakelists.py +++ b/scripts/update_cmakelists.py @@ -231,8 +231,8 @@ def RunOnDirectory(root): for c in sorted(mains): # Binaries do not get their full subpath appended, but we prepend # 'cartographer' to distinguish them after installation. So, - # 'io/asset_writer_main.cc' will generate a binary called - # 'cartographer_asset_writer'. + # 'io/assets_writer_main.cc' will generate a binary called + # 'cartographer_assets_writer'. name = "cartographer_" + path.basename(path.splitext(c)[0][:-5]) AddTarget("google_binary", name, directory, [c], [])