Re-implement VoxelFilter with unordered_set (#938)

Use hashing to filter voxels.
Handles arbitrary grid coordinates up to sizeof(int).

FIXES=#937
master
gaschler 2018-02-28 11:12:18 +01:00 committed by Wally B. Feed
parent 32b8bd3581
commit 363a337e67
3 changed files with 59 additions and 20 deletions

View File

@ -76,31 +76,43 @@ PointCloud AdaptivelyVoxelFiltered(
return result; return result;
} }
template <typename PointCloudType> } // namespace
PointCloudType FilterPointCloudUsingVoxels(
const PointCloudType& point_cloud, mapping::HybridGridBase<uint8>* voxels) { PointCloud VoxelFilter::Filter(const PointCloud& point_cloud) {
PointCloudType results; PointCloud results;
for (const typename PointCloudType::value_type& point : point_cloud) { for (const Eigen::Vector3f& point : point_cloud) {
auto* const value = auto it_inserted = voxel_set_.insert(IndexToKey(GetCellIndex(point)));
voxels->mutable_value(voxels->GetCellIndex(point.template head<3>())); if (it_inserted.second) {
if (*value == 0) {
results.push_back(point); results.push_back(point);
*value = 1;
} }
} }
return results; return results;
} }
} // namespace TimedPointCloud VoxelFilter::Filter(const TimedPointCloud& timed_point_cloud) {
TimedPointCloud results;
VoxelFilter::VoxelFilter(const float size) : voxels_(size) {} for (const Eigen::Vector4f& point : timed_point_cloud) {
auto it_inserted =
PointCloud VoxelFilter::Filter(const PointCloud& point_cloud) { voxel_set_.insert(IndexToKey(GetCellIndex(point.head<3>())));
return FilterPointCloudUsingVoxels(point_cloud, &voxels_); if (it_inserted.second) {
results.push_back(point);
}
}
return results;
} }
TimedPointCloud VoxelFilter::Filter(const TimedPointCloud& timed_point_cloud) { VoxelFilter::KeyType VoxelFilter::IndexToKey(const Eigen::Array3i& index) {
return FilterPointCloudUsingVoxels(timed_point_cloud, &voxels_); KeyType k_0(static_cast<uint32>(index[0]));
KeyType k_1(static_cast<uint32>(index[1]));
KeyType k_2(static_cast<uint32>(index[2]));
return (k_0 << 2 * 32) | (k_1 << 1 * 32) | k_2;
}
Eigen::Array3i VoxelFilter::GetCellIndex(const Eigen::Vector3f& point) const {
Eigen::Array3f index = point.array() / resolution_;
return Eigen::Array3i(common::RoundToInt(index.x()),
common::RoundToInt(index.y()),
common::RoundToInt(index.z()));
} }
proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions( proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions(

View File

@ -17,8 +17,10 @@
#ifndef CARTOGRAPHER_SENSOR_VOXEL_FILTER_H_ #ifndef CARTOGRAPHER_SENSOR_VOXEL_FILTER_H_
#define CARTOGRAPHER_SENSOR_VOXEL_FILTER_H_ #define CARTOGRAPHER_SENSOR_VOXEL_FILTER_H_
#include <bitset>
#include <unordered_set>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/mapping/3d/hybrid_grid.h"
#include "cartographer/sensor/point_cloud.h" #include "cartographer/sensor/point_cloud.h"
#include "cartographer/sensor/proto/adaptive_voxel_filter_options.pb.h" #include "cartographer/sensor/proto/adaptive_voxel_filter_options.pb.h"
@ -31,7 +33,7 @@ namespace sensor {
class VoxelFilter { class VoxelFilter {
public: public:
// 'size' is the length of a voxel edge. // 'size' is the length of a voxel edge.
explicit VoxelFilter(float size); explicit VoxelFilter(float size) : resolution_(size){};
VoxelFilter(const VoxelFilter&) = delete; VoxelFilter(const VoxelFilter&) = delete;
VoxelFilter& operator=(const VoxelFilter&) = delete; VoxelFilter& operator=(const VoxelFilter&) = delete;
@ -43,7 +45,14 @@ class VoxelFilter {
TimedPointCloud Filter(const TimedPointCloud& timed_point_cloud); TimedPointCloud Filter(const TimedPointCloud& timed_point_cloud);
private: private:
mapping::HybridGridBase<uint8> voxels_; using KeyType = std::bitset<3 * 32>;
static KeyType IndexToKey(const Eigen::Array3i& index);
Eigen::Array3i GetCellIndex(const Eigen::Vector3f& point) const;
float resolution_;
std::unordered_set<KeyType> voxel_set_;
}; };
proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions( proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions(

View File

@ -35,6 +35,24 @@ TEST(VoxelFilterTest, ReturnsTheFirstPointInEachVoxel) {
ContainerEq(PointCloud{point_cloud[0], point_cloud[2]})); ContainerEq(PointCloud{point_cloud[0], point_cloud[2]}));
} }
TEST(VoxelFilterTest, HandlesLargeCoordinates) {
PointCloud point_cloud = {{100000.f, 0.f, 0.f},
{100000.001f, -0.0001f, 0.0001f},
{100000.003f, -0.0001f, 0.f},
{-200000.f, 0.f, 0.f}};
EXPECT_THAT(VoxelFilter(0.01f).Filter(point_cloud),
ContainerEq(PointCloud{point_cloud[0], point_cloud[3]}));
}
TEST(VoxelFilterTest, IgnoresTime) {
TimedPointCloud timed_point_cloud;
for (int i = 0; i < 100; ++i) {
timed_point_cloud.emplace_back(-100.f, 0.3f, 0.4f, 1.f * i);
}
EXPECT_THAT(VoxelFilter(0.3f).Filter(timed_point_cloud),
ContainerEq(TimedPointCloud{timed_point_cloud[0]}));
}
} // namespace } // namespace
} // namespace sensor } // namespace sensor
} // namespace cartographer } // namespace cartographer