Re-implement VoxelFilter with unordered_set (#938)
Use hashing to filter voxels. Handles arbitrary grid coordinates up to sizeof(int). FIXES=#937master
parent
32b8bd3581
commit
363a337e67
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue