mirror of https://github.com/koide3/small_gicp.git
Compare commits
7 Commits
8ca7bd29a8
...
6027a5556d
| Author | SHA1 | Date |
|---|---|---|
|
|
6027a5556d | |
|
|
08bc50beff | |
|
|
9befefb198 | |
|
|
3466ea263a | |
|
|
df145cbb15 | |
|
|
db2f8e6646 | |
|
|
fa518412d7 |
|
|
@ -13,7 +13,7 @@ on:
|
|||
|
||||
jobs:
|
||||
coverage:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ on:
|
|||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
|||
|
|
@ -129,5 +129,5 @@ small_vgicp : APE=5.956 +- 2.725 RPE(100)=1.315 +- 0.762 RPE(400)=6.8
|
|||
|
||||
[Code](https://github.com/koide3/small_gicp/blob/pybench/src/benchmark/odometry_benchmark.py)
|
||||
|
||||
Processing speed comparison between small_gicp and Open3D ([youtube]((https://youtu.be/LNESzGXPr4c?feature=shared))).
|
||||
Processing speed comparison between small_gicp and Open3D ([youtube](https://youtu.be/LNESzGXPr4c?feature=shared)).
|
||||
[](https://youtu.be/LNESzGXPr4c?feature=shared)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ endif()
|
|||
|
||||
if (BUILD_WITH_PCL)
|
||||
find_package(PCL REQUIRED)
|
||||
if(PCL_VERSION VERSION_LESS "1.11.0")
|
||||
message(FATAL_ERROR "The found PCL version ${PCL_VERSION} is too low. Required is at least 1.11.0")
|
||||
endif()
|
||||
add_compile_definitions(BUILD_WITH_PCL)
|
||||
if (NOT TARGET PCL::PCL)
|
||||
add_library(PCL::PCL INTERFACE IMPORTED)
|
||||
|
|
@ -111,8 +114,8 @@ if(ENABLE_COVERAGE)
|
|||
find_program(GENHTML genhtml REQUIRED)
|
||||
|
||||
add_custom_target(coverage
|
||||
COMMAND ${LCOV} --directory . --capture --output-file coverage.info
|
||||
COMMAND ${LCOV} --remove coverage.info -o coverage.info '/usr/*'
|
||||
COMMAND ${LCOV} --directory . --capture --output-file coverage.info --ignore-errors mismatch
|
||||
COMMAND ${LCOV} --remove coverage.info -o coverage.info '/usr/*' --ignore-errors mismatch
|
||||
COMMAND ${GENHTML} --demangle-cpp -o coverage coverage.info
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ python3 src/example/basic_registration.py
|
|||
|
||||
## [Benchmark](BENCHMARK.md)
|
||||
|
||||
Processing speed comparison between small_gicp and Open3D ([youtube]((https://youtu.be/LNESzGXPr4c?feature=shared))).
|
||||
Processing speed comparison between small_gicp and Open3D ([youtube](https://youtu.be/LNESzGXPr4c?feature=shared)).
|
||||
[](https://youtu.be/LNESzGXPr4c?feature=shared)
|
||||
|
||||
### Downsampling
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -108,7 +108,7 @@ struct LevenbergMarquardtOptimizer {
|
|||
// Solve with damping
|
||||
const Eigen::Matrix<double, 6, 1> delta = (H + lambda * Eigen::Matrix<double, 6, 6>::Identity()).ldlt().solve(-b);
|
||||
|
||||
// Validte new solution
|
||||
// Validate new solution
|
||||
const Eigen::Isometry3d new_T = result.T_target_source * se3_exp(delta);
|
||||
double new_e = reduction.error(target, source, new_T, factors);
|
||||
general_factor.update_error(target, source, new_T, &e);
|
||||
|
|
@ -150,7 +150,7 @@ struct LevenbergMarquardtOptimizer {
|
|||
|
||||
bool verbose; ///< If true, print debug messages
|
||||
int max_iterations; ///< Max number of optimization iterations
|
||||
int max_inner_iterations; ///< Max number of inner iterations (lambda-trial)
|
||||
int max_inner_iterations; ///< Max number of inner iterations (lambda-trial)
|
||||
double init_lambda; ///< Initial lambda (damping factor)
|
||||
double lambda_factor; ///< Lambda increase factor
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue