mirror of https://github.com/koide3/small_gicp.git
Docpy (#59)
* doc for py * doc for cpp * sphinx * fix sphinx * generate docs
This commit is contained in:
parent
1183e3d39a
commit
84406aefda
|
|
@ -61,6 +61,12 @@ cd ~/.local/lib/python3.10/site-packages
|
||||||
pybind11-stubgen -o . --ignore-invalid=all small_gicp
|
pybind11-stubgen -o . --ignore-invalid=all small_gicp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- Auto-generated docs: [C++](https://koide3.github.io/small_gicp/doc_cpp/index.html) [Python](https://koide3.github.io/small_gicp/doc_py/index.html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage (C++)
|
## Usage (C++)
|
||||||
|
|
||||||
The following examples assume `using namespace small_gicp` is placed somewhere.
|
The following examples assume `using namespace small_gicp` is placed somewhere.
|
||||||
|
|
|
||||||
|
|
@ -829,7 +829,7 @@ WARN_LOGFILE =
|
||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = include README.md
|
INPUT = ../include ../README.md
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
|
|
@ -1184,7 +1184,7 @@ GENERATE_HTML = YES
|
||||||
# The default directory is: html.
|
# The default directory is: html.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_OUTPUT = html
|
HTML_OUTPUT = doc_cpp
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||||
# generated HTML page (for example: .htm, .php, .asp).
|
# generated HTML page (for example: .htm, .php, .asp).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "make cpp|py|all"
|
||||||
|
|
||||||
|
.PHONY: cpp
|
||||||
|
cpp:
|
||||||
|
@echo "Building C++ documentation..."
|
||||||
|
doxygen Doxyfile doc_cpp
|
||||||
|
|
||||||
|
.PHONY: py
|
||||||
|
py:
|
||||||
|
@echo "Building Python documentation..."
|
||||||
|
mkdir -p build && cd build && cmake ../../ -DBUILD_PYTHON_BINDINGS=ON && make -j
|
||||||
|
sphinx-build -b singlehtml . ./doc_py/
|
||||||
|
|
||||||
|
.PHONY: mkdocs
|
||||||
|
mkdocs:
|
||||||
|
@echo "Building MkDocs documentation..."
|
||||||
|
cd .. && mkdocs build
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: cpp py mkdocs
|
||||||
|
@echo "All documentation built."
|
||||||
|
|
||||||
|
.PHONY: deploy
|
||||||
|
deploy:
|
||||||
|
@echo "Deploying documentation..."
|
||||||
|
cd .. && mkdocs gh-deploy
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# For the full list of built-in configuration values, see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
project = 'small_gicp'
|
||||||
|
copyright = '2024, k.koide'
|
||||||
|
author = 'k.koide'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, os.path.abspath('./build/'))
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
|
||||||
|
|
||||||
|
templates_path = ['_templates']
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# small_gicp
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- [C++](doc_cpp/index.html)
|
||||||
|
- [Python](doc_py/index.html)
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
.. small_gicp documentation master file, created by
|
||||||
|
sphinx-quickstart on Wed Jun 5 11:07:43 2024.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
Welcome to small_gicp's documentation!
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Contents:
|
||||||
|
|
||||||
|
small_gicp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
small\_gicp module
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. automodule:: small_gicp
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
@ -8,26 +8,32 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
/// @brief Flat point container
|
/// @brief Point container with a flat vector.
|
||||||
/// @note IncrementalVoxelMap combined with FlastContainer is mostly the same as iVox.
|
/// @note IncrementalVoxelMap combined with FlastContainer is mostly the same as linear iVox.
|
||||||
/// Bai et al., "Faster-LIO: Lightweight Tightly Coupled Lidar-Inertial Odometry Using Parallel Sparse Incremental Voxels", IEEE RA-L, 2022
|
/// Bai et al., "Faster-LIO: Lightweight Tightly Coupled Lidar-Inertial Odometry Using Parallel Sparse Incremental Voxels", IEEE RA-L, 2022
|
||||||
/// @tparam HasNormals If true, normals are stored
|
/// @tparam HasNormals If true, store normals.
|
||||||
/// @tparam HasCovs If true, covariances are stored
|
/// @tparam HasCovs If true, store covariances.
|
||||||
template <bool HasNormals = false, bool HasCovs = false>
|
template <bool HasNormals = false, bool HasCovs = false>
|
||||||
struct FlatContainer {
|
struct FlatContainer {
|
||||||
public:
|
public:
|
||||||
|
/// @brief FlatContainer setting.
|
||||||
struct Setting {
|
struct Setting {
|
||||||
double min_sq_dist_in_cell = 0.1 * 0.1; ///< Minimum squared distance between points in a cell
|
double min_sq_dist_in_cell = 0.1 * 0.1; ///< Minimum squared distance between points in a cell.
|
||||||
size_t max_num_points_in_cell = 10; ///< Maximum number of points in a cell
|
size_t max_num_points_in_cell = 10; ///< Maximum number of points in a cell.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor.
|
||||||
FlatContainer() { points.reserve(5); }
|
FlatContainer() { points.reserve(5); }
|
||||||
|
|
||||||
/// @brief Number of points
|
/// @brief Number of points.
|
||||||
size_t size() const { return points.size(); }
|
size_t size() const { return points.size(); }
|
||||||
|
|
||||||
/// @brief Add a point to the container
|
/// @brief Add a point to the container.
|
||||||
|
/// @param setting Setting
|
||||||
|
/// @param transformed_pt Transformed point (== T * points[i])
|
||||||
|
/// @param points Point cloud
|
||||||
|
/// @param i Index of the point
|
||||||
|
/// @param T Transformation matrix
|
||||||
template <typename PointCloud>
|
template <typename PointCloud>
|
||||||
void add(const Setting& setting, const Eigen::Vector4d& transformed_pt, const PointCloud& points, size_t i, const Eigen::Isometry3d& T) {
|
void add(const Setting& setting, const Eigen::Vector4d& transformed_pt, const PointCloud& points, size_t i, const Eigen::Isometry3d& T) {
|
||||||
if (
|
if (
|
||||||
|
|
@ -46,10 +52,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Finalize the container (Nothing to do for FlatContainer)
|
/// @brief Finalize the container (Nothing to do for FlatContainer).
|
||||||
void finalize() {}
|
void finalize() {}
|
||||||
|
|
||||||
/// @brief Find the nearest neighbor
|
/// @brief Find the nearest neighbor.
|
||||||
/// @param pt Query point
|
/// @param pt Query point
|
||||||
/// @param k_index Index of the nearest neighbor
|
/// @param k_index Index of the nearest neighbor
|
||||||
/// @param k_sq_dist Squared distance to the nearest neighbor
|
/// @param k_sq_dist Squared distance to the nearest neighbor
|
||||||
|
|
@ -76,7 +82,7 @@ public:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Find k nearest neighbors
|
/// @brief Find k nearest neighbors.
|
||||||
/// @param pt Query point
|
/// @param pt Query point
|
||||||
/// @param k Number of neighbors
|
/// @param k Number of neighbors
|
||||||
/// @param k_index Indices of nearest neighbors
|
/// @param k_index Indices of nearest neighbors
|
||||||
|
|
@ -109,14 +115,18 @@ public:
|
||||||
public:
|
public:
|
||||||
struct Empty {};
|
struct Empty {};
|
||||||
|
|
||||||
std::vector<Eigen::Vector4d> points;
|
std::vector<Eigen::Vector4d> points; ///< Points
|
||||||
std::conditional_t<HasNormals, std::vector<Eigen::Vector4d>, Empty> normals;
|
std::conditional_t<HasNormals, std::vector<Eigen::Vector4d>, Empty> normals; ///< Normals (Empty if HasNormals is false)
|
||||||
std::conditional_t<HasCovs, std::vector<Eigen::Matrix4d>, Empty> covs;
|
std::conditional_t<HasCovs, std::vector<Eigen::Matrix4d>, Empty> covs; ///< Covariances (Empty if HasCovs is false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief FlatContainer that stores only points.
|
||||||
using FlatContainerPoints = FlatContainer<false, false>;
|
using FlatContainerPoints = FlatContainer<false, false>;
|
||||||
|
/// @brief FlatContainer with normals.
|
||||||
using FlatContainerNormal = FlatContainer<true, false>;
|
using FlatContainerNormal = FlatContainer<true, false>;
|
||||||
|
/// @brief FlatContainer with covariances.
|
||||||
using FlatContainerCov = FlatContainer<false, true>;
|
using FlatContainerCov = FlatContainer<false, true>;
|
||||||
|
/// @brief FlatContainer with normals and covariances.
|
||||||
using FlatContainerNormalCov = FlatContainer<true, true>;
|
using FlatContainerNormalCov = FlatContainer<true, true>;
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,18 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
/// @brief Gaussian voxel.
|
/// @brief Gaussian voxel that computes and stores voxel mean and covariance.
|
||||||
struct GaussianVoxel {
|
struct GaussianVoxel {
|
||||||
public:
|
public:
|
||||||
struct Setting {};
|
struct Setting {};
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor.
|
||||||
GaussianVoxel() : finalized(false), num_points(0), mean(Eigen::Vector4d::Zero()), cov(Eigen::Matrix4d::Zero()) {}
|
GaussianVoxel() : finalized(false), num_points(0), mean(Eigen::Vector4d::Zero()), cov(Eigen::Matrix4d::Zero()) {}
|
||||||
|
|
||||||
/// @brief Number of points in the voxel (Always 1 for GaussianVoxel)
|
/// @brief Number of points in the voxel (Always 1 for GaussianVoxel).
|
||||||
size_t size() const { return 1; }
|
size_t size() const { return 1; }
|
||||||
|
|
||||||
/// @brief Add a point to the voxel
|
/// @brief Add a point to the voxel.
|
||||||
/// @param setting Setting
|
/// @param setting Setting
|
||||||
/// @param transformed_pt Transformed point mean
|
/// @param transformed_pt Transformed point mean
|
||||||
/// @param points Point cloud
|
/// @param points Point cloud
|
||||||
|
|
@ -41,7 +41,7 @@ public:
|
||||||
this->cov += T.matrix() * traits::cov(points, i) * T.matrix().transpose();
|
this->cov += T.matrix() * traits::cov(points, i) * T.matrix().transpose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Finalize the voxel mean and covariance
|
/// @brief Finalize the voxel mean and covariance.
|
||||||
void finalize() {
|
void finalize() {
|
||||||
if (finalized) {
|
if (finalized) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
/// @brief Voxel meta information
|
/// @brief Voxel meta information.
|
||||||
struct VoxelInfo {
|
struct VoxelInfo {
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor.
|
||||||
/// @param coord Voxel coordinate
|
/// @param coord Integer voxel coordinates
|
||||||
/// @param lru LRU counter for caching
|
/// @param lru LRU counter for caching
|
||||||
VoxelInfo(const Eigen::Vector3i& coord, size_t lru) : lru(lru), coord(coord) {}
|
VoxelInfo(const Eigen::Vector3i& coord, size_t lru) : lru(lru), coord(coord) {}
|
||||||
|
|
||||||
|
|
@ -31,21 +31,21 @@ public:
|
||||||
|
|
||||||
/// @brief Incremental voxelmap.
|
/// @brief Incremental voxelmap.
|
||||||
/// This class supports incremental point cloud insertion and LRU-based voxel deletion.
|
/// This class supports incremental point cloud insertion and LRU-based voxel deletion.
|
||||||
/// @note This class can be used as a point cloud as well as a neighbor search.
|
/// @note This class can be used as a point cloud as well as a neighbor search structure.
|
||||||
template <typename VoxelContents>
|
template <typename VoxelContents>
|
||||||
struct IncrementalVoxelMap {
|
struct IncrementalVoxelMap {
|
||||||
public:
|
public:
|
||||||
using Ptr = std::shared_ptr<IncrementalVoxelMap>;
|
using Ptr = std::shared_ptr<IncrementalVoxelMap>;
|
||||||
using ConstPtr = std::shared_ptr<const IncrementalVoxelMap>;
|
using ConstPtr = std::shared_ptr<const IncrementalVoxelMap>;
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor.
|
||||||
/// @param leaf_size Voxel size
|
/// @param leaf_size Voxel size
|
||||||
explicit IncrementalVoxelMap(double leaf_size) : inv_leaf_size(1.0 / leaf_size), lru_horizon(100), lru_clear_cycle(10), lru_counter(0) {}
|
explicit IncrementalVoxelMap(double leaf_size) : inv_leaf_size(1.0 / leaf_size), lru_horizon(100), lru_clear_cycle(10), lru_counter(0) {}
|
||||||
|
|
||||||
/// @brief Number of points in the voxelmap
|
/// @brief Number of points in the voxelmap.
|
||||||
size_t size() const { return flat_voxels.size(); }
|
size_t size() const { return flat_voxels.size(); }
|
||||||
|
|
||||||
/// @brief Insert points to the voxelmap
|
/// @brief Insert points to the voxelmap.
|
||||||
/// @param points Point cloud
|
/// @param points Point cloud
|
||||||
/// @param T Transformation matrix
|
/// @param T Transformation matrix
|
||||||
template <typename PointCloud>
|
template <typename PointCloud>
|
||||||
|
|
@ -88,7 +88,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Find the nearest neighbor
|
/// @brief Find the nearest neighbor.
|
||||||
/// @param pt Query point
|
/// @param pt Query point
|
||||||
/// @param index Index of the nearest neighbor
|
/// @param index Index of the nearest neighbor
|
||||||
/// @param sq_dist Squared distance to the nearest neighbor
|
/// @param sq_dist Squared distance to the nearest neighbor
|
||||||
|
|
@ -139,9 +139,10 @@ public:
|
||||||
return num_found;
|
return num_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Calculate the global point index from the voxel index and the point index.
|
||||||
inline size_t calc_index(const size_t voxel_id, const size_t point_id) const { return (voxel_id << point_id_bits) | point_id; }
|
inline size_t calc_index(const size_t voxel_id, const size_t point_id) const { return (voxel_id << point_id_bits) | point_id; }
|
||||||
inline size_t voxel_id(const size_t i) const { return i >> point_id_bits; } ///< Extract the point ID from an index
|
inline size_t voxel_id(const size_t i) const { return i >> point_id_bits; } ///< Extract the point ID from a global index.
|
||||||
inline size_t point_id(const size_t i) const { return i & ((1ull << point_id_bits) - 1); } ///< Extract the voxel ID from an index
|
inline size_t point_id(const size_t i) const { return i & ((1ull << point_id_bits) - 1); } ///< Extract the voxel ID from a global index.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static_assert(sizeof(size_t) == 8, "size_t must be 64-bit");
|
static_assert(sizeof(size_t) == 8, "size_t must be 64-bit");
|
||||||
|
|
@ -149,13 +150,13 @@ public:
|
||||||
static constexpr int voxel_id_bits = 64 - point_id_bits; ///< Use the remaining bits for voxel id
|
static constexpr int voxel_id_bits = 64 - point_id_bits; ///< Use the remaining bits for voxel id
|
||||||
const double inv_leaf_size; ///< Inverse of the voxel size
|
const double inv_leaf_size; ///< Inverse of the voxel size
|
||||||
|
|
||||||
size_t lru_horizon; ///< LRU horizon size
|
size_t lru_horizon; ///< LRU horizon size. Voxels that have not been accessed for lru_horizon steps are deleted.
|
||||||
size_t lru_clear_cycle; ///< LRU clear cycle
|
size_t lru_clear_cycle; ///< LRU clear cycle. Voxel deletion is performed every lru_clear_cycle steps.
|
||||||
size_t lru_counter; ///< LRU counter
|
size_t lru_counter; ///< LRU counter. Incremented every step.
|
||||||
|
|
||||||
typename VoxelContents::Setting voxel_setting; ///< Voxel setting
|
typename VoxelContents::Setting voxel_setting; ///< Voxel setting.
|
||||||
std::vector<std::shared_ptr<std::pair<VoxelInfo, VoxelContents>>> flat_voxels; ///< Voxel contents
|
std::vector<std::shared_ptr<std::pair<VoxelInfo, VoxelContents>>> flat_voxels; ///< Voxel contents.
|
||||||
std::unordered_map<Eigen::Vector3i, size_t, XORVector3iHash> voxels; ///< Voxel index map
|
std::unordered_map<Eigen::Vector3i, size_t, XORVector3iHash> voxels; ///< Voxel index map.
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
|
||||||
|
|
@ -9,24 +9,30 @@ namespace pcl {
|
||||||
using Matrix4fMap = Eigen::Map<Eigen::Matrix4f, Eigen::Aligned>;
|
using Matrix4fMap = Eigen::Map<Eigen::Matrix4f, Eigen::Aligned>;
|
||||||
using Matrix4fMapConst = const Eigen::Map<const Eigen::Matrix4f, Eigen::Aligned>;
|
using Matrix4fMapConst = const Eigen::Map<const Eigen::Matrix4f, Eigen::Aligned>;
|
||||||
|
|
||||||
/// @brief Point with covariance
|
/// @brief Point with covariance for PCL
|
||||||
struct PointCovariance {
|
struct PointCovariance {
|
||||||
PCL_ADD_POINT4D;
|
PCL_ADD_POINT4D; ///< Point coordinates
|
||||||
Eigen::Matrix4f cov;
|
Eigen::Matrix4f cov; ///< 4x4 covariance matrix
|
||||||
|
|
||||||
|
/// @brief Get covariance matrix as Matrix4fMap
|
||||||
Matrix4fMap getCovariance4fMap() { return Matrix4fMap(cov.data()); }
|
Matrix4fMap getCovariance4fMap() { return Matrix4fMap(cov.data()); }
|
||||||
|
|
||||||
|
/// @brief Get covariance matrix as Matrix4fMapConst
|
||||||
Matrix4fMapConst getCovariance4fMap() const { return Matrix4fMapConst(cov.data()); }
|
Matrix4fMapConst getCovariance4fMap() const { return Matrix4fMapConst(cov.data()); }
|
||||||
|
|
||||||
PCL_MAKE_ALIGNED_OPERATOR_NEW
|
PCL_MAKE_ALIGNED_OPERATOR_NEW
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Point with normal and covariance
|
/// @brief Point with normal and covariance for PCL
|
||||||
struct PointNormalCovariance {
|
struct PointNormalCovariance {
|
||||||
PCL_ADD_POINT4D;
|
PCL_ADD_POINT4D; ///< Point coordinates
|
||||||
PCL_ADD_NORMAL4D
|
PCL_ADD_NORMAL4D ///< Point normal
|
||||||
Eigen::Matrix4f cov;
|
Eigen::Matrix4f cov; ///< 4x4 covariance matrix
|
||||||
|
|
||||||
|
/// @brief Get covariance matrix as Matrix4fMap
|
||||||
Matrix4fMap getCovariance4fMap() { return Matrix4fMap(cov.data()); }
|
Matrix4fMap getCovariance4fMap() { return Matrix4fMap(cov.data()); }
|
||||||
|
|
||||||
|
/// @brief Get covariance matrix as Matrix4fMapConst
|
||||||
Matrix4fMapConst getCovariance4fMap() const { return Matrix4fMapConst(cov.data()); }
|
Matrix4fMapConst getCovariance4fMap() const { return Matrix4fMapConst(cov.data()); }
|
||||||
|
|
||||||
PCL_MAKE_ALIGNED_OPERATOR_NEW
|
PCL_MAKE_ALIGNED_OPERATOR_NEW
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
|
/// @brief Proxy class to access PCL point cloud with external covariance matrices.
|
||||||
template <typename PointT>
|
template <typename PointT>
|
||||||
struct PointCloudProxy {
|
struct PointCloudProxy {
|
||||||
PointCloudProxy(const pcl::PointCloud<PointT>& cloud, std::vector<Eigen::Matrix4d>& covs) : cloud(cloud), covs(covs) {}
|
PointCloudProxy(const pcl::PointCloud<PointT>& cloud, std::vector<Eigen::Matrix4d>& covs) : cloud(cloud), covs(covs) {}
|
||||||
|
|
||||||
const pcl::PointCloud<PointT>& cloud;
|
const pcl::PointCloud<PointT>& cloud; ///< Point cloud
|
||||||
std::vector<Eigen::Matrix4d>& covs;
|
std::vector<Eigen::Matrix4d>& covs; ///< Covariance matrices
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ inline Eigen::Matrix3d skew(const Eigen::Vector3d& x) {
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// @brief SO3 expmap.
|
||||||
|
/// @param omega [rx, ry, rz]
|
||||||
|
/// @return Quaternion
|
||||||
inline Eigen::Quaterniond so3_exp(const Eigen::Vector3d& omega) {
|
inline Eigen::Quaterniond so3_exp(const Eigen::Vector3d& omega) {
|
||||||
double theta_sq = omega.dot(omega);
|
double theta_sq = omega.dot(omega);
|
||||||
|
|
||||||
|
|
@ -67,6 +71,9 @@ inline Eigen::Quaterniond so3_exp(const Eigen::Vector3d& omega) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotation-first
|
// Rotation-first
|
||||||
|
/// @brief SE3 expmap (Rotation-first).
|
||||||
|
/// @param a Twist vector [rx, ry, rz, tx, ty, tz]
|
||||||
|
/// @return SE3 matrix
|
||||||
inline Eigen::Isometry3d se3_exp(const Eigen::Matrix<double, 6, 1>& a) {
|
inline Eigen::Isometry3d se3_exp(const Eigen::Matrix<double, 6, 1>& a) {
|
||||||
using std::cos;
|
using std::cos;
|
||||||
using std::sin;
|
using std::sin;
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
|
/// @brief Computes point normals from eigenvectors and sets them to the point cloud.
|
||||||
template <typename PointCloud>
|
template <typename PointCloud>
|
||||||
struct NormalSetter {
|
struct NormalSetter {
|
||||||
|
/// @brief Handle invalid case (too few points).
|
||||||
static void set_invalid(PointCloud& cloud, size_t i) { traits::set_normal(cloud, i, Eigen::Vector4d::Zero()); }
|
static void set_invalid(PointCloud& cloud, size_t i) { traits::set_normal(cloud, i, Eigen::Vector4d::Zero()); }
|
||||||
|
|
||||||
|
/// @brief Compute and set the normal to the point cloud.
|
||||||
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
||||||
const Eigen::Vector4d normal = (Eigen::Vector4d() << eigenvectors.col(0).normalized(), 0.0).finished();
|
const Eigen::Vector4d normal = (Eigen::Vector4d() << eigenvectors.col(0).normalized(), 0.0).finished();
|
||||||
if (traits::point(cloud, i).dot(normal) > 0) {
|
if (traits::point(cloud, i).dot(normal) > 0) {
|
||||||
|
|
@ -21,14 +24,17 @@ struct NormalSetter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Computes point covariances from eigenvectors and sets them to the point cloud.
|
||||||
template <typename PointCloud>
|
template <typename PointCloud>
|
||||||
struct CovarianceSetter {
|
struct CovarianceSetter {
|
||||||
|
/// @brief Handle invalid case (too few points).
|
||||||
static void set_invalid(PointCloud& cloud, size_t i) {
|
static void set_invalid(PointCloud& cloud, size_t i) {
|
||||||
Eigen::Matrix4d cov = Eigen::Matrix4d::Identity();
|
Eigen::Matrix4d cov = Eigen::Matrix4d::Identity();
|
||||||
cov(3, 3) = 0.0;
|
cov(3, 3) = 0.0;
|
||||||
traits::set_cov(cloud, i, cov);
|
traits::set_cov(cloud, i, cov);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Compute and set the covariance to the point cloud.
|
||||||
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
||||||
const Eigen::Vector3d values(1e-3, 1.0, 1.0);
|
const Eigen::Vector3d values(1e-3, 1.0, 1.0);
|
||||||
Eigen::Matrix4d cov = Eigen::Matrix4d::Zero();
|
Eigen::Matrix4d cov = Eigen::Matrix4d::Zero();
|
||||||
|
|
@ -37,13 +43,16 @@ struct CovarianceSetter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Computes point normals and covariances from eigenvectors and sets them to the point cloud.
|
||||||
template <typename PointCloud>
|
template <typename PointCloud>
|
||||||
struct NormalCovarianceSetter {
|
struct NormalCovarianceSetter {
|
||||||
|
/// @brief Handle invalid case (too few points).
|
||||||
static void set_invalid(PointCloud& cloud, size_t i) {
|
static void set_invalid(PointCloud& cloud, size_t i) {
|
||||||
NormalSetter<PointCloud>::set_invalid(cloud, i);
|
NormalSetter<PointCloud>::set_invalid(cloud, i);
|
||||||
CovarianceSetter<PointCloud>::set_invalid(cloud, i);
|
CovarianceSetter<PointCloud>::set_invalid(cloud, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Compute and set the normal and covariance to the point cloud.
|
||||||
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
static void set(PointCloud& cloud, size_t i, const Eigen::Matrix3d& eigenvectors) {
|
||||||
NormalSetter<PointCloud>::set(cloud, i, eigenvectors);
|
NormalSetter<PointCloud>::set(cloud, i, eigenvectors);
|
||||||
CovarianceSetter<PointCloud>::set(cloud, i, eigenvectors);
|
CovarianceSetter<PointCloud>::set(cloud, i, eigenvectors);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@
|
||||||
|
|
||||||
namespace small_gicp {
|
namespace small_gicp {
|
||||||
|
|
||||||
|
/// @brief Implementation of merge sort with OpenMP parallelism. Do not call this directly. Use merge_sort_omp instead.
|
||||||
|
/// @param first First iterator
|
||||||
|
/// @param last Last iterator
|
||||||
|
/// @param comp Comparison function
|
||||||
template <typename RandomAccessIterator, typename Compare>
|
template <typename RandomAccessIterator, typename Compare>
|
||||||
void merge_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
|
void merge_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
|
||||||
const size_t n = std::distance(first, last);
|
const size_t n = std::distance(first, last);
|
||||||
|
|
@ -31,6 +35,12 @@ void merge_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last,
|
||||||
std::inplace_merge(first, center, last, comp);
|
std::inplace_merge(first, center, last, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Merge sort with OpenMP parallelism.
|
||||||
|
/// @note This tends to be slower than quick_sort_omp.
|
||||||
|
/// @param first First iterator
|
||||||
|
/// @param last Last iterator
|
||||||
|
/// @param comp Comparison function
|
||||||
|
/// @param num_threads Number of threads
|
||||||
template <typename RandomAccessIterator, typename Compare>
|
template <typename RandomAccessIterator, typename Compare>
|
||||||
void merge_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
|
void merge_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
@ -44,6 +54,10 @@ void merge_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Implementation of quick sort with OpenMP parallelism. Do not call this directly. Use quick_sort_omp instead.
|
||||||
|
/// @param first First iterator
|
||||||
|
/// @param last Last iterator
|
||||||
|
/// @param comp Comparison function
|
||||||
template <typename RandomAccessIterator, typename Compare>
|
template <typename RandomAccessIterator, typename Compare>
|
||||||
void quick_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
|
void quick_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
|
||||||
const std::ptrdiff_t n = std::distance(first, last);
|
const std::ptrdiff_t n = std::distance(first, last);
|
||||||
|
|
@ -72,6 +86,11 @@ void quick_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last,
|
||||||
quick_sort_omp_impl(middle2, last, comp);
|
quick_sort_omp_impl(middle2, last, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Quick sort with OpenMP parallelism.
|
||||||
|
/// @param first First iterator
|
||||||
|
/// @param last Last iterator
|
||||||
|
/// @param comp Comparison function
|
||||||
|
/// @param num_threads Number of threads
|
||||||
template <typename RandomAccessIterator, typename Compare>
|
template <typename RandomAccessIterator, typename Compare>
|
||||||
void quick_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
|
void quick_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
site_name: "small_gicp"
|
||||||
|
site_author: k.koide
|
||||||
|
repo_url: https://github.com/koide3/small_gicp
|
||||||
|
site_url: https://github.com/koide3/small_gicp
|
||||||
|
site_description: "small_gicp: Efficient and parallel algorithms for point cloud registration"
|
||||||
|
|
||||||
|
theme:
|
||||||
|
name: material
|
||||||
|
palette:
|
||||||
|
primary: indigo
|
||||||
|
front:
|
||||||
|
text: Roboto
|
||||||
|
|
||||||
|
use_directory_urls: false
|
||||||
|
|
||||||
|
markdown_extensions:
|
||||||
|
- meta
|
||||||
|
- attr_list
|
||||||
|
- admonition
|
||||||
|
- pymdownx.highlight:
|
||||||
|
anchor_linenums: true
|
||||||
|
- pymdownx.inlinehilite
|
||||||
|
- pymdownx.snippets
|
||||||
|
- pymdownx.superfences
|
||||||
|
- pymdownx.emoji:
|
||||||
|
emoji_index: !!python/name:materialx.emoji.twemoji
|
||||||
|
emoji_generator: !!python/name:materialx.emoji.to_svg
|
||||||
|
- fontawesome_markdown
|
||||||
|
|
||||||
|
copyright: Copyright © 2024 Kenji Koide
|
||||||
|
extra:
|
||||||
|
social:
|
||||||
|
- icon: material/home
|
||||||
|
link: https://staff.aist.go.jp/k.koide/
|
||||||
|
- icon: fontawesome/brands/github
|
||||||
|
link: https://github.com/koide3/small_gicp
|
||||||
|
- icon: fontawesome/brands/twitter
|
||||||
|
link: https://twitter.com/k_koide3
|
||||||
|
|
||||||
|
extra_css:
|
||||||
|
- "css/custom.css"
|
||||||
|
- "https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css"
|
||||||
|
|
||||||
|
nav:
|
||||||
|
- 'index.md'
|
||||||
|
|
@ -20,12 +20,12 @@ using namespace small_gicp;
|
||||||
|
|
||||||
void define_factors(py::module& m) {
|
void define_factors(py::module& m) {
|
||||||
// DistanceRejector
|
// DistanceRejector
|
||||||
py::class_<DistanceRejector>(m, "DistanceRejector") //
|
py::class_<DistanceRejector>(m, "DistanceRejector", "Correspondence rejection based on the distance between points.")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("set_max_distance", [](DistanceRejector& rejector, double dist) { rejector.max_dist_sq = dist * dist; });
|
.def("set_max_distance", [](DistanceRejector& rejector, double dist) { rejector.max_dist_sq = dist * dist; }, py::arg("dist"), "Set the maximum distance.");
|
||||||
|
|
||||||
// ICPFactor
|
// ICPFactor
|
||||||
py::class_<ICPFactor>(m, "ICPFactor") //
|
py::class_<ICPFactor>(m, "ICPFactor", "ICP per-point factor")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def(
|
.def(
|
||||||
"linearize",
|
"linearize",
|
||||||
|
|
@ -42,10 +42,17 @@ void define_factors(py::module& m) {
|
||||||
double e = 0.0;
|
double e = 0.0;
|
||||||
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
||||||
return std::make_tuple(succ, H, b, e);
|
return std::make_tuple(succ, H, b, e);
|
||||||
});
|
},
|
||||||
|
py::arg("target"),
|
||||||
|
py::arg("source"),
|
||||||
|
py::arg("kdtree"),
|
||||||
|
py::arg("T"),
|
||||||
|
py::arg("source_index"),
|
||||||
|
py::arg("rejector"),
|
||||||
|
"Linearize the factor. Returns a tuple of success, Hessian, gradient, and error.");
|
||||||
|
|
||||||
// PointToPlaneICPFactor
|
// PointToPlaneICPFactor
|
||||||
py::class_<PointToPlaneICPFactor>(m, "PointToPlaneICPFactor") //
|
py::class_<PointToPlaneICPFactor>(m, "PointToPlaneICPFactor", "Point-to-plane ICP per-point factor")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def(
|
.def(
|
||||||
"linearize",
|
"linearize",
|
||||||
|
|
@ -62,10 +69,17 @@ void define_factors(py::module& m) {
|
||||||
double e = 0.0;
|
double e = 0.0;
|
||||||
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
||||||
return std::make_tuple(succ, H, b, e);
|
return std::make_tuple(succ, H, b, e);
|
||||||
});
|
},
|
||||||
|
py::arg("target"),
|
||||||
|
py::arg("source"),
|
||||||
|
py::arg("kdtree"),
|
||||||
|
py::arg("T"),
|
||||||
|
py::arg("source_index"),
|
||||||
|
py::arg("rejector"),
|
||||||
|
"Linearize the factor. Returns a tuple of success, Hessian, gradient, and error.");
|
||||||
|
|
||||||
// GICPFactor
|
// GICPFactor
|
||||||
py::class_<GICPFactor>(m, "GICPFactor") //
|
py::class_<GICPFactor>(m, "GICPFactor", "Generalized ICP per-point factor") //
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def(
|
.def(
|
||||||
"linearize",
|
"linearize",
|
||||||
|
|
@ -82,5 +96,12 @@ void define_factors(py::module& m) {
|
||||||
double e = 0.0;
|
double e = 0.0;
|
||||||
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
bool succ = factor.linearize(target, source, kdtree, Eigen::Isometry3d(T), source_index, rejector, &H, &b, &e);
|
||||||
return std::make_tuple(succ, H, b, e);
|
return std::make_tuple(succ, H, b, e);
|
||||||
});
|
},
|
||||||
|
py::arg("target"),
|
||||||
|
py::arg("source"),
|
||||||
|
py::arg("kdtree"),
|
||||||
|
py::arg("T"),
|
||||||
|
py::arg("source_index"),
|
||||||
|
py::arg("rejector"),
|
||||||
|
"Linearize the factor. Returns a tuple of success, Hessian, gradient, and error.");
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ using namespace small_gicp;
|
||||||
|
|
||||||
void define_kdtree(py::module& m) {
|
void define_kdtree(py::module& m) {
|
||||||
// KdTree
|
// KdTree
|
||||||
py::class_<KdTree<PointCloud>, std::shared_ptr<KdTree<PointCloud>>>(m, "KdTree") //
|
py::class_<KdTree<PointCloud>, std::shared_ptr<KdTree<PointCloud>>>(m, "KdTree", "KdTree") //
|
||||||
.def(
|
.def(
|
||||||
py::init([](const PointCloud::ConstPtr& points, int num_threads) { return std::make_shared<KdTree<PointCloud>>(points, KdTreeBuilderOMP(num_threads)); }),
|
py::init([](const PointCloud::ConstPtr& points, int num_threads) { return std::make_shared<KdTree<PointCloud>>(points, KdTreeBuilderOMP(num_threads)); }),
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
|
|
@ -28,11 +28,18 @@ void define_kdtree(py::module& m) {
|
||||||
double k_sq_dist = std::numeric_limits<double>::max();
|
double k_sq_dist = std::numeric_limits<double>::max();
|
||||||
const size_t found = traits::nearest_neighbor_search(kdtree, Eigen::Vector4d(pt.x(), pt.y(), pt.z(), 1.0), &k_index, &k_sq_dist);
|
const size_t found = traits::nearest_neighbor_search(kdtree, Eigen::Vector4d(pt.x(), pt.y(), pt.z(), 1.0), &k_index, &k_sq_dist);
|
||||||
return std::make_tuple(found, k_index, k_sq_dist);
|
return std::make_tuple(found, k_index, k_sq_dist);
|
||||||
})
|
},
|
||||||
.def("knn_search", [](const KdTree<PointCloud>& kdtree, const Eigen::Vector3d& pt, int k) {
|
py::arg("pt"),
|
||||||
|
"Search the nearest neighbor. Returns a tuple of found flag, index, and squared distance.")
|
||||||
|
.def(
|
||||||
|
"knn_search",
|
||||||
|
[](const KdTree<PointCloud>& kdtree, const Eigen::Vector3d& pt, int k) {
|
||||||
std::vector<size_t> k_indices(k, -1);
|
std::vector<size_t> k_indices(k, -1);
|
||||||
std::vector<double> k_sq_dists(k, std::numeric_limits<double>::max());
|
std::vector<double> k_sq_dists(k, std::numeric_limits<double>::max());
|
||||||
const size_t found = traits::knn_search(kdtree, Eigen::Vector4d(pt.x(), pt.y(), pt.z(), 1.0), k, k_indices.data(), k_sq_dists.data());
|
const size_t found = traits::knn_search(kdtree, Eigen::Vector4d(pt.x(), pt.y(), pt.z(), 1.0), k, k_indices.data(), k_sq_dists.data());
|
||||||
return std::make_pair(k_indices, k_sq_dists);
|
return std::make_pair(k_indices, k_sq_dists);
|
||||||
});
|
},
|
||||||
|
py::arg("pt"),
|
||||||
|
py::arg("k"),
|
||||||
|
"Search the k-nearest neighbors. Returns a pair of indices and squared distances.");
|
||||||
}
|
}
|
||||||
|
|
@ -38,16 +38,29 @@ void define_pointcloud(py::module& m) {
|
||||||
})) //
|
})) //
|
||||||
.def("__repr__", [](const PointCloud& points) { return "small_gicp.PointCloud (" + std::to_string(points.size()) + " points)"; })
|
.def("__repr__", [](const PointCloud& points) { return "small_gicp.PointCloud (" + std::to_string(points.size()) + " points)"; })
|
||||||
.def("__len__", [](const PointCloud& points) { return points.size(); })
|
.def("__len__", [](const PointCloud& points) { return points.size(); })
|
||||||
.def("empty", &PointCloud::empty)
|
.def("empty", &PointCloud::empty, "Check if the point cloud is empty.")
|
||||||
.def("size", &PointCloud::size)
|
.def("size", &PointCloud::size, "Get the number of points.")
|
||||||
.def(
|
.def(
|
||||||
"points",
|
"points",
|
||||||
[](const PointCloud& points) -> Eigen::MatrixXd { return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points.points[0].data(), points.size(), 4); })
|
[](const PointCloud& points) -> Eigen::MatrixXd { return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points.points[0].data(), points.size(), 4); },
|
||||||
|
"Get the points as a Nx4 matrix.")
|
||||||
.def(
|
.def(
|
||||||
"normals",
|
"normals",
|
||||||
[](const PointCloud& points) -> Eigen::MatrixXd { return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points.normals[0].data(), points.size(), 4); })
|
[](const PointCloud& points) -> Eigen::MatrixXd { return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points.normals[0].data(), points.size(), 4); },
|
||||||
.def("covs", [](const PointCloud& points) { return points.covs; })
|
"Get the normals as a Nx4 matrix.")
|
||||||
.def("point", [](const PointCloud& points, size_t i) -> Eigen::Vector4d { return points.point(i); })
|
.def(
|
||||||
.def("normal", [](const PointCloud& points, size_t i) -> Eigen::Vector4d { return points.normal(i); })
|
"covs",
|
||||||
.def("cov", [](const PointCloud& points, size_t i) -> Eigen::Matrix4d { return points.cov(i); });
|
[](const PointCloud& points) { return points.covs; },
|
||||||
|
"Get the covariance matrices.")
|
||||||
|
.def(
|
||||||
|
"point",
|
||||||
|
[](const PointCloud& points, size_t i) -> Eigen::Vector4d { return points.point(i); },
|
||||||
|
py::arg("i"),
|
||||||
|
"Get the i-th point.")
|
||||||
|
.def(
|
||||||
|
"normal",
|
||||||
|
[](const PointCloud& points, size_t i) -> Eigen::Vector4d { return points.normal(i); },
|
||||||
|
py::arg("i"),
|
||||||
|
"Get the i-th normal.")
|
||||||
|
.def("cov", [](const PointCloud& points, size_t i) -> Eigen::Matrix4d { return points.cov(i); }, py::arg("i"), "Get the i-th covariance matrix.");
|
||||||
}
|
}
|
||||||
|
|
@ -29,10 +29,26 @@ void define_preprocess(py::module& m) {
|
||||||
}
|
}
|
||||||
return voxelgrid_sampling_omp(points, resolution, num_threads);
|
return voxelgrid_sampling_omp(points, resolution, num_threads);
|
||||||
},
|
},
|
||||||
"Voxelgrid sampling",
|
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("downsampling_resolution"),
|
py::arg("downsampling_resolution"),
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Voxelgrid downsampling.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : PointCloud
|
||||||
|
Input point cloud.
|
||||||
|
resolution : float
|
||||||
|
Voxel size.
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
PointCloud
|
||||||
|
Downsampled point cloud.
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// voxelgrid_sampling (numpy)
|
// voxelgrid_sampling (numpy)
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -49,10 +65,26 @@ void define_preprocess(py::module& m) {
|
||||||
return voxelgrid_sampling_omp<Eigen::MatrixXd, PointCloud>(points, resolution, num_threads);
|
return voxelgrid_sampling_omp<Eigen::MatrixXd, PointCloud>(points, resolution, num_threads);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Voxelgrid sampling",
|
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("downsampling_resolution"),
|
py::arg("downsampling_resolution"),
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Voxelgrid downsampling.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : [np.float64]
|
||||||
|
Input point cloud. Nx3 or Nx4.
|
||||||
|
resolution : float
|
||||||
|
Voxel size.
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
PointCloud
|
||||||
|
Downsampled point cloud.
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// estimate_normals
|
// estimate_normals
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -71,7 +103,21 @@ void define_preprocess(py::module& m) {
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("tree") = nullptr,
|
py::arg("tree") = nullptr,
|
||||||
py::arg("num_neighbors") = 20,
|
py::arg("num_neighbors") = 20,
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Estimate point normals.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : PointCloud
|
||||||
|
Input point cloud. Normals will be estimated in-place. (in/out)
|
||||||
|
tree : KdTree, optional
|
||||||
|
Nearest neighbor search. If None, create a new KdTree (default: None)
|
||||||
|
num_neighbors : int, optional
|
||||||
|
Number of neighbors. (default: 20)
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// estimate_covariances
|
// estimate_covariances
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -90,7 +136,21 @@ void define_preprocess(py::module& m) {
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("tree") = nullptr,
|
py::arg("tree") = nullptr,
|
||||||
py::arg("num_neighbors") = 20,
|
py::arg("num_neighbors") = 20,
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Estimate point covariances.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : PointCloud
|
||||||
|
Input point cloud. Covariances will be estimated in-place. (in/out)
|
||||||
|
tree : KdTree, optional
|
||||||
|
Nearest neighbor search. If None, create a new KdTree (default: None)
|
||||||
|
num_neighbors : int, optional
|
||||||
|
Number of neighbors. (default: 20)
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// estimate_normals_covariances
|
// estimate_normals_covariances
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -109,7 +169,21 @@ void define_preprocess(py::module& m) {
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("tree") = nullptr,
|
py::arg("tree") = nullptr,
|
||||||
py::arg("num_neighbors") = 20,
|
py::arg("num_neighbors") = 20,
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Estimate point normals and covariances.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : PointCloud
|
||||||
|
Input point cloud. Normals and covariances will be estimated in-place. (in/out)
|
||||||
|
tree : KdTree, optional
|
||||||
|
Nearest neighbor search. If None, create a new KdTree (default: None)
|
||||||
|
num_neighbors : int, optional
|
||||||
|
Number of neighbors. (default: 20)
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// preprocess_points (numpy)
|
// preprocess_points (numpy)
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -138,7 +212,28 @@ void define_preprocess(py::module& m) {
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("downsampling_resolution") = 0.25,
|
py::arg("downsampling_resolution") = 0.25,
|
||||||
py::arg("num_neighbors") = 10,
|
py::arg("num_neighbors") = 10,
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Preprocess point cloud (Downsampling and normal/covariance estimation).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : [np.float64]
|
||||||
|
Input point cloud. Nx3 or Nx4.
|
||||||
|
downsampling_resolution : float, optional
|
||||||
|
Resolution for downsampling the point clouds. (default: 0.25)
|
||||||
|
num_neighbors : int, optional
|
||||||
|
Number of neighbors used for attribute estimation. (default: 10)
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
PointCloud
|
||||||
|
Downsampled point cloud.
|
||||||
|
KdTree
|
||||||
|
KdTree for the downsampled point cloud.
|
||||||
|
)pbdoc");
|
||||||
|
|
||||||
// preprocess_points
|
// preprocess_points
|
||||||
m.def(
|
m.def(
|
||||||
|
|
@ -157,5 +252,26 @@ void define_preprocess(py::module& m) {
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("downsampling_resolution") = 0.25,
|
py::arg("downsampling_resolution") = 0.25,
|
||||||
py::arg("num_neighbors") = 10,
|
py::arg("num_neighbors") = 10,
|
||||||
py::arg("num_threads") = 1);
|
py::arg("num_threads") = 1,
|
||||||
|
R"pbdoc(
|
||||||
|
Preprocess point cloud (Downsampling and normal/covariance estimation).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
points : PointCloud
|
||||||
|
Input point cloud.
|
||||||
|
downsampling_resolution : float, optional
|
||||||
|
Resolution for downsampling the point clouds. (default: 0.25)
|
||||||
|
num_neighbors : int, optional
|
||||||
|
Number of neighbors used for attribute estimation. (default: 10)
|
||||||
|
num_threads : int, optional
|
||||||
|
Number of threads. (default: 1)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
PointCloud
|
||||||
|
Downsampled point cloud.
|
||||||
|
KdTree
|
||||||
|
KdTree for the downsampled point cloud.
|
||||||
|
)pbdoc");
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ void define_factors(py::module& m);
|
||||||
void define_misc(py::module& m);
|
void define_misc(py::module& m);
|
||||||
|
|
||||||
PYBIND11_MODULE(small_gicp, m) {
|
PYBIND11_MODULE(small_gicp, m) {
|
||||||
m.doc() = "Small GICP";
|
m.doc() = "Efficient and parallel algorithms for point cloud registration";
|
||||||
|
|
||||||
define_pointcloud(m);
|
define_pointcloud(m);
|
||||||
define_kdtree(m);
|
define_kdtree(m);
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,14 @@ void define_result(py::module& m) {
|
||||||
sst << "error= " << result.error << "\n";
|
sst << "error= " << result.error << "\n";
|
||||||
return sst.str();
|
return sst.str();
|
||||||
})
|
})
|
||||||
.def_property_readonly("T_target_source", [](const RegistrationResult& result) -> Eigen::Matrix4d { return result.T_target_source.matrix(); })
|
.def_property_readonly(
|
||||||
.def_readonly("converged", &RegistrationResult::converged)
|
"T_target_source",
|
||||||
.def_readonly("iterations", &RegistrationResult::iterations)
|
[](const RegistrationResult& result) -> Eigen::Matrix4d { return result.T_target_source.matrix(); },
|
||||||
.def_readonly("num_inliers", &RegistrationResult::num_inliers)
|
"Final transformation matrix")
|
||||||
.def_readonly("H", &RegistrationResult::H)
|
.def_readonly("converged", &RegistrationResult::converged, "Convergence flag")
|
||||||
.def_readonly("b", &RegistrationResult::b)
|
.def_readonly("iterations", &RegistrationResult::iterations, "Number of iterations")
|
||||||
.def_readonly("error", &RegistrationResult::error);
|
.def_readonly("num_inliers", &RegistrationResult::num_inliers, "Number of inliers")
|
||||||
|
.def_readonly("H", &RegistrationResult::H, "Final Hessian matrix")
|
||||||
|
.def_readonly("b", &RegistrationResult::b, "Final information vector")
|
||||||
|
.def_readonly("error", &RegistrationResult::error, "Final error");
|
||||||
}
|
}
|
||||||
|
|
@ -27,12 +27,13 @@ auto define_class(py::module& m, const std::string& name) {
|
||||||
return sst.str();
|
return sst.str();
|
||||||
})
|
})
|
||||||
.def("__len__", [](const VoxelMap& voxelmap) { return voxelmap.size(); })
|
.def("__len__", [](const VoxelMap& voxelmap) { return voxelmap.size(); })
|
||||||
.def("size", &VoxelMap::size)
|
.def("size", &VoxelMap::size, "Get the number of voxels.")
|
||||||
.def(
|
.def(
|
||||||
"insert",
|
"insert",
|
||||||
[](VoxelMap& voxelmap, const PointCloud& points, const Eigen::Matrix4d& T) { voxelmap.insert(points, Eigen::Isometry3d(T)); },
|
[](VoxelMap& voxelmap, const PointCloud& points, const Eigen::Matrix4d& T) { voxelmap.insert(points, Eigen::Isometry3d(T)); },
|
||||||
py::arg("points"),
|
py::arg("points"),
|
||||||
py::arg("T") = Eigen::Matrix4d::Identity())
|
py::arg("T") = Eigen::Matrix4d::Identity(),
|
||||||
|
"Insert a point cloud.")
|
||||||
.def(
|
.def(
|
||||||
"set_lru",
|
"set_lru",
|
||||||
[](VoxelMap& voxelmap, size_t horizon, size_t clear_cycle) {
|
[](VoxelMap& voxelmap, size_t horizon, size_t clear_cycle) {
|
||||||
|
|
@ -40,24 +41,34 @@ auto define_class(py::module& m, const std::string& name) {
|
||||||
voxelmap.lru_clear_cycle = clear_cycle;
|
voxelmap.lru_clear_cycle = clear_cycle;
|
||||||
},
|
},
|
||||||
py::arg("horizon") = 100,
|
py::arg("horizon") = 100,
|
||||||
py::arg("clear_cycle") = 10)
|
py::arg("clear_cycle") = 10,
|
||||||
.def("voxel_points", [](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
"Set the LRU cache parameters.")
|
||||||
|
.def(
|
||||||
|
"voxel_points",
|
||||||
|
[](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
||||||
auto points = traits::voxel_points(voxelmap);
|
auto points = traits::voxel_points(voxelmap);
|
||||||
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points[0].data(), points.size(), 4);
|
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(points[0].data(), points.size(), 4);
|
||||||
});
|
},
|
||||||
|
"Get the voxel points.");
|
||||||
|
|
||||||
if constexpr (has_normals) {
|
if constexpr (has_normals) {
|
||||||
vox.def("voxel_normals", [](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
vox.def(
|
||||||
|
"voxel_normals",
|
||||||
|
[](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
||||||
auto normals = traits::voxel_normals(voxelmap);
|
auto normals = traits::voxel_normals(voxelmap);
|
||||||
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(normals[0].data(), normals.size(), 4);
|
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(normals[0].data(), normals.size(), 4);
|
||||||
});
|
},
|
||||||
|
"Get the voxel normals.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (has_covs) {
|
if constexpr (has_covs) {
|
||||||
vox.def("voxel_covs", [](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
vox.def(
|
||||||
|
"voxel_covs",
|
||||||
|
[](const VoxelMap& voxelmap) -> Eigen::MatrixXd {
|
||||||
auto covs = traits::voxel_covs(voxelmap);
|
auto covs = traits::voxel_covs(voxelmap);
|
||||||
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(covs[0].data(), covs.size(), 16);
|
return Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(covs[0].data(), covs.size(), 16);
|
||||||
});
|
},
|
||||||
|
"Get the voxel covariance matrices.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue