cartographer源码分析(31)-io-xray_points_processor.h
来源:互联网 发布:注册淘宝账号 编辑:程序博客网 时间:2024/06/05 05:46
源码可在https://github.com/learnmoreonce/SLAM 下载
文件:xray_points_processor.h#ifndef CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_#define CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_#include <map>#include "Eigen/Core"#include "cartographer/common/lua_parameter_dictionary.h"#include "cartographer/io/file_writer.h"#include "cartographer/io/points_processor.h"#include "cartographer/mapping/detect_floors.h"#include "cartographer/mapping/proto/trajectory.pb.h"#include "cartographer/mapping_3d/hybrid_grid.h"#include "cartographer/transform/rigid_transform.h"/*配置文件概览:VOXEL_SIZE = 5e-2YZ_TRANSFORM = { translation = { 0., 0., 0. }, rotation = { 0. , 0., math.pi, },}{ action = "write_xray_image", voxel_size = VOXEL_SIZE, filename = "xray_yz_all_intensity", transform = YZ_TRANSFORM,},*/namespace cartographer {namespace io {/*xray_points_processor.h是PointsProcessor的第三个子类(3).功能:将x射线以体素为voxel_size写入image。数据成员:1), 2), */// Creates X-ray cuts through the points with pixels being 'voxel_size' big.class XRayPointsProcessor : public PointsProcessor { public: constexpr static const char* kConfigurationFileActionName = "write_xray_image"; XRayPointsProcessor(double voxel_size, const transform::Rigid3f& transform, const std::vector<mapping::Floor>& floors, const string& output_filename, FileWriterFactory file_writer_factory, PointsProcessor* next); static std::unique_ptr<XRayPointsProcessor> FromDictionary( const mapping::proto::Trajectory& trajectory, FileWriterFactory file_writer_factory, common::LuaParameterDictionary* dictionary, PointsProcessor* next); ~XRayPointsProcessor() override {}//将点云写入.png文件,然后流水到下一处理器 void Process(std::unique_ptr<PointsBatch> batch) override; FlushResult Flush() override; Eigen::AlignedBox3i bounding_box() const { return bounding_box_; } private: struct ColumnData { double sum_r = 0.; double sum_g = 0.; double sum_b = 0.; uint32_t count = 0; }; struct Aggregation { mapping_3d::HybridGridBase<bool> voxels; std::map<std::pair<int, int>, ColumnData> column_data; }; void WriteVoxels(const Aggregation& aggregation, FileWriter* const file_writer); void Insert(const PointsBatch& batch, const transform::Rigid3f& transform, Aggregation* aggregation); PointsProcessor* const next_; FileWriterFactory file_writer_factory_; //负责文件写入的工厂 // If empty, we do not separate into floors. std::vector<mapping::Floor> floors_; //楼层 const string output_filename_; //文件名称 const transform::Rigid3f transform_; //点云涉及的变换 // Only has one entry if we do not separate into floors. std::vector<Aggregation> aggregations_; //聚集数据 // Bounding box containing all cells with data in all 'aggregations_'. Eigen::AlignedBox3i bounding_box_; //边界框};} // namespace io} // namespace cartographer#endif // CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_
xray_points_processor.cc#include "cartographer/io/xray_points_processor.h"#include <cmath>#include <string>#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/detect_floors.h"#include "cartographer/mapping_3d/hybrid_grid.h"namespace cartographer {namespace io {namespace {struct PixelData { size_t num_occupied_cells_in_column = 0; double mean_r = 0.; double mean_g = 0.; double mean_b = 0.;};using PixelDataMatrix = Eigen::Matrix<PixelData, Eigen::Dynamic, Eigen::Dynamic>;double Mix(const double a, const double b, const double t) { return a * (1. - t) + t * b;}//cairo回调函数,将data写入FileWritercairo_status_t CairoWriteCallback(void* const closure, const unsigned char* data, const unsigned int length) { if (static_cast<FileWriter*>(closure)->Write( reinterpret_cast<const char*>(data), length)) { return CAIRO_STATUS_SUCCESS; } return CAIRO_STATUS_WRITE_ERROR;}/*使用cairo库将mat以png文件写入filename*/// Write 'mat' as a pleasing-to-look-at PNG into 'filename'void WritePng(const PixelDataMatrix& mat, FileWriter* const file_writer) { const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, mat.cols()); CHECK_EQ(stride % 4, 0); std::vector<uint32_t> pixels(stride / 4 * mat.rows(), 0.); float max = std::numeric_limits<float>::min(); for (int y = 0; y < mat.rows(); ++y) { for (int x = 0; x < mat.cols(); ++x) { const PixelData& cell = mat(y, x); if (cell.num_occupied_cells_in_column == 0.) { continue; } max = std::max<float>(max, std::log(cell.num_occupied_cells_in_column)); } } for (int y = 0; y < mat.rows(); ++y) { for (int x = 0; x < mat.cols(); ++x) { const PixelData& cell = mat(y, x); if (cell.num_occupied_cells_in_column == 0.) { pixels[y * stride / 4 + x] = (255 << 24) | (255 << 16) | (255 << 8) | 255; continue; } // We use a logarithmic weighting for how saturated a pixel will be. The // basic idea here was that walls (full height) are fully saturated, but // details like chairs and tables are still well visible. const float saturation = std::log(cell.num_occupied_cells_in_column) / max; double mean_r_in_column = (cell.mean_r / 255.); double mean_g_in_column = (cell.mean_g / 255.); double mean_b_in_column = (cell.mean_b / 255.); double mix_r = Mix(1., mean_r_in_column, saturation); double mix_g = Mix(1., mean_g_in_column, saturation); double mix_b = Mix(1., mean_b_in_column, saturation); const int r = common::RoundToInt(mix_r * 255.); const int g = common::RoundToInt(mix_g * 255.); const int b = common::RoundToInt(mix_b * 255.); pixels[y * stride / 4 + x] = (255 << 24) | (r << 16) | (g << 8) | b; } } // TODO(hrapp): cairo_image_surface_create_for_data does not take ownership of // the data until the surface is finalized. Once it is finalized though, // cairo_surface_write_to_png fails, complaining that the surface is already // finalized. This makes it pretty hard to pass back ownership of the image to // the caller. cairo::UniqueSurfacePtr surface( cairo_image_surface_create_for_data( reinterpret_cast<unsigned char*>(pixels.data()), CAIRO_FORMAT_ARGB32, mat.cols(), mat.rows(), stride), cairo_surface_destroy); CHECK_EQ(cairo_surface_status(surface.get()), CAIRO_STATUS_SUCCESS); CHECK_EQ(cairo_surface_write_to_png_stream(surface.get(), &CairoWriteCallback, file_writer), CAIRO_STATUS_SUCCESS); CHECK(file_writer->Close());}bool ContainedIn(const common::Time& time, const std::vector<mapping::Timespan>& timespans) { for (const mapping::Timespan& timespan : timespans) { if (timespan.start <= time && time <= timespan.end) { return true; } } return false;}} // namespaceXRayPointsProcessor::XRayPointsProcessor( const double voxel_size, const transform::Rigid3f& transform, const std::vector<mapping::Floor>& floors, const string& output_filename, FileWriterFactory file_writer_factory, PointsProcessor* const next) : next_(next), file_writer_factory_(file_writer_factory), floors_(floors), output_filename_(output_filename), transform_(transform) { for (size_t i = 0; i < (floors_.empty() ? 1 : floors.size()); ++i) { aggregations_.emplace_back( Aggregation{mapping_3d::HybridGridBase<bool>(voxel_size), {}}); }}std::unique_ptr<XRayPointsProcessor> XRayPointsProcessor::FromDictionary( const mapping::proto::Trajectory& trajectory, FileWriterFactory file_writer_factory, common::LuaParameterDictionary* const dictionary, PointsProcessor* const next) { std::vector<mapping::Floor> floors; if (dictionary->HasKey("separate_floors") && dictionary->GetBool("separate_floors")) { floors = mapping::DetectFloors(trajectory); } return common::make_unique<XRayPointsProcessor>( dictionary->GetDouble("voxel_size"), transform::FromDictionary(dictionary->GetDictionary("transform").get()) .cast<float>(), floors, dictionary->GetString("filename"), file_writer_factory, next);}void XRayPointsProcessor::WriteVoxels(const Aggregation& aggregation, FileWriter* const file_writer) { if (bounding_box_.isEmpty()) { LOG(WARNING) << "Not writing output: bounding box is empty."; return; } // Returns the (x, y) pixel of the given 'index'. const auto voxel_index_to_pixel = [this](const Eigen::Array3i& index) { // We flip the y axis, since matrices rows are counted from the top. return Eigen::Array2i(bounding_box_.max()[1] - index[1], bounding_box_.max()[2] - index[2]); }; // Hybrid grid uses X: forward, Y: left, Z: up. // For the screen we are using. X: right, Y: up const int xsize = bounding_box_.sizes()[1] + 1; const int ysize = bounding_box_.sizes()[2] + 1; PixelDataMatrix image = PixelDataMatrix(ysize, xsize); for (mapping_3d::HybridGridBase<bool>::Iterator it(aggregation.voxels); !it.Done(); it.Next()) { const Eigen::Array3i cell_index = it.GetCellIndex(); const Eigen::Array2i pixel = voxel_index_to_pixel(cell_index); PixelData& pixel_data = image(pixel.y(), pixel.x()); const auto& column_data = aggregation.column_data.at( std::make_pair(cell_index[1], cell_index[2])); pixel_data.mean_r = column_data.sum_r / column_data.count; pixel_data.mean_g = column_data.sum_g / column_data.count; pixel_data.mean_b = column_data.sum_b / column_data.count; ++pixel_data.num_occupied_cells_in_column; } WritePng(image, file_writer);}void XRayPointsProcessor::Insert(const PointsBatch& batch, const transform::Rigid3f& transform, Aggregation* const aggregation) { constexpr Color kDefaultColor = {{0, 0, 0}}; for (size_t i = 0; i < batch.points.size(); ++i) { const Eigen::Vector3f camera_point = transform * batch.points[i]; const Eigen::Array3i cell_index = aggregation->voxels.GetCellIndex(camera_point); *aggregation->voxels.mutable_value(cell_index) = true; bounding_box_.extend(cell_index.matrix()); ColumnData& column_data = aggregation->column_data[std::make_pair(cell_index[1], cell_index[2])]; const auto& color = batch.colors.empty() ? kDefaultColor : batch.colors.at(i); column_data.sum_r += color[0]; column_data.sum_g += color[1]; column_data.sum_b += color[2]; ++column_data.count; }}void XRayPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) { if (floors_.empty()) { CHECK_EQ(aggregations_.size(), 1); Insert(*batch, transform_, &aggregations_[0]); } else { for (size_t i = 0; i < floors_.size(); ++i) { if (!ContainedIn(batch->time, floors_[i].timespans)) { continue; } Insert(*batch, transform_, &aggregations_[i]); } } next_->Process(std::move(batch));}PointsProcessor::FlushResult XRayPointsProcessor::Flush() { if (floors_.empty()) { CHECK_EQ(aggregations_.size(), 1); WriteVoxels(aggregations_[0], file_writer_factory_(output_filename_ + ".png").get()); } else { for (size_t i = 0; i < floors_.size(); ++i) { WriteVoxels( aggregations_[i], file_writer_factory_(output_filename_ + std::to_string(i) + ".png") .get()); } } switch (next_->Flush()) { case FlushResult::kRestartStream: LOG(FATAL) << "X-Ray generation must be configured to occur after any " "stages that require multiple passes."; case FlushResult::kFinished: return FlushResult::kFinished; } LOG(FATAL);}} // namespace io} // namespace cartographer
本文发于:
* http://www.jianshu.com/u/9e38d2febec1
* https://zhuanlan.zhihu.com/learnmoreonce
* http://blog.csdn.net/learnmoreonce
* slam源码分析微信公众号:slamcode
阅读全文
0 0
- cartographer源码分析(31)-io-xray_points_processor.h
- cartographer源码分析(26)-io-file_writer.h
- cartographer源码分析(27)-io-points_batch.h
- cartographer源码分析(28)-io-points_processor.h
- cartographer源码分析(29)-io-min_max_range_filtering_points_processor.h
- cartographer源码分析(30)-io-counting_points_processor.h
- cartographer源码分析(32)-io-intensity_to_color_points_processor.h
- cartographer源码分析(33)-io-ply_writing_points_processor.h
- cartographer源码分析(34)-io-coloring_points_processor.h
- cartographer源码分析(35)-io-fixed_ratio_sampling_points_processor.h
- cartographer源码分析(36)-io- outlier_removing_points_processor.h
- cartographer源码分析(37)-io-pcd_writing_points_processor.h
- cartographer源码分析(38)-io-null_points_processor.h
- cartographer源码分析(3)-common-port.h
- cartographer源码分析(4)-common-time.h
- cartographer源码分析(5)-common-rate_time.h
- cartographer源码分析(6)-common-histogram.h
- cartographer源码分析(7)-common-math.h
- Lucas–Kanade光流算法
- C++Windows下CONTAINING_RECORD宏的用法和详解
- int数组里的元素查重问题
- Vue项目启动问题
- cartographer源码分析(30)-io-counting_points_processor.h
- cartographer源码分析(31)-io-xray_points_processor.h
- JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解
- 系统日志
- cartographer源码分析(32)-io-intensity_to_color_points_processor.h
- hbase源码编译、配置安装、测试
- cartographer源码分析(33)-io-ply_writing_points_processor.h
- python ‘str’ does not support the buffer interface解决办法
- cartographer源码分析(34)-io-coloring_points_processor.h
- Android简单计算器实现