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::vector
/std::deque
/std::list
/std::array
are converted into a Python list
, std::set
/std::unordered_set
are converted into a Python set
and finally std::map
/std::unordered_map
are converted into a Python dict
.
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 dict
respectively.
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 Matrix
, Map
and SparseMatrix
and numpy’s array
and ndarray
data types. That is, you can seamlessly use numpy’s ndarray
instead of Eigen’s Vector
or Matrix
.
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.stdin
and 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:
python3 icp_simple.py
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.