Using libpointmatcher with Python
This tutorial presents the different things to know before using pypointmatcher, the libpointmatcher's Python module.
Differences between the C++ and Python APIs
Despite the fact that pypointmatcher and libpointmatcher have very similar APIs, the fact remains that they differ in some ways. So, why not start by listing these differences.
STL containers vs Python data structures
pybind11 provides automatic conversion between C++'s STL containers and their Python equivalent data structures. That is,
std::array are converted into a Python
std::unordered_set are converted into a Python
set and finally
std::unordered_map are converted into a Python
Although this can be very useful, it comes with some major downsides, which you can see here, hence the need to make the classes inheriting from STL containers and some
typedef "opaque". For the moment, only the
std::vector and the
std::map containers are made "opaque", i.e. they keep the same name as the one used in libpointmatcher, but they adopt the behavior of a
list and a
Note: This also means that these opaque STL containers must be used in constructors and methods that accept one of these types as parameter.
For more information about pybind11 STL containers conversion, visit this section of the official documentation.
Eigen vs Numpy
pybind11 also provides transparent conversion between Eigen's
SparseMatrix and numpy's
ndarray data types. That is, you can seamlessly use numpy's
ndarray instead of Eigen's
For more information about pybind11 Eigen to numpy data type conversion, visit this section of the official documentation.
Overloaded methods based on constness
In libpointmatcher, more precisely in the
DataPoints class, some methods are overloaded based on constness, i.e. they will be called with a constant
DataPoints. So, to avoid ambiguous calls, the suffix
_const has been appended to the method names. E.g. in the
compute_overlap.py example, the
getDescriptorViewByName("inliers") method was calling the
const version before this fix. For more information on pybind11 overloaded method mechanisms, visit this section of the official documentation.
Contructors/methods with std::istream or std::ostream as paramater
Some constructors and methods of libpointmatcher have as parameter either an
std::istream to build an object from a YAML configuration file or an
std::ostream to dump information. pybind11 doesn't allow to call these constructors/methods with their Python equivalent, i.e.
sys.stdout. So, to get around this problem, the constructors/methods having a
std::istream as parameter must be used with a
std::string instead and those having a
std::ostream must be used without parameter.
Structure of pypointmatcher
Before going further, here is the general structure of pypointmatcher to give you a better idea of how to use it.
pypointmatcher # The main module. | |_ pointmatcher # The submodule containing functions and classes that are dependent on scalar types. | |_ pointmatchersupport # The submodule containing everything defined in the | # pointmatchersupport namespace, i.e. functions and classes which are not dependent on scalar types. | |_ datapointsfilters # The submodule containing the differents DataPointsFilters. | |_ errorminimizers # The submodule containing the differents ErrorMinimizers.
General use of pypointmatcher
To help you get familiar with pypointmatcher, some C++ examples have been translated to show you how it is possible to use the Python version of libpointmatcher.
Now that you know the major differences between the C++ and Python API, we suggest newcomers and those who are less familiar with the library to follow, or re-follow, the tutorials in the beginner and advanced sections using the Python examples instead, in order to have a better understanding of how libpointmatcher can be used with Python.
Experienced users of libpointmatcher can, if they wish, take a look at the different Python examples located in the
examples/python/ directory and compare their uses with their C++ counterparts, keeping in mind what makes them different from each other.
The major difference is that they don't require command line arguments like the C++ version. All you have to do is open a terminal and go to the
examples/python/ directory and run one of the examples as a Python module script:
Note: All the information to run a default ICP algorithm is already in the examples, it is up to the user to change these values in order to run a custom ICP algorithm. So take the time to understand what the code does in the examples before making changes.