cartographer源码分析(18)-sensor-compressed_point_cloud
2017-07-27 19:39
369 查看
源码可在https://github.com/learnmoreonce/SLAM 下载
.
–
本文发于:
* http://www.jianshu.com/u/9e38d2febec1
* https://zhuanlan.zhihu.com/learnmoreonce
* http://blog.csdn.net/learnmoreonce
* slam源码分析微信公众号:slamcode
文件:sensor/compressed_point_cloud.h #ifndef CARTOGRAPHER_SENSOR_COMPRESSED_POINT_CLOUD_H_ #define CARTOGRAPHER_SENSOR_COMPRESSED_POINT_CLOUD_H_ #include <iterator> #include <vector> #include "Eigen/Core" #include "cartographer/common/port.h" #include "cartographer/sensor/point_cloud.h" #include "cartographer/sensor/proto/sensor.pb.h" namespace cartographer { namespace sensor { /* CompressedPointCloud是点云压缩类, 目的:压缩ponits以减少存储空间,压缩后有精度损失。 方法:按照block分组。 只有一个私有的 */ // A compressed representation of a point cloud consisting of a collection of // points (Vector3f). // Internally, points are grouped by blocks. Each block encodes a bit of meta // data (number of points in block, coordinates of the block) and encodes each // point with a fixed bit rate in relation to the block. class CompressedPointCloud { public: class ConstIterator; //前置声明 CompressedPointCloud() : num_points_(0) {} explicit CompressedPointCloud(const PointCloud& point_cloud); // Returns decompressed point cloud. PointCloud Decompress() const; bool empty() const; // num_points_==0 size_t size() const; // num_points_ ConstIterator begin() const; ConstIterator end() const; proto::CompressedPointCloud ToProto() const; private: CompressedPointCloud(const std::vector<int32>& point_data, size_t num_points); std::vector<int32> point_data_; size_t num_points_; }; /*前行迭代器*/ // Forward iterator for compressed point clouds. class CompressedPointCloud::ConstIterator : public std::iterator<std::forward_iterator_tag, Eigen::Vector3f> { public: // Creates begin iterator. explicit ConstIterator(const CompressedPointCloud* compressed_point_cloud); // Creates end iterator. static ConstIterator EndIterator( const CompressedPointCloud* compressed_point_cloud); Eigen::Vector3f operator*() const; ConstIterator& operator++(); bool operator!=(const ConstIterator& it) const; private: // Reads next point from buffer. Also handles reading the meta data of the // next block, if the current block is depleted. void ReadNextPoint(); const CompressedPointCloud* compressed_point_cloud_; size_t remaining_points_; int32 remaining_points_in_current_block_; Eigen::Vector3f current_point_; Eigen::Vector3i current_block_coordinates_; std::vector<int32>::const_iterator input_; }; } // namespace sensor } // namespace cartographer #endif // CARTOGRAPHER_SENSOR_COMPRESSED_POINT_CLOUD_H_
.
sensor/compressed_point_cloud.cc #include "cartographer/sensor/compressed_point_cloud.h" #include <limits> #include "cartographer/common/math.h" #include "cartographer/mapping_3d/hybrid_grid.h" namespace cartographer { namespace sensor { namespace { // Points are encoded on a fixed grid with a grid spacing of 'kPrecision' with // integers. Points are organized in blocks, where each point is encoded // relative to the block's origin in an int32 with 'kBitsPerCoordinate' bits per // coordinate. constexpr float kPrecision = 0.001f; // in meters. constexpr int kBitsPerCoordinate = 10; constexpr int kCoordinateMask = (1 << kBitsPerCoordinate) - 1; constexpr int kMaxBitsPerDirection = 23; } // namespace CompressedPointCloud::ConstIterator::ConstIterator( const CompressedPointCloud* compressed_point_cloud) : compressed_point_cloud_(compressed_point_cloud), remaining_points_(compressed_point_cloud->num_points_), remaining_points_in_current_block_(0), input_(compressed_point_cloud->point_data_.begin()) { if (remaining_points_ > 0) { ReadNextPoint(); } } CompressedPointCloud::ConstIterator CompressedPointCloud::ConstIterator::EndIterator( const CompressedPointCloud* compressed_point_cloud) { ConstIterator end_iterator(compressed_point_cloud); end_iterator.remaining_points_ = 0; return end_iterator; } Eigen::Vector3f CompressedPointCloud::ConstIterator::operator*() const { CHECK_GT(remaining_points_, 0); return current_point_; } CompressedPointCloud::ConstIterator& CompressedPointCloud::ConstIterator:: operator++() { --remaining_points_; if (remaining_points_ > 0) { ReadNextPoint(); } return *this; } bool CompressedPointCloud::ConstIterator::operator!=( const ConstIterator& it) const { CHECK(compressed_point_cloud_ == it.compressed_point_cloud_); return remaining_points_ != it.remaining_points_; } void CompressedPointCloud::ConstIterator::ReadNextPoint() { if (remaining_points_in_current_block_ == 0) { remaining_points_in_current_block_ = *input_++; for (int i = 0; i < 3; ++i) { current_block_coordinates_[i] = *input_++ << kBitsPerCoordinate; } } --remaining_points_in_current_block_; const int point = *input_++; constexpr int kMask = (1 << kBitsPerCoordinate) - 1; current_point_[0] = (current_block_coordinates_[0] + (point & kMask)) * kPrecision; current_point_[1] = (current_block_coordinates_[1] + ((point >> kBitsPerCoordinate) & kMask)) * kPrecision; current_point_[2] = (current_block_coordinates_[2] + (point >> (2 * kBitsPerCoordinate))) * kPrecision; } /* 最重要的构造函数 压缩点云 */ CompressedPointCloud::CompressedPointCloud(const PointCloud& point_cloud) //point_cloud是一个3f的vector,压缩到point_data_中储存 : num_points_(point_cloud.size()) { // Distribute points into blocks. struct RasterPoint { Eigen::Array3i point; // Array3i (int d1, int d2, int d3) int index; }; using Blocks = mapping_3d::HybridGridBase<std::vector<RasterPoint>>; Blocks blocks(kPrecision); int num_blocks = 0; CHECK_LE(point_cloud.size(), std::numeric_limits<int>::max()); for (int point_index = 0; point_index < static_cast<int>(point_cloud.size()); ++point_index) { const Eigen::Vector3f& point = point_cloud[point_index];//获取某个point{x,y,z} CHECK_LT(point.cwiseAbs().maxCoeff() / kPrecision, 1 << kMaxBitsPerDirection) << "Point out of bounds: " << point; Eigen::Array3i raster_point; Eigen::Array3i block_coordinate; for (int i = 0; i < 3; ++i) { raster_point[i] = common::RoundToInt(point[i] / kPrecision); block_coordinate[i] = raster_point[i] >> kBitsPerCoordinate; raster_point[i] &= kCoordinateMask; } auto* const block = blocks.mutable_value(block_coordinate); num_blocks += block->empty(); block->push_back({raster_point, point_index}); } //end for // Encode blocks. point_data_.reserve(4 * num_blocks + point_cloud.size()); for (Blocks::Iterator it(blocks); !it.Done(); it.Next(), --num_blocks) { const auto& raster_points = it.GetValue(); CHECK_LE(raster_points.size(), std::numeric_limits<int32>::max()); point_data_.push_back(raster_points.size()); const Eigen::Array3i block_coordinate = it.GetCellIndex(); point_data_.push_back(block_coordinate.x()); point_data_.push_back(block_coordinate.y()); point_data_.push_back(block_coordinate.z()); for (const RasterPoint& raster_point : raster_points) { point_data_.push_back((((raster_point.point.z() << kBitsPerCoordinate) + raster_point.point.y()) << kBitsPerCoordinate) + raster_point.point.x()); } } CHECK_EQ(num_blocks, 0); } /*私有的构造函数,外部不能调用*/ CompressedPointCloud::CompressedPointCloud(const std::vector<int32>& point_data, size_t num_points) : point_data_(point_data), num_points_(num_points) {} bool CompressedPointCloud::empty() const { return num_points_ == 0; } size_t CompressedPointCloud::size() const { return num_points_; } CompressedPointCloud::ConstIterator CompressedPointCloud::begin() const {//迭代器首, return ConstIterator(this); } CompressedPointCloud::ConstIterator CompressedPointCloud::end() const { //迭代器尾, return ConstIterator::EndIterator(this); } PointCloud CompressedPointCloud::Decompress() const { PointCloud decompressed; //Vector3f组成的vector for (const Eigen::Vector3f& point : *this) { //此处调用的是迭代器函数,begin(),end() decompressed.push_back(point); } return decompressed; } proto::CompressedPointCloud CompressedPointCloud::ToProto() const { proto::CompressedPointCloud result; result.set_num_points(num_points_); //序列化点云的个数 for (const int32 data : point_data_) { result.add_point_data(data); //依次序添加数据 } return result; } } // namespace sensor } // namespace cartographer
–
测试代码:sensor/compressed_point_cloud_test.cc #include "cartographer/sensor/compressed_point_cloud.h" #include "gmock/gmock.h" namespace Eigen { // Prints Vector3f in a readable format in matcher ApproximatelyEquals when // failing a test. Without this function, the output is formated as hexadecimal // 8 bit numbers. void PrintTo(const Vector3f& x, std::ostream* os) { *os << "(" << x[0] << ", " << x[1] << ", " << x[2] << ")"; } } // namespace Eigen namespace cartographer { namespace sensor { namespace { using ::testing::Contains; using ::testing::FloatNear; using ::testing::PrintToString; constexpr float kPrecision = 0.001f; // Matcher for 3-d vectors w.r.t. to the target precision. MATCHER_P(ApproximatelyEquals, expected, string("is equal to ") + PrintToString(expected)) { return (arg - expected).isZero(kPrecision);//压缩后有精度丢失,精确度为0.001 } // Helper function to test the mapping of a single point. Includes test for // recompressing the same point again. void TestPoint(const Eigen::Vector3f& p) { CompressedPointCloud compressed({p}); EXPECT_EQ(1, compressed.size()); EXPECT_THAT(*compressed.begin(), ApproximatelyEquals(p)); CompressedPointCloud recompressed({*compressed.begin()}); EXPECT_THAT(*recompressed.begin(), ApproximatelyEquals(p)); } TEST(CompressPointCloudTest, CompressesPointsCorrectly) { TestPoint(Eigen::Vector3f(8000.f, 7500.f, 5000.f)); TestPoint(Eigen::Vector3f(1000.f, 2000.f, 3000.f)); TestPoint(Eigen::Vector3f(100.f, 200.f, 300.f)); TestPoint(Eigen::Vector3f(10.f, 20.f, 30.f)); TestPoint(Eigen::Vector3f(-0.00049f, -0.0005f, -0.0015f)); TestPoint(Eigen::Vector3f(0.05119f, 0.0512f, 0.05121)); TestPoint(Eigen::Vector3f(-0.05119f, -0.0512f, -0.05121)); TestPoint(Eigen::Vector3f(0.8405f, 0.84f, 0.8396f)); TestPoint(Eigen::Vector3f(0.8395f, 0.8394f, 0.8393f)); TestPoint(Eigen::Vector3f(0.839f, 0.8391f, 0.8392f)); TestPoint(Eigen::Vector3f(0.8389f, 0.8388f, 0.83985f)); } TEST(CompressPointCloudTest, Compresses) { const CompressedPointCloud compressed({Eigen::Vector3f(0.838f, 0, 0), Eigen::Vector3f(0.839f, 0, 0), Eigen::Vector3f(0.840f, 0, 0)}); EXPECT_FALSE(compressed.empty()); EXPECT_EQ(3, compressed.size()); const PointCloud decompressed = compressed.Decompress(); EXPECT_EQ(3, decompressed.size()); EXPECT_THAT(decompressed, Contains(ApproximatelyEquals(Eigen::Vector3f(0.838f, 0, 0))));//压缩解压缩后,前3位小数不变 EXPECT_THAT(decompressed, Contains(ApproximatelyEquals(Eigen::Vector3f(0.839f, 0, 0)))); EXPECT_THAT(decompressed, Contains(ApproximatelyEquals(Eigen::Vector3f(0.840f, 0, 0)))); } TEST(CompressPointCloudTest, CompressesEmptyPointCloud) { CompressedPointCloud compressed; EXPECT_TRUE(compressed.empty()); EXPECT_EQ(0, compressed.size()); } // Test for gaps. // Produces a series of points densly packed along the x axis, compresses these // points (twice), and tests, whether there are gaps between two consecutive // points. TEST(CompressPointCloudTest, CompressesNoGaps) { PointCloud point_cloud; for (int i = 0; i < 3000; ++i) { point_cloud.push_back(Eigen::Vector3f(kPrecision * i - 1.5f, 0, 0)); } const CompressedPointCloud compressed(point_cloud);//压缩 const PointCloud decompressed = compressed.Decompress();//解压缩 const CompressedPointCloud recompressed(decompressed);//再压缩 EXPECT_EQ(decompressed.size(), recompressed.size()); std::vector<float> x_coord; for (const auto& p : compressed) { x_coord.push_back(p[0]); } std::sort(x_coord.begin(), x_coord.end()); for (size_t i = 1; i < x_coord.size(); ++i) { EXPECT_THAT(std::abs(x_coord[i] - x_coord[i - 1]), FloatNear(kPrecision, 1e-7f)); //前后相差不大 } } } // namespace } // namespace sensor } // namespace cartographer
本文发于:
* http://www.jianshu.com/u/9e38d2febec1
* https://zhuanlan.zhihu.com/learnmoreonce
* http://blog.csdn.net/learnmoreonce
* slam源码分析微信公众号:slamcode
相关文章推荐
- cartographer源码分析(17)-sensor-point_cloud.h
- cartographer源码分析(22)-sensor-collator.h
- cartographer源码分析(23)-sensor-voxel_filter.h
- cartographer源码分析(24)-sensor-configuration.h
- [置顶] 25-总结-【cartographer源码分析】系列的第三部分【sensor源码分析】
- Ciclop开源3D扫描仪软件---Horus源码分析之point_cloud_generation.py
- Ciclop开源3D扫描仪软件---Horus源码分析之point_cloud_roi.py
- cartographer源码分析(19)-sensor-range_data.h
- cartographer源码分析(20)-sensor-data.h
- cartographer源码分析(21)-sensor-ordered_multi_queue.h
- springcloud 入门 5 (feign源码分析)
- cartographer源码分析(1)-缘起
- cartographer源码分析(5)-common-fixed_ratio_sampler.h
- cartographer源码分析(29)-io-min_max_range_filtering_points_processor.h
- cartographer源码分析(36)-io- outlier_removing_points_processor.h
- cartographer源码分析(53)-mapping-trajectory_connectivity.h
- NGUI 源码分析- AnchorPoint
- cartographer源码分析(2)- 快速安装
- 【高可用】分布式作业系统 Elastic-Job-Cloud 源码分析
- MyBatis-3.4.2-源码分析18:XML解析之RoleMapper userMapper = sqlSession.getMapper(RoleMapper.class)