Skip to content

Commit de97346

Browse files
committed
graduated non-convexity
1 parent d80f615 commit de97346

File tree

10 files changed

+842
-17
lines changed

10 files changed

+842
-17
lines changed

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,17 @@ add_library(gtsam_points SHARED
144144
src/gtsam_points/features/normal_estimation.cpp
145145
src/gtsam_points/features/fpfh_estimation.cpp
146146
# registration
147-
src/gtsam_points/registration/ransac.cpp
148147
src/gtsam_points/registration/alignment.cpp
148+
src/gtsam_points/registration/ransac.cpp
149+
src/gtsam_points/registration/graduated_non_convexity.cpp
149150
# ann
150151
src/gtsam_points/ann/kdtree.cpp
151152
src/gtsam_points/ann/kdtreex.cpp
152153
src/gtsam_points/ann/intensity_kdtree.cpp
153154
src/gtsam_points/ann/ivox.cpp
154155
src/gtsam_points/ann/incremental_covariance_container.cpp
155156
src/gtsam_points/ann/incremental_covariance_voxelmap.cpp
157+
src/gtsam_points/ann/fast_occupancy_grid.cpp
156158
# types
157159
src/gtsam_points/types/point_cloud.cpp
158160
src/gtsam_points/types/point_cloud_cpu.cpp
@@ -257,14 +259,15 @@ endif()
257259

258260
#Demo
259261
if(BUILD_DEMO)
262+
find_package(spdlog REQUIRED)
260263
find_package(Iridescence REQUIRED)
261264

262265
file(GLOB demo_sources "src/demo/*.cpp")
263266
foreach(demo_src IN LISTS demo_sources)
264267
get_filename_component(demo_name ${demo_src} NAME_WE)
265268

266269
add_executable(${demo_name} ${demo_src})
267-
target_link_libraries(${demo_name} gtsam_points Iridescence::Iridescence)
270+
target_link_libraries(${demo_name} gtsam_points spdlog::spdlog Iridescence::Iridescence)
268271
endforeach()
269272
endif()
270273

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 Kenji Koide ([email protected])
3+
#pragma once
4+
5+
#include <vector>
6+
#include <bitset>
7+
#include <numeric>
8+
#include <gtsam_points/types/point_cloud.hpp>
9+
10+
namespace gtsam_points {
11+
12+
/// @brief Fast occupancy grid block.
13+
struct FastOccupancyBlock {
14+
public:
15+
FastOccupancyBlock() : cells(0) {}
16+
17+
static constexpr int stride = 8; ///< Size of the block in each dimension
18+
static constexpr int num_cells = stride * stride * stride; ///< Number of cells in the block
19+
20+
/// @brief Calculate the index of the cell in the block.
21+
/// @param coord Coordinate of the cell.
22+
int cell_index(const Eigen::Vector3i& coord) const { return coord.x() + coord.y() * stride + coord.z() * stride * stride; }
23+
24+
/// @brief Check if the cell is occupied.
25+
/// @param coord Coordinate of the cell.
26+
/// @return True if the cell is occupied.
27+
bool occupied(const Eigen::Vector3i& coord) const { return cells[cell_index(coord)]; }
28+
29+
/// @brief Check if the cell is free.
30+
/// @param coord Coordinate of the cell.
31+
/// @return True if the cell is free.
32+
bool free(const Eigen::Vector3i& coord) const { return !occupied(coord); }
33+
34+
/// @brief Set the cell as occupied.
35+
/// @param coord Coordinate of the cell.
36+
void set_occupied(const Eigen::Vector3i& coord) { cells.set(cell_index(coord)); }
37+
38+
/// @brief Set the cell as free.
39+
/// @param coord Coordinate of the cell.
40+
void set_free(const Eigen::Vector3i& coord) { cells.reset(cell_index(coord)); }
41+
42+
/// @brief Count the number of occupied cells.
43+
/// @return Number of occupied cells.
44+
int count() const { return cells.count(); }
45+
46+
public:
47+
std::bitset<num_cells> cells; ///< Occupancy status of each cell in the block.
48+
};
49+
50+
/// @brief Fast occupancy grid with occupancy blocks and flat hashing for efficient point cloud overlap evaluation.
51+
class FastOccupancyGrid {
52+
public:
53+
using Ptr = std::shared_ptr<FastOccupancyGrid>;
54+
using ConstPtr = std::shared_ptr<const FastOccupancyGrid>;
55+
56+
/// @brief Constructor.
57+
/// @param resolution Voxel resolution.
58+
FastOccupancyGrid(double resolution);
59+
~FastOccupancyGrid();
60+
61+
/// @brief Insert points into the grid.
62+
/// @param points Point cloud.
63+
/// @param pose Pose of the points.
64+
template <typename PointCloud>
65+
void insert(const PointCloud& points, const Eigen::Isometry3d& pose = Eigen::Isometry3d::Identity());
66+
67+
/// @brief Calculate the number of points overlapping with the grid.
68+
/// @param points Point cloud.
69+
/// @param pose Pose of the points.
70+
/// @return Overlap ratio.
71+
template <typename PointCloud>
72+
int calc_overlap(const PointCloud& points, const Eigen::Isometry3d& pose = Eigen::Isometry3d::Identity()) const;
73+
74+
/// @brief Calculate the overlap ratio of the points with the grid.
75+
/// @param points Point cloud.
76+
/// @param pose Pose of the points.
77+
/// @return Overlap ratio.
78+
template <typename PointCloud>
79+
double calc_overlap_rate(const PointCloud& points, const Eigen::Isometry3d& pose = Eigen::Isometry3d::Identity()) const;
80+
81+
/// @brief Get the overlap status of each point in the point cloud.
82+
/// @param points Point cloud.
83+
/// @param pose Pose of the points.
84+
/// @return Overlap status of each point (0=free, 1=occupied).
85+
template <typename PointCloud>
86+
std::vector<unsigned char> get_overlaps(const PointCloud& points, const Eigen::Isometry3d& pose = Eigen::Isometry3d::Identity()) const;
87+
88+
/// @brief Get the number of occupied cells in the grid.
89+
int num_occupied_cells() const;
90+
91+
private:
92+
std::uint64_t calc_index(const Eigen::Vector4i& coord) const;
93+
94+
Eigen::Vector3i calc_coord(std::uint64_t index) const;
95+
96+
std::uint64_t calc_hash(std::uint64_t index) const;
97+
98+
std::uint64_t find_block(std::uint64_t block_index) const;
99+
100+
std::uint64_t find_or_insert_block(std::uint64_t block_index);
101+
102+
void rehash(size_t hash_size);
103+
104+
private:
105+
static constexpr std::uint64_t INVALID_INDEX = std::numeric_limits<std::uint64_t>::max();
106+
static constexpr int coord_bit_size = 21; ///< Bits to represent each voxel coordinate (pack 21x3=63bits in 64bit int)
107+
static constexpr std::uint64_t coord_bit_mask = (1ull << 21) - 1; ///< Bit mask
108+
static constexpr std::uint64_t coord_offset = 1ull << (coord_bit_size - 1); ///< Coordinate offset to make values positive
109+
110+
double inv_resolution; ///< Inverse of the voxel resolution
111+
int max_seek_count; ///< Maximum number of seek attempts
112+
std::vector<std::pair<std::uint64_t, FastOccupancyBlock>> blocks; ///< Hash table of occupancy blocks
113+
};
114+
115+
} // namespace gtsam_points
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 Kenji Koide ([email protected])
3+
#pragma once
4+
5+
#include <gtsam_points/ann/fast_occupancy_grid.hpp>
6+
7+
#include <gtsam_points/types/frame_traits.hpp>
8+
#include <gtsam_points/util/fast_floor.hpp>
9+
#include <gtsam_points/util/vector3i_hash.hpp>
10+
#include <gtsam_points/types/point_cloud_cpu.hpp>
11+
12+
namespace gtsam_points {
13+
14+
template <typename PointCloud>
15+
void FastOccupancyGrid::insert(const PointCloud& points, const Eigen::Isometry3d& pose) {
16+
for (int i = 0; i < frame::size(points); i++) {
17+
const auto& pt = frame::point(points, i);
18+
const Eigen::Array4i global_coord = fast_floor((pose * pt) * inv_resolution) + coord_offset;
19+
const Eigen::Array4i block_coord = global_coord / FastOccupancyBlock::stride;
20+
const Eigen::Array4i cell_coord = global_coord - block_coord * FastOccupancyBlock::stride;
21+
22+
const std::uint64_t block_index = calc_index(block_coord);
23+
const std::uint64_t block_loc = find_or_insert_block(block_index);
24+
blocks[block_loc].second.set_occupied(cell_coord.head<3>());
25+
}
26+
}
27+
28+
template <typename PointCloud>
29+
int FastOccupancyGrid::calc_overlap(const PointCloud& points, const Eigen::Isometry3d& pose) const {
30+
int num_overlap = 0;
31+
for (int i = 0; i < frame::size(points); i++) {
32+
const auto& pt = frame::point(points, i);
33+
const Eigen::Array4i global_coord = fast_floor((pose * pt) * inv_resolution) + coord_offset;
34+
const Eigen::Array4i block_coord = global_coord / FastOccupancyBlock::stride;
35+
36+
const std::uint64_t block_index = calc_index(block_coord);
37+
const std::uint64_t block_loc = find_block(block_index);
38+
if (block_loc == INVALID_INDEX) {
39+
continue;
40+
}
41+
42+
const Eigen::Array4i cell_coord = global_coord - block_coord * FastOccupancyBlock::stride;
43+
num_overlap += blocks[block_loc].second.occupied(cell_coord.head<3>());
44+
}
45+
46+
return num_overlap;
47+
}
48+
49+
template <typename PointCloud>
50+
double FastOccupancyGrid::calc_overlap_rate(const PointCloud& points, const Eigen::Isometry3d& pose) const {
51+
return calc_overlap(points, pose) / static_cast<double>(frame::size(points));
52+
}
53+
54+
template <typename PointCloud>
55+
std::vector<unsigned char> FastOccupancyGrid::get_overlaps(const PointCloud& points, const Eigen::Isometry3d& pose) const {
56+
std::vector<unsigned char> overlaps(frame::size(points), 0);
57+
58+
for (int i = 0; i < frame::size(points); i++) {
59+
const auto& pt = frame::point(points, i);
60+
const Eigen::Array4i global_coord = fast_floor((pose * pt) * inv_resolution) + coord_offset;
61+
const Eigen::Array4i block_coord = global_coord / FastOccupancyBlock::stride;
62+
63+
const std::uint64_t block_index = calc_index(block_coord);
64+
const std::uint64_t block_loc = find_block(block_index);
65+
if (block_loc == INVALID_INDEX) {
66+
continue;
67+
}
68+
69+
const Eigen::Array4i cell_coord = global_coord - block_coord * FastOccupancyBlock::stride;
70+
overlaps[i] = blocks[block_loc].second.occupied(cell_coord.head<3>());
71+
}
72+
73+
return overlaps;
74+
}
75+
76+
} // namespace gtsam_points

0 commit comments

Comments
 (0)