Skip to content

Commit

Permalink
Take intensities into account in PointCloud transforms and filters. (#…
Browse files Browse the repository at this point in the history
…1763)

Adds a new method to sensor::PointCloud, copy_if, which copies all
points satisfying a provided condition, together with the associated
intensities (if they exist).

Adapts transforms/filters to use this new method.

Signed-off-by: Wolfgang Hess <whess@lyft.com>
  • Loading branch information
wohe committed Oct 16, 2020
1 parent 81d34ef commit 952f59d
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 22 deletions.
12 changes: 5 additions & 7 deletions cartographer/mapping/3d/submap_3d.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,14 @@ struct PixelData {
};

// Filters 'range_data', retaining only the returns that have no more than
// 'max_range' distance from the origin. Removes misses and reflectivity
// information.
// 'max_range' distance from the origin. Removes misses.
sensor::RangeData FilterRangeDataByMaxRange(const sensor::RangeData& range_data,
const float max_range) {
sensor::RangeData result{range_data.origin, {}, {}};
for (const sensor::RangefinderPoint& hit : range_data.returns) {
if ((hit.position - range_data.origin).norm() <= max_range) {
result.returns.push_back(hit);
}
}
result.returns =
range_data.returns.copy_if([&](const sensor::RangefinderPoint& point) {
return (point.position - range_data.origin).norm() <= max_range;
});
return result;
}

Expand Down
10 changes: 3 additions & 7 deletions cartographer/sensor/internal/voxel_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,9 @@ namespace {

PointCloud FilterByMaxRange(const PointCloud& point_cloud,
const float max_range) {
PointCloud result;
for (const RangefinderPoint& point : point_cloud) {
if (point.position.norm() <= max_range) {
result.push_back(point);
}
}
return result;
return point_cloud.copy_if([max_range](const RangefinderPoint& point) {
return point.position.norm() <= max_range;
});
}

PointCloud AdaptivelyVoxelFiltered(
Expand Down
12 changes: 4 additions & 8 deletions cartographer/sensor/point_cloud.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ PointCloud TransformPointCloud(const PointCloud& point_cloud,
for (const RangefinderPoint& point : point_cloud.points()) {
points.emplace_back(transform * point);
}
return PointCloud(points);
return PointCloud(points, point_cloud.intensities());
}

TimedPointCloud TransformTimedPointCloud(const TimedPointCloud& point_cloud,
Expand All @@ -75,13 +75,9 @@ TimedPointCloud TransformTimedPointCloud(const TimedPointCloud& point_cloud,

PointCloud CropPointCloud(const PointCloud& point_cloud, const float min_z,
const float max_z) {
PointCloud cropped_point_cloud;
for (const RangefinderPoint& point : point_cloud) {
if (min_z <= point.position.z() && point.position.z() <= max_z) {
cropped_point_cloud.push_back(point);
}
}
return cropped_point_cloud;
return point_cloud.copy_if([min_z, max_z](const RangefinderPoint& point) {
return min_z <= point.position.z() && point.position.z() <= max_z;
});
}

} // namespace sensor
Expand Down
29 changes: 29 additions & 0 deletions cartographer/sensor/point_cloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@ class PointCloud {

void push_back(PointType value);

// Creates a PointCloud consisting of all the points for which `predicate`
// returns true, together with the corresponding intensities.
template <class UnaryPredicate>
PointCloud copy_if(UnaryPredicate predicate) const {
std::vector<PointType> points;
std::vector<float> intensities;

// Note: benchmarks show that it is better to have this conditional outside
// the loop.
if (intensities_.empty()) {
for (size_t index = 0; index < size(); ++index) {
const PointType& point = points_[index];
if (predicate(point)) {
points.push_back(point);
}
}
} else {
for (size_t index = 0; index < size(); ++index) {
const PointType& point = points_[index];
if (predicate(point)) {
points.push_back(point);
intensities.push_back(intensities_[index]);
}
}
}

return PointCloud(points, intensities);
}

private:
// For 2D points, the third entry is 0.f.
std::vector<PointType> points_;
Expand Down
37 changes: 37 additions & 0 deletions cartographer/sensor/point_cloud_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@
#include <cmath>

#include "cartographer/transform/transform.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace cartographer {
namespace sensor {
namespace {

using ::testing::ElementsAre;
using ::testing::FloatNear;
using ::testing::IsEmpty;

TEST(PointCloudTest, TransformPointCloud) {
PointCloud point_cloud;
point_cloud.push_back({{Eigen::Vector3f{0.5f, 0.5f, 1.f}}});
Expand All @@ -49,6 +54,38 @@ TEST(PointCloudTest, TransformTimedPointCloud) {
EXPECT_NEAR(3.5f, transformed_point_cloud[1].position.y(), 1e-6);
}

TEST(PointCloudTest, CopyIf) {
std::vector<RangefinderPoint> points = {
{{0.f, 0.f, 0.f}}, {{1.f, 1.f, 1.f}}, {{2.f, 2.f, 2.f}}};

const PointCloud point_cloud(points);
const PointCloud copied_point_cloud = point_cloud.copy_if(
[&](const RangefinderPoint& point) { return point.position.x() > 0.1f; });

EXPECT_EQ(copied_point_cloud.size(), 2);
EXPECT_THAT(copied_point_cloud.intensities(), IsEmpty());
EXPECT_THAT(copied_point_cloud.points(),
ElementsAre(RangefinderPoint{Eigen::Vector3f{1.f, 1.f, 1.f}},
RangefinderPoint{Eigen::Vector3f{2.f, 2.f, 2.f}}));
}

TEST(PointCloudTest, CopyIfWithIntensities) {
std::vector<RangefinderPoint> points = {
{{0.f, 0.f, 0.f}}, {{1.f, 1.f, 1.f}}, {{2.f, 2.f, 2.f}}};
std::vector<float> intensities = {0.f, 1.f, 2.f};

const PointCloud point_cloud(points, intensities);
const PointCloud copied_point_cloud = point_cloud.copy_if(
[&](const RangefinderPoint& point) { return point.position.x() > 0.1f; });
EXPECT_EQ(copied_point_cloud.size(), 2);
EXPECT_EQ(copied_point_cloud.intensities().size(), 2);
EXPECT_THAT(copied_point_cloud.points(),
ElementsAre(RangefinderPoint{Eigen::Vector3f{1.f, 1.f, 1.f}},
RangefinderPoint{Eigen::Vector3f{2.f, 2.f, 2.f}}));
EXPECT_THAT(copied_point_cloud.intensities(),
ElementsAre(FloatNear(1.f, 1e-6), FloatNear(2.f, 1e-6)));
}

} // namespace
} // namespace sensor
} // namespace cartographer

0 comments on commit 952f59d

Please sign in to comment.