Compare commits

...

3 Commits

Author SHA1 Message Date
koide3 08bc50beff
fix typo (#115) 2025-05-07 14:51:07 +09:00
koide3 9befefb198
sequential voxelmap accessor (#113)
* sequential voxelmap accessor

* capital
2025-05-07 11:35:58 +09:00
koide3 3466ea263a
change accessing order for column major (#112) 2025-05-07 11:25:04 +09:00
4 changed files with 91 additions and 6 deletions

View File

@ -34,6 +34,7 @@ public:
/// This class supports incremental point cloud insertion and LRU-based voxel deletion that removes voxels that are not recently referenced.
/// @note This class can be used as a point cloud as well as a neighbor search structure.
/// @note This class can handle arbitrary number of voxels and arbitrary range of voxel coordinates (in 32-bit int range).
/// @note To use this as a source point cloud for registration, use `SequentialVoxelMapAccessor`.
template <typename VoxelContents>
struct IncrementalVoxelMap {
public:

View File

@ -110,15 +110,15 @@ private:
const int u = uv[0] * index_map.cols();
const int v = uv[1] * index_map.rows();
for (int dv = -search_window_v; dv <= search_window_v; dv++) {
const int v_clamped = border_v(v + dv, index_map.rows());
if (v_clamped < 0 || v_clamped >= index_map.rows()) {
for (int du = -search_window_h; du <= search_window_h; du++) {
const int u_clamped = border_h(u + du, index_map.cols());
if (u_clamped < 0 || u_clamped >= index_map.cols()) {
continue;
}
for (int du = -search_window_h; du <= search_window_h; du++) {
const int u_clamped = border_h(u + du, index_map.cols());
if (u_clamped < 0 || u_clamped >= index_map.cols()) {
for (int dv = -search_window_v; dv <= search_window_v; dv++) {
const int v_clamped = border_v(v + dv, index_map.rows());
if (v_clamped < 0 || v_clamped >= index_map.rows()) {
continue;
}

View File

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: Copyright 2024 Kenji Koide
// SPDX-License-Identifier: MIT
#pragma once
#include <small_gicp/points/traits.hpp>
#include <small_gicp/ann/incremental_voxelmap.hpp>
namespace small_gicp {
/**
* @brief A wrapper class to sequentially access points in a voxelmap (e.g., using points in a voxelmap as source point cloud for registration).
* @note If the contents of the voxelmap are changed, the accessor must be recreated.
* @example
small_gicp::IncrementalVoxelMap<small_gicp::FlatContainerCov>::Ptr last_voxelmap = ...;
small_gicp::IncrementalVoxelMap<small_gicp::FlatContainerCov>::Ptr voxelmap = ...;
// Create a sequential accessor
const auto accessor = small_gicp::create_sequential_accessor(*voxelmap);
// Use the voxelmap as a source point cloud
small_gicp::Registration<small_gicp::GICPFactor, small_gicp::ParallelReductionOMP> registration;
auto result = registration.align(*last_voxelmap, accessor, *last_voxelmap, Eigen::Isometry3d::Identity());
*/
template <typename VoxelMap>
class SequentialVoxelMapAccessor {
public:
/// @brief Constructor.
/// @param voxelmap Voxelmap
SequentialVoxelMapAccessor(const VoxelMap& voxelmap) : voxelmap(voxelmap), indices(traits::point_indices(voxelmap)) {}
/// @brief Number of points in the voxelmap.
size_t size() const { return indices.size(); }
public:
const VoxelMap& voxelmap; ///< Voxelmap
const std::vector<size_t> indices; ///< Indices of points in the voxelmap
};
/// @brief Create a sequential voxelmap accessor.
template <typename VoxelMap>
SequentialVoxelMapAccessor<VoxelMap> create_sequential_accessor(const VoxelMap& voxelmap) {
return SequentialVoxelMapAccessor<VoxelMap>(voxelmap);
}
template <typename VoxelMap>
struct traits::Traits<SequentialVoxelMapAccessor<VoxelMap>> {
static size_t size(const SequentialVoxelMapAccessor<VoxelMap>& accessor) { return accessor.size(); }
static bool has_points(const SequentialVoxelMapAccessor<VoxelMap>& accessor) { return traits::has_points(accessor.voxelmap); }
static bool has_normals(const SequentialVoxelMapAccessor<VoxelMap>& accessor) { return traits::has_normals(accessor.voxelmap); }
static bool has_covs(const SequentialVoxelMapAccessor<VoxelMap>& accessor) { return traits::has_covs(accessor.voxelmap); }
static Eigen::Vector4d point(const SequentialVoxelMapAccessor<VoxelMap>& accessor, size_t i) { return traits::point(accessor.voxelmap, accessor.indices[i]); }
static Eigen::Vector4d normal(const SequentialVoxelMapAccessor<VoxelMap>& accessor, size_t i) { return traits::normal(accessor.voxelmap, accessor.indices[i]); }
static Eigen::Matrix4d cov(const SequentialVoxelMapAccessor<VoxelMap>& accessor, size_t i) { return traits::cov(accessor.voxelmap, accessor.indices[i]); }
};
} // namespace small_gicp

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT
#pragma once
#include <vector>
#include <Eigen/Core>
#include <small_gicp/points/traits.hpp>
@ -15,5 +16,30 @@ struct Traits<Eigen::MatrixXd> {
static Eigen::Vector4d point(const Eigen::MatrixXd& points, size_t i) { return Eigen::Vector4d(points(i, 0), points(i, 1), points(i, 2), 1.0); }
};
template <typename Scalar, int D>
struct Traits<std::vector<Eigen::Matrix<Scalar, D, 1>>> {
static_assert(D == 3 || D == 4, "Only 3D and 4D (homogeneous) points are supported");
static_assert(std::is_floating_point<Scalar>::value, "Only floating point types are supported");
using Point = Eigen::Matrix<Scalar, D, 1>;
static size_t size(const std::vector<Point>& points) { return points.size(); }
static bool has_points(const std::vector<Point>& points) { return points.size(); }
static Eigen::Vector4d point(const std::vector<Point>& points, size_t i) {
if constexpr (std::is_same_v<Scalar, double>) {
if constexpr (D == 3) {
return points[i].homogeneous();
} else {
return points[i];
}
} else {
if constexpr (D == 3) {
return points[i].homogeneous().template cast<double>();
} else {
return points[i].template cast<double>();
}
}
}
};
} // namespace traits
} // namespace small_gicp