Skip to content

Commit cad3378

Browse files
authored
Add a cost function to take intensities into account. (#1760)
Adds (optional) intensities to sensor::PointCloud and uses it in a cost function. Not yet in use. Signed-off-by: Wolfgang Hess <whess@lyft.com>
1 parent ee98a92 commit cad3378

File tree

5 files changed

+205
-1
lines changed

5 files changed

+205
-1
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "cartographer/mapping/internal/3d/scan_matching/intensity_cost_function_3d.h"
2+
3+
namespace cartographer {
4+
namespace mapping {
5+
namespace scan_matching {
6+
7+
// This method is defined here instead of the header file as it was observed
8+
// that defining it in the header file has a negative impact on the runtime
9+
// performance.
10+
ceres::CostFunction* IntensityCostFunction3D::CreateAutoDiffCostFunction(
11+
const double scaling_factor, const float intensity_threshold,
12+
const sensor::PointCloud& point_cloud,
13+
const IntensityHybridGrid& hybrid_grid) {
14+
CHECK(!point_cloud.intensities().empty());
15+
return new ceres::AutoDiffCostFunction<
16+
IntensityCostFunction3D, ceres::DYNAMIC /* residuals */,
17+
3 /* translation variables */, 4 /* rotation variables */>(
18+
new IntensityCostFunction3D(scaling_factor, intensity_threshold,
19+
point_cloud, hybrid_grid),
20+
point_cloud.size());
21+
}
22+
23+
} // namespace scan_matching
24+
} // namespace mapping
25+
} // namespace cartographer
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2019 The Cartographer Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTENSITY_COST_FUNCTION_3D_H_
18+
#define CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTENSITY_COST_FUNCTION_3D_H_
19+
20+
#include "Eigen/Core"
21+
#include "cartographer/mapping/3d/hybrid_grid.h"
22+
#include "cartographer/mapping/internal/3d/scan_matching/interpolated_grid.h"
23+
#include "cartographer/sensor/point_cloud.h"
24+
#include "cartographer/transform/rigid_transform.h"
25+
#include "cartographer/transform/transform.h"
26+
#include "ceres/ceres.h"
27+
28+
namespace cartographer {
29+
namespace mapping {
30+
namespace scan_matching {
31+
32+
// Computes a cost for matching the 'point_cloud' to the 'hybrid_grid' with a
33+
// 'translation' and 'rotation'. The cost increases when points fall into space
34+
// for which different intensity has been observed, i.e. at voxels with different
35+
// values. Only points up to a certain threshold are evaluated which is intended
36+
// to ignore data from retroreflections.
37+
class IntensityCostFunction3D {
38+
public:
39+
static ceres::CostFunction* CreateAutoDiffCostFunction(
40+
const double scaling_factor, const float intensity_threshold,
41+
const sensor::PointCloud& point_cloud,
42+
const IntensityHybridGrid& hybrid_grid);
43+
44+
template <typename T>
45+
bool operator()(const T* const translation, const T* const rotation,
46+
T* const residual) const {
47+
const transform::Rigid3<T> transform(
48+
Eigen::Map<const Eigen::Matrix<T, 3, 1>>(translation),
49+
Eigen::Quaternion<T>(rotation[0], rotation[1], rotation[2],
50+
rotation[3]));
51+
return Evaluate(transform, residual);
52+
}
53+
54+
private:
55+
IntensityCostFunction3D(const double scaling_factor,
56+
const float intensity_threshold,
57+
const sensor::PointCloud& point_cloud,
58+
const IntensityHybridGrid& hybrid_grid)
59+
: scaling_factor_(scaling_factor),
60+
intensity_threshold_(intensity_threshold),
61+
point_cloud_(point_cloud),
62+
interpolated_grid_(hybrid_grid) {}
63+
64+
IntensityCostFunction3D(const IntensityCostFunction3D&) = delete;
65+
IntensityCostFunction3D& operator=(const IntensityCostFunction3D&) = delete;
66+
67+
template <typename T>
68+
bool Evaluate(const transform::Rigid3<T>& transform,
69+
T* const residual) const {
70+
for (size_t i = 0; i < point_cloud_.size(); ++i) {
71+
if (point_cloud_.intensities()[i] > intensity_threshold_) {
72+
residual[i] = T(0.f);
73+
} else {
74+
const Eigen::Matrix<T, 3, 1> point = point_cloud_[i].position.cast<T>();
75+
const T intensity = T(point_cloud_.intensities()[i]);
76+
77+
const Eigen::Matrix<T, 3, 1> world = transform * point;
78+
const T interpolated_intensity =
79+
interpolated_grid_.GetInterpolatedValue(world[0], world[1],
80+
world[2]);
81+
residual[i] = scaling_factor_ * (interpolated_intensity - intensity);
82+
}
83+
}
84+
return true;
85+
}
86+
87+
const double scaling_factor_;
88+
// We will ignore returns with intensity above this threshold.
89+
const float intensity_threshold_;
90+
const sensor::PointCloud& point_cloud_;
91+
const InterpolatedIntensityGrid interpolated_grid_;
92+
};
93+
94+
} // namespace scan_matching
95+
} // namespace mapping
96+
} // namespace cartographer
97+
98+
#endif // CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTENSITY_COST_FUNCTION_3D_H_
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2019 The Cartographer Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "cartographer/mapping/internal/3d/scan_matching/intensity_cost_function_3d.h"
18+
19+
#include <array>
20+
#include <memory>
21+
22+
#include "cartographer/mapping/3d/hybrid_grid.h"
23+
#include "cartographer/sensor/point_cloud.h"
24+
#include "cartographer/transform/rigid_transform.h"
25+
#include "ceres/ceres.h"
26+
#include "gmock/gmock.h"
27+
#include "gtest/gtest.h"
28+
29+
namespace cartographer {
30+
namespace mapping {
31+
namespace scan_matching {
32+
namespace {
33+
34+
using ::testing::DoubleNear;
35+
using ::testing::ElementsAre;
36+
37+
TEST(IntensityCostFunction3DTest, SmokeTest) {
38+
const sensor::PointCloud point_cloud(
39+
{{{0.f, 0.f, 0.f}}, {{1.f, 1.f, 1.f}}, {{2.f, 2.f, 2.f}}},
40+
{50.f, 100.f, 150.f});
41+
IntensityHybridGrid hybrid_grid(0.3f);
42+
hybrid_grid.AddIntensity(hybrid_grid.GetCellIndex({0.f, 0.f, 0.f}), 50.f);
43+
44+
std::unique_ptr<ceres::CostFunction> cost_function(
45+
IntensityCostFunction3D::CreateAutoDiffCostFunction(
46+
/*scaling_factor=*/1.0f, /*intensity_threshold=*/100.f, point_cloud,
47+
hybrid_grid));
48+
49+
const std::array<double, 3> translation{{0., 0., 0.}};
50+
const std::array<double, 4> rotation{{1., 0., 0., 0.}};
51+
52+
const std::array<const double*, 2> parameter_blocks{
53+
{translation.data(), rotation.data()}};
54+
std::array<double, 3> residuals;
55+
56+
cost_function->Evaluate(parameter_blocks.data(), residuals.data(),
57+
/*jacobians=*/nullptr);
58+
EXPECT_THAT(residuals,
59+
ElementsAre(DoubleNear(0., 1e-9), DoubleNear(-100., 1e-9),
60+
DoubleNear(0., 1e-9)));
61+
}
62+
63+
} // namespace
64+
} // namespace scan_matching
65+
} // namespace mapping
66+
} // namespace cartographer

cartographer/sensor/point_cloud.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,23 @@ namespace sensor {
2525
PointCloud::PointCloud() {}
2626
PointCloud::PointCloud(std::vector<PointCloud::PointType> points)
2727
: points_(std::move(points)) {}
28+
PointCloud::PointCloud(std::vector<PointType> points,
29+
std::vector<float> intensities)
30+
: points_(std::move(points)), intensities_(std::move(intensities)) {
31+
if (!intensities_.empty()) {
32+
CHECK_EQ(points_.size(), intensities_.size());
33+
}
34+
}
2835

2936
size_t PointCloud::size() const { return points_.size(); }
3037
bool PointCloud::empty() const { return points_.empty(); }
3138

3239
const std::vector<PointCloud::PointType>& PointCloud::points() const {
3340
return points_;
3441
}
42+
const std::vector<float>& PointCloud::intensities() const {
43+
return intensities_;
44+
}
3545
const PointCloud::PointType& PointCloud::operator[](const size_t index) const {
3646
return points_[index];
3747
}

cartographer/sensor/point_cloud.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,21 @@ namespace sensor {
3030

3131
// Stores 3D positions of points together with some additional data, e.g.
3232
// intensities.
33-
struct PointCloud {
33+
class PointCloud {
3434
public:
3535
using PointType = RangefinderPoint;
3636

3737
PointCloud();
3838
explicit PointCloud(std::vector<PointType> points);
39+
PointCloud(std::vector<PointType> points, std::vector<float> intensities);
3940

4041
// Returns the number of points in the point cloud.
4142
size_t size() const;
4243
// Checks whether there are any points in the point cloud.
4344
bool empty() const;
4445

4546
const std::vector<PointType>& points() const;
47+
const std::vector<float>& intensities() const;
4648
const PointType& operator[](const size_t index) const;
4749

4850
// Iterator over the points in the point cloud.
@@ -55,6 +57,9 @@ struct PointCloud {
5557
private:
5658
// For 2D points, the third entry is 0.f.
5759
std::vector<PointType> points_;
60+
// Intensities are optional. If non-empty, they must have the same size as
61+
// points.
62+
std::vector<float> intensities_;
5863
};
5964

6065
// Stores 3D positions of points with their relative measurement time in the

0 commit comments

Comments
 (0)