From 3e6227b1378d574d8c823a2c1fb85f87fe7987c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Gu=C3=A9nette?= Date: Thu, 6 Aug 2020 17:18:11 -0400 Subject: [PATCH 01/28] Adding libpointmatcher's Python bindings --- CMakeLists.txt | 9 +- examples/python/icp.py | 56 ++++++ examples/python/icp_advance_api.py | 134 +++++++++++++ examples/python/icp_customized.py | 128 +++++++++++++ examples/python/icp_simple.py | 33 ++++ examples/python/utils.py | 35 ++++ python/CMakeLists.txt | 112 +++++++++++ python/datapointsfilters/boundingbox.cpp | 27 +++ python/datapointsfilters/boundingbox.h | 12 ++ .../datapointsfilters/covariancesampling.cpp | 31 +++ python/datapointsfilters/covariancesampling.h | 12 ++ .../cutatdescriptorthreshold.cpp | 22 +++ .../cutatdescriptorthreshold.h | 12 ++ python/datapointsfilters/distancelimit.cpp | 22 +++ python/datapointsfilters/distancelimit.h | 12 ++ python/datapointsfilters/ellipsoids.cpp | 37 ++++ python/datapointsfilters/ellipsoids.h | 12 ++ python/datapointsfilters/fixstepsampling.cpp | 23 +++ python/datapointsfilters/fixstepsampling.h | 12 ++ python/datapointsfilters/gestalt.cpp | 37 ++++ python/datapointsfilters/gestalt.h | 12 ++ python/datapointsfilters/identity.cpp | 17 ++ python/datapointsfilters/identity.h | 12 ++ python/datapointsfilters/incidenceangle.cpp | 17 ++ python/datapointsfilters/incidenceangle.h | 12 ++ python/datapointsfilters/maxdensity.cpp | 20 ++ python/datapointsfilters/maxdensity.h | 12 ++ python/datapointsfilters/maxpointcount.cpp | 21 +++ python/datapointsfilters/maxpointcount.h | 12 ++ .../datapointsfilters/maxquantileonaxis.cpp | 21 +++ python/datapointsfilters/maxquantileonaxis.h | 12 ++ python/datapointsfilters/normalspace.cpp | 22 +++ python/datapointsfilters/normalspace.h | 12 ++ .../observationdirection.cpp | 22 +++ .../datapointsfilters/observationdirection.h | 12 ++ python/datapointsfilters/octreegrid.cpp | 79 ++++++++ python/datapointsfilters/octreegrid.h | 12 ++ python/datapointsfilters/orientnormals.cpp | 21 +++ python/datapointsfilters/orientnormals.h | 12 ++ python/datapointsfilters/randomsampling.cpp | 21 +++ python/datapointsfilters/randomsampling.h | 12 ++ python/datapointsfilters/removenan.cpp | 18 ++ python/datapointsfilters/removenan.h | 12 ++ python/datapointsfilters/removesensorbias.cpp | 19 ++ python/datapointsfilters/removesensorbias.h | 12 ++ .../samplingsurfacenormal.cpp | 29 +++ .../datapointsfilters/samplingsurfacenormal.h | 12 ++ python/datapointsfilters/shadow.cpp | 21 +++ python/datapointsfilters/shadow.h | 12 ++ .../datapointsfilters/simplesensornoise.cpp | 22 +++ python/datapointsfilters/simplesensornoise.h | 12 ++ python/datapointsfilters/sphericality.cpp | 22 +++ python/datapointsfilters/sphericality.h | 12 ++ python/datapointsfilters/surfacenormal.cpp | 31 +++ python/datapointsfilters/surfacenormal.h | 12 ++ python/errorminimizers/identity.cpp | 13 ++ python/errorminimizers/identity.h | 12 ++ python/errorminimizers/pointtoplane.cpp | 26 +++ python/errorminimizers/pointtoplane.h | 12 ++ .../errorminimizers/pointtoplanewithcov.cpp | 24 +++ python/errorminimizers/pointtoplanewithcov.h | 12 ++ python/errorminimizers/pointtopoint.cpp | 18 ++ python/errorminimizers/pointtopoint.h | 12 ++ .../pointtopointsimilarity.cpp | 16 ++ .../errorminimizers/pointtopointsimilarity.h | 12 ++ .../errorminimizers/pointtopointwithcov.cpp | 19 ++ python/errorminimizers/pointtopointwithcov.h | 12 ++ python/modules/datapointsfilters_module.cpp | 59 ++++++ python/modules/datapointsfilters_module.h | 11 ++ python/modules/errorminimizers_module.cpp | 23 +++ python/modules/errorminimizers_module.h | 11 ++ python/modules/pointmatcher_module.cpp | 13 ++ python/modules/pointmatcher_module.h | 13 ++ python/modules/pointmatchersupport_module.cpp | 41 ++++ python/modules/pointmatchersupport_module.h | 14 ++ python/pointmatcher/datapoints.cpp | 177 ++++++++++++++++++ python/pointmatcher/datapoints.h | 11 ++ python/pointmatcher/datapointsfilter.cpp | 14 ++ python/pointmatcher/datapointsfilter.h | 11 ++ python/pointmatcher/datapointsfilters.cpp | 22 +++ python/pointmatcher/datapointsfilters.h | 11 ++ python/pointmatcher/errorminimizer.cpp | 42 +++++ python/pointmatcher/errorminimizer.h | 11 ++ python/pointmatcher/icp.cpp | 14 ++ python/pointmatcher/icp.h | 11 ++ python/pointmatcher/icpchainbase.cpp | 32 ++++ python/pointmatcher/icpchainbase.h | 11 ++ python/pointmatcher/icpsequence.cpp | 33 ++++ python/pointmatcher/icpsequence.h | 11 ++ python/pointmatcher/impl.cpp | 19 ++ python/pointmatcher/impl.h | 11 ++ python/pointmatcher/impls/inspectors_impl.cpp | 66 +++++++ python/pointmatcher/impls/inspectors_impl.h | 11 ++ python/pointmatcher/impls/matchers_impl.cpp | 46 +++++ python/pointmatcher/impls/matchers_impl.h | 12 ++ .../impls/outlierfilters_impl.cpp | 104 ++++++++++ .../pointmatcher/impls/outlierfilters_impl.h | 12 ++ .../impls/transformationcheckers_impl.cpp | 50 +++++ .../impls/transformationcheckers_impl.h | 12 ++ .../impls/transformations_impl.cpp | 34 ++++ .../pointmatcher/impls/transformations_impl.h | 17 ++ python/pointmatcher/inspector.cpp | 33 ++++ python/pointmatcher/inspector.h | 11 ++ python/pointmatcher/matcher.cpp | 13 ++ python/pointmatcher/matcher.h | 11 ++ python/pointmatcher/matches.cpp | 34 ++++ python/pointmatcher/matches.h | 11 ++ python/pointmatcher/outlierfilter.cpp | 17 ++ python/pointmatcher/outlierfilter.h | 11 ++ python/pointmatcher/outlierfilters.cpp | 14 ++ python/pointmatcher/outlierfilters.h | 11 ++ python/pointmatcher/pointmatcher.cpp | 62 ++++++ python/pointmatcher/pointmatcher.h | 11 ++ python/pointmatcher/transformation.cpp | 10 + python/pointmatcher/transformation.h | 11 ++ python/pointmatcher/transformationchecker.cpp | 21 +++ python/pointmatcher/transformationchecker.h | 11 ++ .../pointmatcher/transformationcheckers.cpp | 14 ++ python/pointmatcher/transformationcheckers.h | 11 ++ python/pointmatcher/transformations.cpp | 13 ++ python/pointmatcher/transformations.h | 11 ++ python/pointmatchersupport/bibliography.cpp | 32 ++++ python/pointmatchersupport/bibliography.h | 13 ++ python/pointmatchersupport/logger.cpp | 21 +++ python/pointmatchersupport/logger.h | 11 ++ python/pointmatchersupport/logger_impl.cpp | 35 ++++ python/pointmatchersupport/logger_impl.h | 11 ++ python/pointmatchersupport/parametrizable.cpp | 67 +++++++ python/pointmatchersupport/parametrizable.h | 11 ++ python/pointmatchersupport/registrar.cpp | 24 +++ python/pointmatchersupport/registrar.h | 11 ++ .../registrars/datapointsfilter_registrar.cpp | 18 ++ .../registrars/datapointsfilter_registrar.h | 11 ++ .../registrars/errorminimizer_registrar.cpp | 18 ++ .../registrars/errorminimizer_registrar.h | 11 ++ .../registrars/inspector_registrar.cpp | 18 ++ .../registrars/inspector_registrar.h | 11 ++ .../registrars/logger_registrar.cpp | 18 ++ .../registrars/logger_registrar.h | 11 ++ .../registrars/matcher_registrar.cpp | 18 ++ .../registrars/matcher_registrar.h | 10 + .../registrars/outlierfilter_registrar.cpp | 18 ++ .../registrars/outlierfilter_registrar.h | 11 ++ .../registrars/transformation_registrar.cpp | 18 ++ .../registrars/transformation_registrar.h | 11 ++ .../transformationchecker_registrar.cpp | 18 ++ .../transformationchecker_registrar.h | 11 ++ python/pypointmatcher.cpp | 16 ++ python/pypointmatcher_helper.h | 76 ++++++++ 149 files changed, 3494 insertions(+), 1 deletion(-) create mode 100644 examples/python/icp.py create mode 100644 examples/python/icp_advance_api.py create mode 100644 examples/python/icp_customized.py create mode 100644 examples/python/icp_simple.py create mode 100644 examples/python/utils.py create mode 100644 python/CMakeLists.txt create mode 100644 python/datapointsfilters/boundingbox.cpp create mode 100644 python/datapointsfilters/boundingbox.h create mode 100644 python/datapointsfilters/covariancesampling.cpp create mode 100644 python/datapointsfilters/covariancesampling.h create mode 100644 python/datapointsfilters/cutatdescriptorthreshold.cpp create mode 100644 python/datapointsfilters/cutatdescriptorthreshold.h create mode 100644 python/datapointsfilters/distancelimit.cpp create mode 100644 python/datapointsfilters/distancelimit.h create mode 100644 python/datapointsfilters/ellipsoids.cpp create mode 100644 python/datapointsfilters/ellipsoids.h create mode 100644 python/datapointsfilters/fixstepsampling.cpp create mode 100644 python/datapointsfilters/fixstepsampling.h create mode 100644 python/datapointsfilters/gestalt.cpp create mode 100644 python/datapointsfilters/gestalt.h create mode 100644 python/datapointsfilters/identity.cpp create mode 100644 python/datapointsfilters/identity.h create mode 100644 python/datapointsfilters/incidenceangle.cpp create mode 100644 python/datapointsfilters/incidenceangle.h create mode 100644 python/datapointsfilters/maxdensity.cpp create mode 100644 python/datapointsfilters/maxdensity.h create mode 100644 python/datapointsfilters/maxpointcount.cpp create mode 100644 python/datapointsfilters/maxpointcount.h create mode 100644 python/datapointsfilters/maxquantileonaxis.cpp create mode 100644 python/datapointsfilters/maxquantileonaxis.h create mode 100644 python/datapointsfilters/normalspace.cpp create mode 100644 python/datapointsfilters/normalspace.h create mode 100644 python/datapointsfilters/observationdirection.cpp create mode 100644 python/datapointsfilters/observationdirection.h create mode 100644 python/datapointsfilters/octreegrid.cpp create mode 100644 python/datapointsfilters/octreegrid.h create mode 100644 python/datapointsfilters/orientnormals.cpp create mode 100644 python/datapointsfilters/orientnormals.h create mode 100644 python/datapointsfilters/randomsampling.cpp create mode 100644 python/datapointsfilters/randomsampling.h create mode 100644 python/datapointsfilters/removenan.cpp create mode 100644 python/datapointsfilters/removenan.h create mode 100644 python/datapointsfilters/removesensorbias.cpp create mode 100644 python/datapointsfilters/removesensorbias.h create mode 100644 python/datapointsfilters/samplingsurfacenormal.cpp create mode 100644 python/datapointsfilters/samplingsurfacenormal.h create mode 100644 python/datapointsfilters/shadow.cpp create mode 100644 python/datapointsfilters/shadow.h create mode 100644 python/datapointsfilters/simplesensornoise.cpp create mode 100644 python/datapointsfilters/simplesensornoise.h create mode 100644 python/datapointsfilters/sphericality.cpp create mode 100644 python/datapointsfilters/sphericality.h create mode 100644 python/datapointsfilters/surfacenormal.cpp create mode 100644 python/datapointsfilters/surfacenormal.h create mode 100644 python/errorminimizers/identity.cpp create mode 100644 python/errorminimizers/identity.h create mode 100644 python/errorminimizers/pointtoplane.cpp create mode 100644 python/errorminimizers/pointtoplane.h create mode 100644 python/errorminimizers/pointtoplanewithcov.cpp create mode 100644 python/errorminimizers/pointtoplanewithcov.h create mode 100644 python/errorminimizers/pointtopoint.cpp create mode 100644 python/errorminimizers/pointtopoint.h create mode 100644 python/errorminimizers/pointtopointsimilarity.cpp create mode 100644 python/errorminimizers/pointtopointsimilarity.h create mode 100644 python/errorminimizers/pointtopointwithcov.cpp create mode 100644 python/errorminimizers/pointtopointwithcov.h create mode 100644 python/modules/datapointsfilters_module.cpp create mode 100644 python/modules/datapointsfilters_module.h create mode 100644 python/modules/errorminimizers_module.cpp create mode 100644 python/modules/errorminimizers_module.h create mode 100644 python/modules/pointmatcher_module.cpp create mode 100644 python/modules/pointmatcher_module.h create mode 100644 python/modules/pointmatchersupport_module.cpp create mode 100644 python/modules/pointmatchersupport_module.h create mode 100644 python/pointmatcher/datapoints.cpp create mode 100644 python/pointmatcher/datapoints.h create mode 100644 python/pointmatcher/datapointsfilter.cpp create mode 100644 python/pointmatcher/datapointsfilter.h create mode 100644 python/pointmatcher/datapointsfilters.cpp create mode 100644 python/pointmatcher/datapointsfilters.h create mode 100644 python/pointmatcher/errorminimizer.cpp create mode 100644 python/pointmatcher/errorminimizer.h create mode 100644 python/pointmatcher/icp.cpp create mode 100644 python/pointmatcher/icp.h create mode 100644 python/pointmatcher/icpchainbase.cpp create mode 100644 python/pointmatcher/icpchainbase.h create mode 100644 python/pointmatcher/icpsequence.cpp create mode 100644 python/pointmatcher/icpsequence.h create mode 100644 python/pointmatcher/impl.cpp create mode 100644 python/pointmatcher/impl.h create mode 100644 python/pointmatcher/impls/inspectors_impl.cpp create mode 100644 python/pointmatcher/impls/inspectors_impl.h create mode 100644 python/pointmatcher/impls/matchers_impl.cpp create mode 100644 python/pointmatcher/impls/matchers_impl.h create mode 100644 python/pointmatcher/impls/outlierfilters_impl.cpp create mode 100644 python/pointmatcher/impls/outlierfilters_impl.h create mode 100644 python/pointmatcher/impls/transformationcheckers_impl.cpp create mode 100644 python/pointmatcher/impls/transformationcheckers_impl.h create mode 100644 python/pointmatcher/impls/transformations_impl.cpp create mode 100644 python/pointmatcher/impls/transformations_impl.h create mode 100644 python/pointmatcher/inspector.cpp create mode 100644 python/pointmatcher/inspector.h create mode 100644 python/pointmatcher/matcher.cpp create mode 100644 python/pointmatcher/matcher.h create mode 100644 python/pointmatcher/matches.cpp create mode 100644 python/pointmatcher/matches.h create mode 100644 python/pointmatcher/outlierfilter.cpp create mode 100644 python/pointmatcher/outlierfilter.h create mode 100644 python/pointmatcher/outlierfilters.cpp create mode 100644 python/pointmatcher/outlierfilters.h create mode 100644 python/pointmatcher/pointmatcher.cpp create mode 100644 python/pointmatcher/pointmatcher.h create mode 100644 python/pointmatcher/transformation.cpp create mode 100644 python/pointmatcher/transformation.h create mode 100644 python/pointmatcher/transformationchecker.cpp create mode 100644 python/pointmatcher/transformationchecker.h create mode 100644 python/pointmatcher/transformationcheckers.cpp create mode 100644 python/pointmatcher/transformationcheckers.h create mode 100644 python/pointmatcher/transformations.cpp create mode 100644 python/pointmatcher/transformations.h create mode 100644 python/pointmatchersupport/bibliography.cpp create mode 100644 python/pointmatchersupport/bibliography.h create mode 100644 python/pointmatchersupport/logger.cpp create mode 100644 python/pointmatchersupport/logger.h create mode 100644 python/pointmatchersupport/logger_impl.cpp create mode 100644 python/pointmatchersupport/logger_impl.h create mode 100644 python/pointmatchersupport/parametrizable.cpp create mode 100644 python/pointmatchersupport/parametrizable.h create mode 100644 python/pointmatchersupport/registrar.cpp create mode 100644 python/pointmatchersupport/registrar.h create mode 100644 python/pointmatchersupport/registrars/datapointsfilter_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/datapointsfilter_registrar.h create mode 100644 python/pointmatchersupport/registrars/errorminimizer_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/errorminimizer_registrar.h create mode 100644 python/pointmatchersupport/registrars/inspector_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/inspector_registrar.h create mode 100644 python/pointmatchersupport/registrars/logger_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/logger_registrar.h create mode 100644 python/pointmatchersupport/registrars/matcher_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/matcher_registrar.h create mode 100644 python/pointmatchersupport/registrars/outlierfilter_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/outlierfilter_registrar.h create mode 100644 python/pointmatchersupport/registrars/transformation_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/transformation_registrar.h create mode 100644 python/pointmatchersupport/registrars/transformationchecker_registrar.cpp create mode 100644 python/pointmatchersupport/registrars/transformationchecker_registrar.h create mode 100644 python/pypointmatcher.cpp create mode 100644 python/pypointmatcher_helper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 457837e8..4fac1d65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.11) +cmake_minimum_required(VERSION 2.8.12) include(CheckSymbolExists) @@ -446,6 +446,13 @@ if (BUILD_TESTS) add_subdirectory(utest) endif() +# ========================= Python module ============================= +option(BUILD_PYTHON_MODULE "Build the python module for libpointmatcher" OFF) + +if (BUILD_PYTHON_MODULE) + add_subdirectory(python) +endif() + #=================== allow find_package() ========================= # # the following case be used in an external project requiring libpointmatcher: diff --git a/examples/python/icp.py b/examples/python/icp.py new file mode 100644 index 00000000..a3649ae6 --- /dev/null +++ b/examples/python/icp.py @@ -0,0 +1,56 @@ +import numpy as np + +from pypointmatcher.pointmatcher import PointMatcher +from examples.python.utils import parse_translation, parse_rotation + +PM = PointMatcher +DP = PM.DataPoints + +config_file = "../data/default.yaml" +output_base_file = "tests_output/icp/" +is_3D = True +init_translation = "1,1,1" if is_3D else "1,1" +init_rotation = "1,0,0;0,1,0;0,0,1" if is_3D else "1,0;0,1" + +if is_3D: + # 3D point clouds + ref = DP.load('../data/car_cloud400.csv') + data = DP.load('../data/car_cloud401.csv') + test_base = "3D" +else: + # 2D point clouds + ref = DP.load('../data/2D_twoBoxes.csv') + data = DP.load('../data/2D_oneBox.csv') + test_base = "2D" + +icp = PM.ICP() + +icp.loadFromYaml(config_file) +# icp.setDefault() + +cloud_dimension = ref.getEuclideanDim() + +assert cloud_dimension == 2 or cloud_dimension == 3, "Invalid input point clouds dimension" + +translation = parse_translation(init_translation, cloud_dimension) +rotation = parse_rotation(init_rotation, cloud_dimension) +init_transfo = np.matmul(translation, rotation) + +rigid_trans = PM.get().TransformationRegistrar.create("RigidTransformation") + +if not rigid_trans.checkParameters(init_transfo): + print("Initial transformations is not rigid, identiy will be used") + init_transfo = np.identity(cloud_dimension + 1) + +initialized_data = rigid_trans.compute(data, init_transfo) + +T = icp(initialized_data, ref) + +data_out = DP(initialized_data) +icp.transformations.apply(data_out, T) + +ref.save(output_base_file + f"{test_base}_test_ref.vtk") +data.save(output_base_file + f"{test_base}_test_data_in.vtk") +data_out.save(output_base_file + f"{test_base}_test_data_out.vtk") + +print(f"{test_base} ICP transformation:\n{T}".replace("[", " ").replace("]", " ")) diff --git a/examples/python/icp_advance_api.py b/examples/python/icp_advance_api.py new file mode 100644 index 00000000..c95157af --- /dev/null +++ b/examples/python/icp_advance_api.py @@ -0,0 +1,134 @@ +import numpy as np + +from math import sqrt +from pypointmatcher import pointmatcher, pointmatchersupport +from examples.python.utils import parse_translation, parse_rotation + +PM = pointmatcher.PointMatcher +DP = PM.DataPoints +Parameters = pointmatchersupport.Parametrizable.ParametersMap + +# Code example for ICP taking 2 points clouds (2D or 3D) relatively close +# and computing the transformation between them. +# +# This code is more complete than icp_simple. It can load parameter files and has more options. +config_file = "../data/default.yaml" +output_base_file = "tests_output/icp_advance_api/" +is_3D = True # (toggle to switch between 2D and 3D clouds) +init_translation = "1,1,1" if is_3D else "1,1" +init_rotation = "1,0,0;0,1,0;0,0,1" if is_3D else "1,0;0,1" + +if is_3D: + # 3D point clouds + ref = DP.load('../data/car_cloud400.csv') + data = DP.load('../data/car_cloud401.csv') + test_base = "3D" +else: + # 2D point clouds + ref = DP.load('../data/2D_twoBoxes.csv') + data = DP.load('../data/2D_oneBox.csv') + test_base = "2D" + +icp = PM.ICP() + +# icp.setDefault() +icp.loadFromYaml(config_file) + +cloud_dimension = ref.getEuclideanDim() + +assert cloud_dimension == 2 or cloud_dimension == 3, "Invalid input point clouds dimension" + +translation = parse_translation(init_translation, cloud_dimension) +rotation = parse_rotation(init_rotation, cloud_dimension) +init_transfo = np.matmul(translation, rotation) + +rigid_trans = PM.get().TransformationRegistrar.create("RigidTransformation") + +if not rigid_trans.checkParameters(init_transfo): + print("Initial transformations is not rigid, identiy will be used") + init_transfo = np.identity(cloud_dimension + 1) + +initialized_data = rigid_trans.compute(data, init_transfo) + +T = icp(initialized_data, ref) +match_ratio = icp.errorMinimizer.getWeightedPointUsedRatio() +print(f"match ratio: {match_ratio:.6}") +print("\n------------------") + +data_out = DP(initialized_data) +icp.transformations.apply(data_out, T) + +# START demo 1 +# Test for retrieving Haussdorff distance (with outliers). We generate new matching module +# specifically for this purpose. +# +# INPUTS: +# ref: point cloud used as reference +# data_out: aligned point cloud (using the transformation outputted by icp) +# icp: icp object used to aligned the point clouds + +params = Parameters() +params["knn"] = "1" +params["epsilon"] = "0" + +matcher_Hausdorff = PM.get().MatcherRegistrar.create("KDTreeMatcher", params) + +# max. distance from reading to reference +matcher_Hausdorff.init(ref) +matches = matcher_Hausdorff.findClosests(data_out) +max_dist1 = matches.getDistsQuantile(1.0) +max_dist_robust1 = matches.getDistsQuantile(0.85) + +# max. distance from reference to reading +matcher_Hausdorff.init(data_out) +matches = matcher_Hausdorff.findClosests(ref) +max_dist2 = matches.getDistsQuantile(1.0) +max_dist_robust2 = matches.getDistsQuantile(0.85) + +haussdorff_dist = max(max_dist1, max_dist2) +haussdorff_quantile_dist = max(max_dist_robust1, max_dist_robust2) + +print(f"Haussdorff distance: {sqrt(haussdorff_dist):.6} m") +print(f"Haussdorff quantile distance: {sqrt(haussdorff_quantile_dist):.6} m") + +# START demo 2 +# Test for retrieving paired point mean distance without outliers. +# We reuse the same module used for the icp object. +# +# INPUTS: +# ref: point cloud used as reference +# data_out: aligned point cloud (using the transformation outputted by icp) +# icp: icp object used to aligned the point clouds + +# initiate the matching with unfiltered point cloud +icp.matcher.init(ref) + +# extract closest points +matches = icp.matcher.findClosests(data_out) + +# weight paired points +outlier_weights = icp.outlierFilters.compute(data_out, ref, matches) + +# generate tuples of matched points and remove pairs with zero weight +matched_points = PM.ErrorMinimizer.ErrorElements(data_out, ref, outlier_weights, matches) + +# extract relevant information for convenience +dim = matched_points.reading.getEuclideanDim() +nb_matched_points = matched_points.reading.getNbPoints() +matched_read = matched_points.reading.features[:dim] +matched_ref = matched_points.reference.features[:dim] + +# compute mean distance +dist = np.linalg.norm(matched_read - matched_ref, axis=0) +mean_dist = dist.sum() / nb_matched_points + +print(f"Robust mean distance: {mean_dist:.6} m") +print("------------------\n") + +# End demo + +ref.save(output_base_file + f"{test_base}_test_ref.vtk") +data.save(output_base_file + f"{test_base}_test_data_in.vtk") +data_out.save(output_base_file + f"{test_base}_test_data_out.vtk") + +print(f"{test_base} ICP transformation:\n{T}".replace("[", " ").replace("]", " ")) diff --git a/examples/python/icp_customized.py b/examples/python/icp_customized.py new file mode 100644 index 00000000..a5a67c45 --- /dev/null +++ b/examples/python/icp_customized.py @@ -0,0 +1,128 @@ +from pypointmatcher import pointmatcher, pointmatchersupport + +PM = pointmatcher.PointMatcher +DP = PM.DataPoints +Parameters = pointmatchersupport.Parametrizable.ParametersMap +output_base_file = "tests_output/icp_customized/" +is_3D = True # (toggle to switch between 2D and 3D clouds) + +# Load point clouds +if is_3D: + # 3D point clouds + ref = DP.load('../data/car_cloud400.csv') + data = DP.load('../data/car_cloud401.csv') + test_base = "3D" +else: + # 2D point clouds + ref = DP.load('../data/2D_twoBoxes.csv') + data = DP.load('../data/2D_oneBox.csv') + test_base = "2D" + +# Create the default ICP algrotithm +icp = PM.ICP() +params = Parameters() + +pointmatchersupport.setLogger(PM.get().LoggerRegistrar.create("FileLogger")) + +# Prepare reading filters +name = "MinDistDataPointsFilter" +params["minDist"] = "1.0" +minDist_read = PM.get().DataPointsFilterRegistrar.create(name, params) +params = Parameters() + +name = "RandomSamplingDataPointsFilter" +params["prob"] = "0.05" +rand_read = PM.get().DataPointsFilterRegistrar.create(name, params) +params = Parameters() + +# Prepare reference filters +name = "MinDistDataPointsFilter" +params["minDist"] = "1.0" +minDist_ref = PM.get().DataPointsFilterRegistrar.create(name, params) +params = Parameters() + +name = "RandomSamplingDataPointsFilter" +params["prob"] = "0.05" +rand_ref = PM.get().DataPointsFilterRegistrar.create(name, params) +params = Parameters() + +# Prepare matching function +name = "KDTreeMatcher" +params["knn"] = "1" +params["epsilon"] = "3.16" +kdtree = PM.get().MatcherRegistrar.create(name, params) +params = Parameters() + +# Prepare outlier filters +name = "TrimmedDistOutlierFilter" +params["ratio"] = "0.75" +trim = PM.get().OutlierFilterRegistrar.create(name, params) +params = Parameters() + +# Prepare error minimization +name = "PointToPointErrorMinimizer" +pointToPoint = PM.get().ErrorMinimizerRegistrar.create(name) + +# Prepare transformation checker filters +name = "CounterTransformationChecker" +params["maxIterationCount"] = "150" +maxIter = PM.get().TransformationCheckerRegistrar.create(name, params) +params = Parameters() + +name = "DifferentialTransformationChecker" +params["minDiffRotErr"] = "0.001" +params["minDiffTransErr"] = "0.01" +params["smoothLength"] = "4" +diff = PM.get().TransformationCheckerRegistrar.create(name, params) +params = Parameters() + +# Prepare inspector +# toggle to write vtk files per iteration +name = "NullInspector" +nullInspect = PM.get().InspectorRegistrar.create(name) + +# uncomment to write vtk files per iteration +# name = "VTKFileInspector" +# params["dumpDataLinks"] = "1" +# params["dumpReading"] = "1" +# params["dumpReference"] = "1" +# vtkInspect = PM.get().InspectorRegistrar.create(name, params) +# params = Parametrizable.Parameters() + +# Prepare transformation +name = "RigidTransformation" +rigid_trans = PM.get().TransformationRegistrar.create(name) + +# Build ICP solution +icp.readingDataPointsFilters.append(minDist_read) +icp.readingDataPointsFilters.append(rand_read) + +icp.referenceDataPointsFilters.append(minDist_ref) +icp.referenceDataPointsFilters.append(rand_ref) + +icp.matcher = kdtree + +icp.outlierFilters.append(trim) + +icp.errorMinimizer = pointToPoint + +icp.transformationCheckers.append(maxIter) +icp.transformationCheckers.append(diff) + +# toggle to write vtk files per iteration +icp.inspector = nullInspect +# icp.inspector = vtkInspect + +icp.transformations.append(rigid_trans) + +T = icp(data, ref) + +data_out = DP(data) + +icp.transformations.apply(data_out, T) + +ref.save(output_base_file + f"{test_base}_test_ref.vtk") +data.save(output_base_file + f"{test_base}_test_data_in.vtk") +data_out.save(output_base_file + f"{test_base}_test_data_out.vtk") + +print(f"{test_base} ICP transformation:\n{T}".replace("[", " ").replace("]", " ")) diff --git a/examples/python/icp_simple.py b/examples/python/icp_simple.py new file mode 100644 index 00000000..4774f5da --- /dev/null +++ b/examples/python/icp_simple.py @@ -0,0 +1,33 @@ +from pypointmatcher.pointmatcher import PointMatcher + +PM = PointMatcher +DP = PM.DataPoints +output_base_file = "tests_output/icp_simple/" +is_3D = True # (toggle to switch between 2D and 3D clouds) + +if is_3D: + # 3D point clouds + ref = DP.load('../data/car_cloud400.csv') + data = DP.load('../data/car_cloud401.csv') + test_base = "3D" +else: + # 2D point clouds + ref = DP.load('../data/2D_twoBoxes.csv') + data = DP.load('../data/2D_oneBox.csv') + test_base = "2D" + +icp = PM.ICP() + +icp.setDefault() + +TP = icp(ref, data) + +data_out = DP(data) + +icp.transformations.apply(data_out, TP) + +ref.save(output_base_file + f"{test_base}_test_ref.vtk") +data.save(output_base_file + f"{test_base}_test_data_in.vtk") +data_out.save(output_base_file + f"{test_base}_data_out.vtk") + +print(f"Final {test_base} transformations:\n{TP}\n".replace("[", " ").replace("]", " ")) diff --git a/examples/python/utils.py b/examples/python/utils.py new file mode 100644 index 00000000..b0e1a794 --- /dev/null +++ b/examples/python/utils.py @@ -0,0 +1,35 @@ +import numpy as np + + +def list_modules(): + # TODO + pass + + +def parse_translation(p_translation: str, p_cloud_dim: int): + parsed_translation = np.identity(p_cloud_dim + 1) + + p_translation = p_translation.strip('[]') + p_translation = p_translation.replace(',', ' ') + + translation_values = np.fromiter(p_translation.split(' '), np.float64) + + for i, v in enumerate(translation_values): + parsed_translation[i, p_cloud_dim] = v + + return parsed_translation + + +def parse_rotation(p_rotation: str, p_cloud_dim: int): + parsed_rotation = np.identity(p_cloud_dim + 1) + + p_rotation = p_rotation.strip('[]') + p_rotation = p_rotation.replace(',', ' ') + p_rotation = p_rotation.replace(';', ' ') + + rotation_matrix = np.fromiter(p_rotation.split(' '), np.float64) + + for i, v in enumerate(rotation_matrix): + parsed_rotation[i // p_cloud_dim, i % p_cloud_dim] = v + + return parsed_rotation diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 00000000..41f963c0 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,112 @@ +cmake_minimum_required(VERSION 2.8.12) + +include_directories(${CMAKE_SOURCE_DIR}/pointmatcher) +include_directories(${CMAKE_SOURCE_DIR}/pointmatcher/DataPointsFilters) +include_directories(${CMAKE_SOURCE_DIR}/pointmatcher/DataPointsFilters/utils) +include_directories(${CMAKE_SOURCE_DIR}/pointmatcher/ErrorMinimizers) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +foreach (file ${POINTMATCHER_SRC}) + set(PYTHON_SRC ${PYTHON_SRC} ../${file}) +endforeach() + +set(PYBIND11_SOURCES +#pointmatcher module + pointmatcher/datapoints.cpp + pointmatcher/datapointsfilter.cpp + pointmatcher/datapointsfilters.cpp + pointmatcher/errorminimizer.cpp + pointmatcher/icp.cpp + pointmatcher/icpchainbase.cpp + pointmatcher/icpsequence.cpp + pointmatcher/impls/inspectors_impl.cpp + pointmatcher/impls/matchers_impl.cpp + pointmatcher/impls/outlierfilters_impl.cpp + pointmatcher/impls/transformations_impl.cpp + pointmatcher/impls/transformationcheckers_impl.cpp + pointmatcher/impl.cpp + pointmatcher/inspector.cpp + pointmatcher/matcher.cpp + pointmatcher/matches.cpp + pointmatcher/outlierfilter.cpp + pointmatcher/outlierfilters.cpp + pointmatcher/pointmatcher.cpp + pointmatcher/transformation.cpp + pointmatcher/transformations.cpp + pointmatcher/transformationchecker.cpp + pointmatcher/transformationcheckers.cpp + + modules/pointmatcher_module.cpp + +#pointmatchersupport module + pointmatchersupport/bibliography.cpp + pointmatchersupport/logger.cpp + pointmatchersupport/logger_impl.cpp + pointmatchersupport/parametrizable.cpp + pointmatchersupport/registrars/datapointsfilter_registrar.cpp + pointmatchersupport/registrars/errorminimizer_registrar.cpp + pointmatchersupport/registrars/inspector_registrar.cpp + pointmatchersupport/registrars/logger_registrar.cpp + pointmatchersupport/registrars/matcher_registrar.cpp + pointmatchersupport/registrars/outlierfilter_registrar.cpp + pointmatchersupport/registrars/transformation_registrar.cpp + pointmatchersupport/registrars/transformationchecker_registrar.cpp + pointmatchersupport/registrar.cpp + + modules/pointmatchersupport_module.cpp + +#errorminimizers module + errorminimizers/identity.cpp + errorminimizers/pointtoplane.cpp + errorminimizers/pointtoplanewithcov.cpp + errorminimizers/pointtopoint.cpp + errorminimizers/pointtopointsimilarity.cpp + errorminimizers/pointtopointwithcov.cpp + + modules/errorminimizers_module.cpp + +#datapointfilters module + datapointsfilters/boundingbox.cpp + datapointsfilters/covariancesampling.cpp + datapointsfilters/cutatdescriptorthreshold.cpp + datapointsfilters/distancelimit.cpp + datapointsfilters/ellipsoids.cpp + datapointsfilters/fixstepsampling.cpp + datapointsfilters/gestalt.cpp + datapointsfilters/identity.cpp + datapointsfilters/incidenceangle.cpp + datapointsfilters/maxdensity.cpp + datapointsfilters/maxpointcount.cpp + datapointsfilters/maxquantileonaxis.cpp + datapointsfilters/normalspace.cpp + datapointsfilters/observationdirection.cpp + datapointsfilters/octreegrid.cpp + datapointsfilters/orientnormals.cpp + datapointsfilters/randomsampling.cpp + datapointsfilters/removenan.cpp + datapointsfilters/removesensorbias.cpp + datapointsfilters/samplingsurfacenormal.cpp + datapointsfilters/shadow.cpp + datapointsfilters/simplesensornoise.cpp + datapointsfilters/sphericality.cpp + datapointsfilters/surfacenormal.cpp + + modules/datapointsfilters_module.cpp + +# main module + pypointmatcher.cpp) + +find_package(pybind11 REQUIRED) + +if (pybind11_FOUND) + message(STATUS "pybind11 v${pybind11_VERSION}\n") + + pybind11_add_module(pypointmatcher + ${PYTHON_SRC} + ${PYBIND11_SOURCES}) + + target_link_libraries(pypointmatcher PRIVATE ${EXTERNAL_LIBS}) + + add_dependencies(pypointmatcher ${EXTRA_DEPS}) +endif () \ No newline at end of file diff --git a/python/datapointsfilters/boundingbox.cpp b/python/datapointsfilters/boundingbox.cpp new file mode 100644 index 00000000..439512ad --- /dev/null +++ b/python/datapointsfilters/boundingbox.cpp @@ -0,0 +1,27 @@ +#include "boundingbox.h" + +namespace pointmatcher +{ + void pybindBoundingBox(py::module& p_module) + { + using BoundingBoxDataPointsFilter = BoundingBoxDataPointsFilter; + + py::class_, DataPointsFilter> + (p_module, "BoundingBoxDataPointsFilter") + .def_static("description", &BoundingBoxDataPointsFilter::description) + .def_static("availableParameters", &BoundingBoxDataPointsFilter::availableParameters) + + .def_readonly("xMin", &BoundingBoxDataPointsFilter::xMin) + .def_readonly("xMax", &BoundingBoxDataPointsFilter::xMax) + .def_readonly("yMin", &BoundingBoxDataPointsFilter::yMin) + .def_readonly("yMax", &BoundingBoxDataPointsFilter::yMax) + .def_readonly("zMin", &BoundingBoxDataPointsFilter::zMin) + .def_readonly("zMax", &BoundingBoxDataPointsFilter::zMax) + .def_readonly("removeInside", &BoundingBoxDataPointsFilter::removeInside) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &BoundingBoxDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &BoundingBoxDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/boundingbox.h b/python/datapointsfilters/boundingbox.h new file mode 100644 index 00000000..0cbaa883 --- /dev/null +++ b/python/datapointsfilters/boundingbox.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_BOUNDINGBOX_H +#define PYTHON_DATAPOINTSFILTERS_BOUNDINGBOX_H + +#include "DataPointsFilters/BoundingBox.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindBoundingBox(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_BOUNDINGBOX_H diff --git a/python/datapointsfilters/covariancesampling.cpp b/python/datapointsfilters/covariancesampling.cpp new file mode 100644 index 00000000..eec8c6bf --- /dev/null +++ b/python/datapointsfilters/covariancesampling.cpp @@ -0,0 +1,31 @@ +#include "covariancesampling.h" + +namespace pointmatcher +{ + void pybindCovarianceSampling(py::module& p_module) + { + using CovarianceSamplingDataPointsFilter = CovarianceSamplingDataPointsFilter; + py::class_, DataPointsFilter> + cosamplingClass(p_module, "CovarianceSamplingDataPointsFilter"); + + using TorqueNormMethod = CovarianceSamplingDataPointsFilter::TorqueNormMethod; + py::enum_(cosamplingClass, "TorqueNormMethod") + .value("L1", TorqueNormMethod::L1) + .value("Lavg", TorqueNormMethod::Lavg) + .value("Lmax", TorqueNormMethod::Lmax) + .export_values(); + + cosamplingClass + .def_static("description", &CovarianceSamplingDataPointsFilter::description) + .def_static("availableParameters", &CovarianceSamplingDataPointsFilter::availableParameters) + .def_static("computeConditionNumber", &CovarianceSamplingDataPointsFilter::computeConditionNumber, py::arg("cov")) + + .def_readwrite("nbSample", &CovarianceSamplingDataPointsFilter::nbSample) + .def_readonly("normalizationMethod", &CovarianceSamplingDataPointsFilter::normalizationMethod) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &CovarianceSamplingDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &CovarianceSamplingDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/covariancesampling.h b/python/datapointsfilters/covariancesampling.h new file mode 100644 index 00000000..2d1e319e --- /dev/null +++ b/python/datapointsfilters/covariancesampling.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_COVARIANCESAMPLING_H +#define PYTHON_DATAPOINTSFILTERS_COVARIANCESAMPLING_H + +#include "DataPointsFilters/CovarianceSampling.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindCovarianceSampling(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_COVARIANCESAMPLING_H diff --git a/python/datapointsfilters/cutatdescriptorthreshold.cpp b/python/datapointsfilters/cutatdescriptorthreshold.cpp new file mode 100644 index 00000000..88ad7f99 --- /dev/null +++ b/python/datapointsfilters/cutatdescriptorthreshold.cpp @@ -0,0 +1,22 @@ +#include "cutatdescriptorthreshold.h" + +namespace pointmatcher +{ + void pybindCutAtDescriptorThreshold(py::module& p_module) + { + using CutAtDescriptorThresholdDataPointsFilter = CutAtDescriptorThresholdDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "CutAtDescriptorThresholdDataPointsFilter") + .def_static("description", &CutAtDescriptorThresholdDataPointsFilter::description) + .def_static("availableParameters", &CutAtDescriptorThresholdDataPointsFilter::availableParameters) + + .def_readonly("descName", &CutAtDescriptorThresholdDataPointsFilter::descName) + .def_readonly("useLargerThan", &CutAtDescriptorThresholdDataPointsFilter::useLargerThan) + .def_readonly("threshold", &CutAtDescriptorThresholdDataPointsFilter::threshold) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &CutAtDescriptorThresholdDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &CutAtDescriptorThresholdDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/cutatdescriptorthreshold.h b/python/datapointsfilters/cutatdescriptorthreshold.h new file mode 100644 index 00000000..6ced83d3 --- /dev/null +++ b/python/datapointsfilters/cutatdescriptorthreshold.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_CUTATDESCRIPTORTHRESHOLD_H +#define PYTHON_DATAPOINTSFILTERS_CUTATDESCRIPTORTHRESHOLD_H + +#include "DataPointsFilters/CutAtDescriptorThreshold.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindCutAtDescriptorThreshold(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_CUTATDESCRIPTORTHRESHOLD_H diff --git a/python/datapointsfilters/distancelimit.cpp b/python/datapointsfilters/distancelimit.cpp new file mode 100644 index 00000000..c46ef6eb --- /dev/null +++ b/python/datapointsfilters/distancelimit.cpp @@ -0,0 +1,22 @@ +#include "distancelimit.h" + +namespace pointmatcher +{ + void pybindDistanceLimit(py::module& p_module) + { + using DistanceLimitDataPointsFilter = DistanceLimitDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "DistanceLimitDataPointsFilter") + .def_static("description", &DistanceLimitDataPointsFilter::description) + .def_static("availableParameters", &DistanceLimitDataPointsFilter::availableParameters) + + .def_readonly("dim", &DistanceLimitDataPointsFilter::dim) + .def_readonly("dist", &DistanceLimitDataPointsFilter::dist) + .def_readonly("removeInside", &DistanceLimitDataPointsFilter::removeInside) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &DistanceLimitDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &DistanceLimitDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/distancelimit.h b/python/datapointsfilters/distancelimit.h new file mode 100644 index 00000000..feb8c29e --- /dev/null +++ b/python/datapointsfilters/distancelimit.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_DISTANCELIMIT_H +#define PYTHON_DATAPOINTSFILTERS_DISTANCELIMIT_H + +#include "DataPointsFilters/DistanceLimit.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindDistanceLimit(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_DISTANCELIMIT_H diff --git a/python/datapointsfilters/ellipsoids.cpp b/python/datapointsfilters/ellipsoids.cpp new file mode 100644 index 00000000..68799d1d --- /dev/null +++ b/python/datapointsfilters/ellipsoids.cpp @@ -0,0 +1,37 @@ +#include "ellipsoids.h" + +namespace pointmatcher +{ + void pybindEllipsoids(py::module& p_module) + { + using ElipsoidsDataPointsFilter = ElipsoidsDataPointsFilter; + py::class_, DataPointsFilter> + ellipsoidClass(p_module, "EllipsoidsDataPointsFilter"); + + ellipsoidClass + .def_static("description", &ElipsoidsDataPointsFilter::description) + .def_static("availableParameters", &ElipsoidsDataPointsFilter::availableParameters) + + .def_readonly("ratio", &ElipsoidsDataPointsFilter::ratio) + .def_readonly("knn", &ElipsoidsDataPointsFilter::knn) + .def_readonly("samplingMethod", &ElipsoidsDataPointsFilter::samplingMethod) + .def_readonly("maxBoxDim", &ElipsoidsDataPointsFilter::maxBoxDim) + .def_readonly("maxTimeWindow", &ElipsoidsDataPointsFilter::maxTimeWindow) + .def_readonly("minPlanarity", &ElipsoidsDataPointsFilter::minPlanarity) + .def_readonly("averageExistingDescriptors", &ElipsoidsDataPointsFilter::averageExistingDescriptors) + .def_readonly("keepNormals", &ElipsoidsDataPointsFilter::keepNormals) + .def_readonly("keepDensities", &ElipsoidsDataPointsFilter::keepDensities) + .def_readonly("keepEigenValues", &ElipsoidsDataPointsFilter::keepEigenValues) + .def_readonly("keepEigenVectors", &ElipsoidsDataPointsFilter::keepEigenVectors) + .def_readonly("keepCovariances", &ElipsoidsDataPointsFilter::keepCovariances) + .def_readonly("keepWeights", &ElipsoidsDataPointsFilter::keepWeights) + .def_readonly("keepMeans", &ElipsoidsDataPointsFilter::keepMeans) + .def_readonly("keepShapes", &ElipsoidsDataPointsFilter::keepShapes) + .def_readonly("keepIndices", &ElipsoidsDataPointsFilter::keepIndices) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &ElipsoidsDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &ElipsoidsDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/ellipsoids.h b/python/datapointsfilters/ellipsoids.h new file mode 100644 index 00000000..68b38b0a --- /dev/null +++ b/python/datapointsfilters/ellipsoids.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_ELLIPSOIDS_H +#define PYTHON_DATAPOINTSFILTERS_ELLIPSOIDS_H + +#include "DataPointsFilters/Elipsoids.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindEllipsoids(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_ELLIPSOIDS_H diff --git a/python/datapointsfilters/fixstepsampling.cpp b/python/datapointsfilters/fixstepsampling.cpp new file mode 100644 index 00000000..caba94a6 --- /dev/null +++ b/python/datapointsfilters/fixstepsampling.cpp @@ -0,0 +1,23 @@ +#include "fixstepsampling.h" + +namespace pointmatcher +{ + void pybindFixStepSampling(py::module& p_module) + { + using FixStepSamplingDataPointsFilter = FixStepSamplingDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "FixStepSamplingDataPointsFilter") + .def_static("description", &FixStepSamplingDataPointsFilter::description) + .def_static("availableParameters", &FixStepSamplingDataPointsFilter::availableParameters) + + .def_readonly("startStep", &FixStepSamplingDataPointsFilter::startStep) + .def_readonly("endStep", &FixStepSamplingDataPointsFilter::endStep) + .def_readonly("stepMult", &FixStepSamplingDataPointsFilter::stepMult) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("init", &FixStepSamplingDataPointsFilter::init) + .def("filter", &FixStepSamplingDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &FixStepSamplingDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/fixstepsampling.h b/python/datapointsfilters/fixstepsampling.h new file mode 100644 index 00000000..5c523059 --- /dev/null +++ b/python/datapointsfilters/fixstepsampling.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_FIXSTEPSAMPLING_H +#define PYTHON_DATAPOINTSFILTERS_FIXSTEPSAMPLING_H + +#include "DataPointsFilters/FixStepSampling.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindFixStepSampling(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_FIXSTEPSAMPLING_H diff --git a/python/datapointsfilters/gestalt.cpp b/python/datapointsfilters/gestalt.cpp new file mode 100644 index 00000000..75dfdd88 --- /dev/null +++ b/python/datapointsfilters/gestalt.cpp @@ -0,0 +1,37 @@ +#include "gestalt.h" + +namespace pointmatcher +{ + void pybindGestalt(py::module& p_module) + { + using GestaltDataPointsFilter = GestaltDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "GestaltDataPointsFilter") + .def_static("description", &GestaltDataPointsFilter::description) + .def_static("availableParameters", &GestaltDataPointsFilter::availableParameters) + + .def_readonly("ratio", &GestaltDataPointsFilter::ratio) + .def_readonly("radius", &GestaltDataPointsFilter::radius) + .def_readonly("knn", &GestaltDataPointsFilter::knn) + .def_readonly("vSizeX", &GestaltDataPointsFilter::vSizeX) + .def_readonly("vSizeY", &GestaltDataPointsFilter::vSizeY) + .def_readonly("vSizeZ", &GestaltDataPointsFilter::vSizeZ) + .def_readonly("maxBoxDim", &GestaltDataPointsFilter::maxBoxDim) + .def_readonly("maxTimeWindow", &GestaltDataPointsFilter::maxTimeWindow) + .def_readonly("keepMeans", &GestaltDataPointsFilter::keepMeans) + .def_readonly("averageExistingDescriptors", &GestaltDataPointsFilter::averageExistingDescriptors) + .def_readonly("keepNormals", &GestaltDataPointsFilter::keepNormals) + .def_readonly("keepEigenValues", &GestaltDataPointsFilter::keepEigenValues) + .def_readonly("keepEigenVectors", &GestaltDataPointsFilter::keepEigenVectors) + .def_readonly("keepCovariances", &GestaltDataPointsFilter::keepCovariances) + .def_readonly("keepGestaltFeatures", &GestaltDataPointsFilter::keepGestaltFeatures) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &GestaltDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &GestaltDataPointsFilter::inPlaceFilter, py::arg("cloud")) + .def("serializeGestaltMatrix", &GestaltDataPointsFilter::serializeGestaltMatrix, py::arg("gestaltFeatures")) + .def("calculateAngles", &GestaltDataPointsFilter::calculateAngles, py::arg("points"), py::arg("")) + .def("calculateRadii", &GestaltDataPointsFilter::calculateRadii, py::arg("points"), py::arg("")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/gestalt.h b/python/datapointsfilters/gestalt.h new file mode 100644 index 00000000..8b88e141 --- /dev/null +++ b/python/datapointsfilters/gestalt.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_GESTALT_H +#define PYTHON_DATAPOINTSFILTERS_GESTALT_H + +#include "DataPointsFilters/Gestalt.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindGestalt(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_GESTALT_H diff --git a/python/datapointsfilters/identity.cpp b/python/datapointsfilters/identity.cpp new file mode 100644 index 00000000..475a001a --- /dev/null +++ b/python/datapointsfilters/identity.cpp @@ -0,0 +1,17 @@ +#include "identity.h" + +namespace pointmatcher +{ + void pybindIdentityDPF(py::module& p_module) + { + using IdentityDataPointsFilter = IdentityDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "IdentityDataPointsFilter") + .def_static("description", &IdentityDataPointsFilter::description) + + .def(py::init<>()) + + .def("filter", &IdentityDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &IdentityDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/identity.h b/python/datapointsfilters/identity.h new file mode 100644 index 00000000..37992a83 --- /dev/null +++ b/python/datapointsfilters/identity.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_IDENTITY_H +#define PYTHON_ERRORMINIMIZERS_IDENTITY_H + +#include "DataPointsFilters/Identity.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindIdentityDPF(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_IDENTITY_H diff --git a/python/datapointsfilters/incidenceangle.cpp b/python/datapointsfilters/incidenceangle.cpp new file mode 100644 index 00000000..7f0a9519 --- /dev/null +++ b/python/datapointsfilters/incidenceangle.cpp @@ -0,0 +1,17 @@ +#include "incidenceangle.h" + +namespace pointmatcher +{ + void pybindIncidenceAngle(py::module& p_module) + { + using IncidenceAngleDataPointsFilter = IncidenceAngleDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "IncidenceAngleDataPointsFilter") + .def_static("description", &IncidenceAngleDataPointsFilter::description) + + .def(py::init<>()) + + .def("filter", &IncidenceAngleDataPointsFilter::filter, py::arg("input")) + .def("inPlaceFilter", &IncidenceAngleDataPointsFilter::inPlaceFilter, py::arg("cloud")); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/incidenceangle.h b/python/datapointsfilters/incidenceangle.h new file mode 100644 index 00000000..997634b6 --- /dev/null +++ b/python/datapointsfilters/incidenceangle.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_INCIDENCEANGLE_H +#define PYTHON_DATAPOINTSFILTERS_INCIDENCEANGLE_H + +#include "DataPointsFilters/IncidenceAngle.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindIncidenceAngle(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_INCIDENCEANGLE_H diff --git a/python/datapointsfilters/maxdensity.cpp b/python/datapointsfilters/maxdensity.cpp new file mode 100644 index 00000000..d024853e --- /dev/null +++ b/python/datapointsfilters/maxdensity.cpp @@ -0,0 +1,20 @@ +#include "maxdensity.h" + +namespace pointmatcher +{ + void pybindMaxDensity(py::module& p_module) + { + using MaxDensityDataPointsFilter = MaxDensityDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "MaxDensityDataPointsFilter") + .def_static("description", &MaxDensityDataPointsFilter::description) + .def_static("availableParameters", &MaxDensityDataPointsFilter::availableParameters) + + .def_readonly("maxDensity", &MaxDensityDataPointsFilter::maxDensity) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &MaxDensityDataPointsFilter::filter) + .def("inPlaceFilter", &MaxDensityDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/maxdensity.h b/python/datapointsfilters/maxdensity.h new file mode 100644 index 00000000..5242ffc4 --- /dev/null +++ b/python/datapointsfilters/maxdensity.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_MAXDENSITY_H +#define PYTHON_DATAPOINTSFILTERS_MAXDENSITY_H + +#include "DataPointsFilters/MaxDensity.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindMaxDensity(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_MAXDENSITY_H diff --git a/python/datapointsfilters/maxpointcount.cpp b/python/datapointsfilters/maxpointcount.cpp new file mode 100644 index 00000000..a41aeb73 --- /dev/null +++ b/python/datapointsfilters/maxpointcount.cpp @@ -0,0 +1,21 @@ +#include "maxpointcount.h" + +namespace pointmatcher +{ + void pybindMaxPointCount(py::module& p_module) + { + using MaxPointCountDataPointsFilter = MaxPointCountDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "MaxPointCountDataPointsFilter") + .def_static("description", &MaxPointCountDataPointsFilter::description) + .def_static("availableParameters", &MaxPointCountDataPointsFilter::availableParameters) + + .def_readonly("maxCount", &MaxPointCountDataPointsFilter::maxCount) + .def_readonly("seed", &MaxPointCountDataPointsFilter::seed) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &MaxPointCountDataPointsFilter::filter) + .def("inPlaceFilter", &MaxPointCountDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/maxpointcount.h b/python/datapointsfilters/maxpointcount.h new file mode 100644 index 00000000..84ab148e --- /dev/null +++ b/python/datapointsfilters/maxpointcount.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_MAXPOINTCOUNT_H +#define PYTHON_DATAPOINTSFILTERS_MAXPOINTCOUNT_H + +#include "DataPointsFilters/MaxPointCount.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindMaxPointCount(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_MAXPOINTCOUNT_H diff --git a/python/datapointsfilters/maxquantileonaxis.cpp b/python/datapointsfilters/maxquantileonaxis.cpp new file mode 100644 index 00000000..9bcb129b --- /dev/null +++ b/python/datapointsfilters/maxquantileonaxis.cpp @@ -0,0 +1,21 @@ +#include "maxquantileonaxis.h" + +namespace pointmatcher +{ + void pybindMaxQuantileOnAxis(py::module& p_module) + { + using MaxQuantileOnAxisDataPointsFilter = MaxQuantileOnAxisDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "MaxQuantileOnAxisDataPointsFilter") + .def_static("description", &MaxQuantileOnAxisDataPointsFilter::description) + .def_static("availableParameters", &MaxQuantileOnAxisDataPointsFilter::availableParameters) + + .def_readonly("dim", &MaxQuantileOnAxisDataPointsFilter::dim) + .def_readonly("ratio", &MaxQuantileOnAxisDataPointsFilter::ratio) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &MaxQuantileOnAxisDataPointsFilter::filter) + .def("inPlaceFilter", &MaxQuantileOnAxisDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/maxquantileonaxis.h b/python/datapointsfilters/maxquantileonaxis.h new file mode 100644 index 00000000..1e47e7c2 --- /dev/null +++ b/python/datapointsfilters/maxquantileonaxis.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_MAXQUANTILEONAXIS_H +#define PYTHON_DATAPOINTSFILTERS_MAXQUANTILEONAXIS_H + +#include "DataPointsFilters/MaxQuantileOnAxis.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindMaxQuantileOnAxis(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_MAXQUANTILEONAXIS_H diff --git a/python/datapointsfilters/normalspace.cpp b/python/datapointsfilters/normalspace.cpp new file mode 100644 index 00000000..c9c446b6 --- /dev/null +++ b/python/datapointsfilters/normalspace.cpp @@ -0,0 +1,22 @@ +#include "normalspace.h" + +namespace pointmatcher +{ + void pybindNormalSpace(py::module& p_module) + { + using NormalSpaceDataPointsFilter = NormalSpaceDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "NormalSpaceDataPointsFilter") + .def_static("description", &NormalSpaceDataPointsFilter::description) + .def_static("availableParameters", &NormalSpaceDataPointsFilter::availableParameters) + + .def_readonly("nbSample", &NormalSpaceDataPointsFilter::nbSample) + .def_readonly("seed", &NormalSpaceDataPointsFilter::seed) + .def_readonly("epsilon", &NormalSpaceDataPointsFilter::epsilon) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &NormalSpaceDataPointsFilter::filter) + .def("inPlaceFilter", &NormalSpaceDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/normalspace.h b/python/datapointsfilters/normalspace.h new file mode 100644 index 00000000..85ee3dc5 --- /dev/null +++ b/python/datapointsfilters/normalspace.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_NORMALSPACE_H +#define PYTHON_DATAPOINTSFILTERS_NORMALSPACE_H + +#include "DataPointsFilters/NormalSpace.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindNormalSpace(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_NORMALSPACE_H diff --git a/python/datapointsfilters/observationdirection.cpp b/python/datapointsfilters/observationdirection.cpp new file mode 100644 index 00000000..c912f947 --- /dev/null +++ b/python/datapointsfilters/observationdirection.cpp @@ -0,0 +1,22 @@ +#include "observationdirection.h" + +namespace pointmatcher +{ + void pybindObservationDirection(py::module& p_module) + { + using ObservationDirectionDataPointsFilter = ObservationDirectionDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "ObservationDirectionDataPointsFilter") + .def_static("description", &ObservationDirectionDataPointsFilter::description) + .def_static("availableParameters", &ObservationDirectionDataPointsFilter::availableParameters) + + .def_readonly("centerX", &ObservationDirectionDataPointsFilter::centerX) + .def_readonly("centerY", &ObservationDirectionDataPointsFilter::centerY) + .def_readonly("centerZ", &ObservationDirectionDataPointsFilter::centerZ) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &ObservationDirectionDataPointsFilter::filter) + .def("inPlaceFilter", &ObservationDirectionDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/observationdirection.h b/python/datapointsfilters/observationdirection.h new file mode 100644 index 00000000..52e084b1 --- /dev/null +++ b/python/datapointsfilters/observationdirection.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_OBSERVATIONDIRECTION_H +#define PYTHON_DATAPOINTSFILTERS_OBSERVATIONDIRECTION_H + +#include "DataPointsFilters/ObservationDirection.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindObservationDirection(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_OBSERVATIONDIRECTION_H diff --git a/python/datapointsfilters/octreegrid.cpp b/python/datapointsfilters/octreegrid.cpp new file mode 100644 index 00000000..421c4a9e --- /dev/null +++ b/python/datapointsfilters/octreegrid.cpp @@ -0,0 +1,79 @@ +#include "octreegrid.h" + +namespace pointmatcher +{ + void pybindOctreeGrid(py::module& p_module) + { + using OctreeGridDataPointsFilter = OctreeGridDataPointsFilter; + py::class_, DataPointsFilter> + octreegridClass(p_module, "OctreeGridDataPointsFilter"); + + octreegridClass.doc() = R"pbdoc( +Data Filter based on Octree representation + +Processings are applyed via a Visitor through Depth-first search in the Octree (DFS) +i.e. for each node, the Visitor/Callback is called +)pbdoc"; + + using FirstPtsSampler = OctreeGridDataPointsFilter::FirstPtsSampler; + py::class_ firstptssamplerClass(octreegridClass, "FirstPtsSampler", "Visitors class to apply processing"); + + firstptssamplerClass + .def_readwrite("idx", &FirstPtsSampler::idx) +// .def_readwrite("pts", &FirstPtsSampler::pts, py::return_value_policy::reference) FIXME + .def_readwrite("mapidx", &FirstPtsSampler::mapidx, "Build map of (old index to new index), in case we sample pts at the begining of the pointcloud") + + .def(py::init(), py::arg("dp")) + +// .def("__call__", &FirstPtsSampler::operator()<2>, py::arg("oc")) FIXME +// .def("__call__", &FirstPtsSampler::operator()<3>, py::arg("oc")) FIXME + .def("finalize", &FirstPtsSampler::finalize); + + using RandomPtsSampler = OctreeGridDataPointsFilter::RandomPtsSampler; + py::class_(firstptssamplerClass, "RandomPtsSampler") + .def_readonly("seed", &RandomPtsSampler::seed) + + .def(py::init(), py::arg("dp")) + .def(py::init(), py::arg("dp"), py::arg("seed_")) + +// .def("__call__", &RandomPtsSampler::operator()<2>, py::arg("oc")) FIXME +// .def("__call__", &RandomPtsSampler::operator()<3>, py::arg("oc")) FIXME + .def("finalize", &RandomPtsSampler::finalize); + + using CentroidSampler = OctreeGridDataPointsFilter::CentroidSampler; + py::class_(firstptssamplerClass, "CentroidSampler") + .def(py::init(), py::arg("dp")); + +// .def("__call__", &CentroidSampler::operator()<2>, py::arg("oc")) FIXME +// .def("__call__", &CentroidSampler::operator()<3>, py::arg("oc")); FIXME + + using MedoidSampler = OctreeGridDataPointsFilter::MedoidSampler; + py::class_(firstptssamplerClass, "MedoidSampler", "Nearest point from the centroid (contained in the cloud)") + .def(py::init(), py::arg("dp")); + +// .def("__call__", &RandomPtsSampler::operator()<2>, py::arg("oc")) FIXME +// .def("__call__", &RandomPtsSampler::operator()<3>, py::arg("oc")); FIXME + + using SamplingMethod = OctreeGridDataPointsFilter::SamplingMethod; + py::enum_(octreegridClass, "SamplingMethod") + .value("FIRST_PTS", SamplingMethod::FIRST_PTS) + .value("RAND_PTS", SamplingMethod::RAND_PTS) + .value("CENTROID", SamplingMethod::CENTROID) + .value("MEDOID", SamplingMethod::MEDOID) + .export_values(); + + octreegridClass + .def_static("description", &OctreeGridDataPointsFilter::description) + .def_static("availableParameters", &OctreeGridDataPointsFilter::availableParameters) + + .def_readwrite("centerX", &OctreeGridDataPointsFilter::buildParallel) + .def_readwrite("centerY", &OctreeGridDataPointsFilter::maxPointByNode) + .def_readwrite("centerY", &OctreeGridDataPointsFilter::maxSizeByNode) + .def_readonly("centerZ", &OctreeGridDataPointsFilter::samplingMethod) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &OctreeGridDataPointsFilter::filter) + .def("inPlaceFilter", &OctreeGridDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/octreegrid.h b/python/datapointsfilters/octreegrid.h new file mode 100644 index 00000000..6216cfc2 --- /dev/null +++ b/python/datapointsfilters/octreegrid.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_OCTREEGRID_H +#define PYTHON_DATAPOINTSFILTERS_OCTREEGRID_H + +#include "DataPointsFilters/OctreeGrid.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindOctreeGrid(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_OCTREEGRID_H diff --git a/python/datapointsfilters/orientnormals.cpp b/python/datapointsfilters/orientnormals.cpp new file mode 100644 index 00000000..14ec7e5b --- /dev/null +++ b/python/datapointsfilters/orientnormals.cpp @@ -0,0 +1,21 @@ +#include "orientnormals.h" + +namespace pointmatcher +{ + void pybindOrientNormals(py::module& p_module) + { + using OrientNormalsDataPointsFilter = OrientNormalsDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "OrientNormalsDataPointsFilter", "Reorientation of normals") + + .def_static("description", &OrientNormalsDataPointsFilter::description) + .def_static("availableParameters", &OrientNormalsDataPointsFilter::availableParameters) + + .def_readonly("towardCenter", &OrientNormalsDataPointsFilter::towardCenter) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &OrientNormalsDataPointsFilter::filter) + .def("inPlaceFilter", &OrientNormalsDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/orientnormals.h b/python/datapointsfilters/orientnormals.h new file mode 100644 index 00000000..534bd85d --- /dev/null +++ b/python/datapointsfilters/orientnormals.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_ORIENTNORMALS_H +#define PYTHON_DATAPOINTSFILTERS_ORIENTNORMALS_H + +#include "DataPointsFilters/OrientNormals.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindOrientNormals(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_ORIENTNORMALS_H diff --git a/python/datapointsfilters/randomsampling.cpp b/python/datapointsfilters/randomsampling.cpp new file mode 100644 index 00000000..3c2a080b --- /dev/null +++ b/python/datapointsfilters/randomsampling.cpp @@ -0,0 +1,21 @@ +#include "randomsampling.h" + +namespace pointmatcher +{ + void pybindRandomSampling(py::module& p_module) + { + using RandomSamplingDataPointsFilter = RandomSamplingDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "RandomSamplingDataPointsFilter", "Random sampling") + + .def_static("description", &RandomSamplingDataPointsFilter::description) + .def_static("availableParameters", &RandomSamplingDataPointsFilter::availableParameters) + + .def_readonly("prob", &RandomSamplingDataPointsFilter::prob) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &RandomSamplingDataPointsFilter::filter) + .def("inPlaceFilter", &RandomSamplingDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/randomsampling.h b/python/datapointsfilters/randomsampling.h new file mode 100644 index 00000000..94192c14 --- /dev/null +++ b/python/datapointsfilters/randomsampling.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_RANDOMSAMPLING_H +#define PYTHON_DATAPOINTSFILTERS_RANDOMSAMPLING_H + +#include "DataPointsFilters/RandomSampling.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindRandomSampling(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_RANDOMSAMPLING_H diff --git a/python/datapointsfilters/removenan.cpp b/python/datapointsfilters/removenan.cpp new file mode 100644 index 00000000..50c83bbd --- /dev/null +++ b/python/datapointsfilters/removenan.cpp @@ -0,0 +1,18 @@ +#include "removenan.h" + +namespace pointmatcher +{ + void pybindRemoveNaN(py::module& p_module) + { + using RemoveNaNDataPointsFilter = RemoveNaNDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "RemoveNaNDataPointsFilter", "Remove points having NaN as coordinate") + + .def_static("description", &RemoveNaNDataPointsFilter::description) + + .def(py::init<>()) + + .def("filter", &RemoveNaNDataPointsFilter::filter) + .def("inPlaceFilter", &RemoveNaNDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/removenan.h b/python/datapointsfilters/removenan.h new file mode 100644 index 00000000..96e0eec8 --- /dev/null +++ b/python/datapointsfilters/removenan.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_REMOVENAN_H +#define PYTHON_DATAPOINTSFILTERS_REMOVENAN_H + +#include "DataPointsFilters/RemoveNaN.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindRemoveNaN(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_REMOVENAN_H diff --git a/python/datapointsfilters/removesensorbias.cpp b/python/datapointsfilters/removesensorbias.cpp new file mode 100644 index 00000000..a6beeafb --- /dev/null +++ b/python/datapointsfilters/removesensorbias.cpp @@ -0,0 +1,19 @@ +#include "removesensorbias.h" + +namespace pointmatcher +{ + void pybindRemoveSensorBias(py::module& p_module) + { + using RemoveSensorBiasDataPointsFilter = RemoveSensorBiasDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "RemoveSensorBiasDataPointsFilter") + + .def_static("description", &RemoveSensorBiasDataPointsFilter::description) + .def_static("availableParameters", &RemoveSensorBiasDataPointsFilter::availableParameters) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &RemoveSensorBiasDataPointsFilter::filter) + .def("inPlaceFilter", &RemoveSensorBiasDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/removesensorbias.h b/python/datapointsfilters/removesensorbias.h new file mode 100644 index 00000000..108d02ed --- /dev/null +++ b/python/datapointsfilters/removesensorbias.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_REMOVESENSORBIAS_H +#define PYTHON_DATAPOINTSFILTERS_REMOVESENSORBIAS_H + +#include "DataPointsFilters/RemoveSensorBias.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindRemoveSensorBias(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_REMOVESENSORBIAS_H diff --git a/python/datapointsfilters/samplingsurfacenormal.cpp b/python/datapointsfilters/samplingsurfacenormal.cpp new file mode 100644 index 00000000..c1e7d1d0 --- /dev/null +++ b/python/datapointsfilters/samplingsurfacenormal.cpp @@ -0,0 +1,29 @@ +#include "samplingsurfacenormal.h" + +namespace pointmatcher +{ + void pybindSamplingSurfaceNormal(py::module& p_module) + { + using SamplingSurfaceNormalDataPointsFilter = SamplingSurfaceNormalDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "SamplingSurfaceNormalDataPointsFilter") + + .def_static("description", &SamplingSurfaceNormalDataPointsFilter::description) + .def_static("availableParameters", &SamplingSurfaceNormalDataPointsFilter::availableParameters) + + .def_readonly("ratio", &SamplingSurfaceNormalDataPointsFilter::ratio) + .def_readonly("knn", &SamplingSurfaceNormalDataPointsFilter::knn) + .def_readonly("samplingMethod", &SamplingSurfaceNormalDataPointsFilter::samplingMethod) + .def_readonly("maxBoxDim", &SamplingSurfaceNormalDataPointsFilter::maxBoxDim) + .def_readonly("averageExistingDescriptors", &SamplingSurfaceNormalDataPointsFilter::averageExistingDescriptors) + .def_readonly("keepNormals", &SamplingSurfaceNormalDataPointsFilter::keepNormals) + .def_readonly("keepDensities", &SamplingSurfaceNormalDataPointsFilter::keepDensities) + .def_readonly("keepEigenValues", &SamplingSurfaceNormalDataPointsFilter::keepEigenValues) + .def_readonly("keepEigenVectors", &SamplingSurfaceNormalDataPointsFilter::keepEigenVectors) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &SamplingSurfaceNormalDataPointsFilter::filter) + .def("inPlaceFilter", &SamplingSurfaceNormalDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/samplingsurfacenormal.h b/python/datapointsfilters/samplingsurfacenormal.h new file mode 100644 index 00000000..9978a342 --- /dev/null +++ b/python/datapointsfilters/samplingsurfacenormal.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_SAMPLINGSURFACENORMAL_H +#define PYTHON_DATAPOINTSFILTERS_SAMPLINGSURFACENORMAL_H + +#include "DataPointsFilters/SamplingSurfaceNormal.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindSamplingSurfaceNormal(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_SAMPLINGSURFACENORMAL_H diff --git a/python/datapointsfilters/shadow.cpp b/python/datapointsfilters/shadow.cpp new file mode 100644 index 00000000..a9ce0e8a --- /dev/null +++ b/python/datapointsfilters/shadow.cpp @@ -0,0 +1,21 @@ +#include "shadow.h" + +namespace pointmatcher +{ + void pybindShadow(py::module& p_module) + { + using ShadowDataPointsFilter = ShadowDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "ShadowDataPointsFilter", "Shadow filter, remove ghost points appearing on edges") + + .def_static("description", &ShadowDataPointsFilter::description) + .def_static("availableParameters", &ShadowDataPointsFilter::availableParameters) + + .def_readonly("eps", &ShadowDataPointsFilter::eps) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &ShadowDataPointsFilter::filter) + .def("inPlaceFilter", &ShadowDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/shadow.h b/python/datapointsfilters/shadow.h new file mode 100644 index 00000000..15c12bed --- /dev/null +++ b/python/datapointsfilters/shadow.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_SHADOW_H +#define PYTHON_DATAPOINTSFILTERS_SHADOW_H + +#include "DataPointsFilters/Shadow.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindShadow(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_SHADOW_H diff --git a/python/datapointsfilters/simplesensornoise.cpp b/python/datapointsfilters/simplesensornoise.cpp new file mode 100644 index 00000000..91edb1f9 --- /dev/null +++ b/python/datapointsfilters/simplesensornoise.cpp @@ -0,0 +1,22 @@ +#include "simplesensornoise.h" + +namespace pointmatcher +{ + void pybindSimpleSensorNoise(py::module& p_module) + { + using SimpleSensorNoiseDataPointsFilter = SimpleSensorNoiseDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "SimpleSensorNoiseDataPointsFilter", "Sick LMS-xxx noise model") + + .def_static("description", &SimpleSensorNoiseDataPointsFilter::description) + .def_static("availableParameters", &SimpleSensorNoiseDataPointsFilter::availableParameters) + + .def_readonly("sensorType", &SimpleSensorNoiseDataPointsFilter::sensorType) + .def_readonly("gain", &SimpleSensorNoiseDataPointsFilter::gain) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &SimpleSensorNoiseDataPointsFilter::filter) + .def("inPlaceFilter", &SimpleSensorNoiseDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/simplesensornoise.h b/python/datapointsfilters/simplesensornoise.h new file mode 100644 index 00000000..f32620d4 --- /dev/null +++ b/python/datapointsfilters/simplesensornoise.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_SIMPLESENSORNOISE_H +#define PYTHON_DATAPOINTSFILTERS_SIMPLESENSORNOISE_H + +#include "DataPointsFilters/SimpleSensorNoise.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindSimpleSensorNoise(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_SIMPLESENSORNOISE_H diff --git a/python/datapointsfilters/sphericality.cpp b/python/datapointsfilters/sphericality.cpp new file mode 100644 index 00000000..bd6eebbe --- /dev/null +++ b/python/datapointsfilters/sphericality.cpp @@ -0,0 +1,22 @@ +#include "sphericality.h" + +namespace pointmatcher +{ + void pybindSphericality(py::module& p_module) + { + using SphericalityDataPointsFilter = SphericalityDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "SphericalityDataPointsFilter") + + .def_static("description", &SphericalityDataPointsFilter::description) + .def_static("availableParameters", &SphericalityDataPointsFilter::availableParameters) + + .def_readonly("keepUnstructureness", &SphericalityDataPointsFilter::keepUnstructureness) + .def_readonly("keepStructureness", &SphericalityDataPointsFilter::keepStructureness) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &SphericalityDataPointsFilter::filter) + .def("inPlaceFilter", &SphericalityDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/sphericality.h b/python/datapointsfilters/sphericality.h new file mode 100644 index 00000000..c3f0ca1c --- /dev/null +++ b/python/datapointsfilters/sphericality.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_SPHERICALITY_H +#define PYTHON_DATAPOINTSFILTERS_SPHERICALITY_H + +#include "DataPointsFilters/Sphericality.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindSphericality(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_SPHERICALITY_H diff --git a/python/datapointsfilters/surfacenormal.cpp b/python/datapointsfilters/surfacenormal.cpp new file mode 100644 index 00000000..6fccc8f9 --- /dev/null +++ b/python/datapointsfilters/surfacenormal.cpp @@ -0,0 +1,31 @@ +#include "surfacenormal.h" + +namespace pointmatcher +{ + void pybindSurfaceNormal(py::module& p_module) + { + using SurfaceNormalDataPointsFilter = SurfaceNormalDataPointsFilter; + py::class_, DataPointsFilter> + (p_module, "SurfaceNormalDataPointsFilter") + + .def_static("description", &SurfaceNormalDataPointsFilter::description) + .def_static("availableParameters", &SurfaceNormalDataPointsFilter::availableParameters) + + .def_readonly("knn", &SurfaceNormalDataPointsFilter::knn) + .def_readonly("maxDist", &SurfaceNormalDataPointsFilter::maxDist) + .def_readonly("epsilon", &SurfaceNormalDataPointsFilter::epsilon) + .def_readonly("keepNormals", &SurfaceNormalDataPointsFilter::keepNormals) + .def_readonly("keepDensities", &SurfaceNormalDataPointsFilter::keepDensities) + .def_readonly("keepEigenValues", &SurfaceNormalDataPointsFilter::keepEigenValues) + .def_readonly("keepEigenVectors", &SurfaceNormalDataPointsFilter::keepEigenVectors) + .def_readonly("keepMatchedIds", &SurfaceNormalDataPointsFilter::keepMatchedIds) + .def_readonly("keepMeanDist", &SurfaceNormalDataPointsFilter::keepMeanDist) + .def_readonly("sortEigen", &SurfaceNormalDataPointsFilter::sortEigen) + .def_readonly("smoothNormals", &SurfaceNormalDataPointsFilter::smoothNormals) + + .def(py::init(), py::arg("params") = Parameters(), "Constructor, uses parameter interface") + + .def("filter", &SurfaceNormalDataPointsFilter::filter) + .def("inPlaceFilter", &SurfaceNormalDataPointsFilter::inPlaceFilter); + } +} \ No newline at end of file diff --git a/python/datapointsfilters/surfacenormal.h b/python/datapointsfilters/surfacenormal.h new file mode 100644 index 00000000..297db804 --- /dev/null +++ b/python/datapointsfilters/surfacenormal.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_DATAPOINTSFILTERS_SURFACENORMAL_H +#define PYTHON_DATAPOINTSFILTERS_SURFACENORMAL_H + +#include "DataPointsFilters/SurfaceNormal.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindSurfaceNormal(py::module& p_module); +} + +#endif //PYTHON_DATAPOINTSFILTERS_SURFACENORMAL_H diff --git a/python/errorminimizers/identity.cpp b/python/errorminimizers/identity.cpp new file mode 100644 index 00000000..7973cd9e --- /dev/null +++ b/python/errorminimizers/identity.cpp @@ -0,0 +1,13 @@ +#include "identity.h" + +namespace pointmatcher +{ + void pybindIdentityEM(py::module& p_module) + { + using IdentityErrorMinimizer = ErrorMinimizersImpl::IdentityErrorMinimizer; + py::class_, ErrorMinimizer>(p_module, "IdentityErrorMinimizer") + .def(py::init<>()) + .def_static("description", &IdentityErrorMinimizer::description) + .def("compute", &IdentityErrorMinimizer::compute, py::arg("mPts")); + } +} \ No newline at end of file diff --git a/python/errorminimizers/identity.h b/python/errorminimizers/identity.h new file mode 100644 index 00000000..d2ab9ef4 --- /dev/null +++ b/python/errorminimizers/identity.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_IDENTITY_H +#define PYTHON_ERRORMINIMIZERS_IDENTITY_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindIdentityEM(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_IDENTITY_H diff --git a/python/errorminimizers/pointtoplane.cpp b/python/errorminimizers/pointtoplane.cpp new file mode 100644 index 00000000..58264b05 --- /dev/null +++ b/python/errorminimizers/pointtoplane.cpp @@ -0,0 +1,26 @@ +#include "pointtoplane.h" + +namespace pointmatcher +{ + void pybindPointToPlane(py::module& p_module) + { + using PointToPlaneErrorMinimizer = ErrorMinimizersImpl::PointToPlaneErrorMinimizer; + py::class_, ErrorMinimizer>(p_module, "PointToPlaneErrorMinimizer") + .def(py::init(), py::arg("params") = Parameters()) + .def(py::init(), py::arg("paramsDoc"), py::arg("params") = Parameters()) + + .def_readonly("force2D", &PointToPlaneErrorMinimizer::force2D) + .def_readonly("force4DOF", &PointToPlaneErrorMinimizer::force4DOF) + + .def_static("description", &PointToPlaneErrorMinimizer::description) + .def_static("availableParameters", &PointToPlaneErrorMinimizer::availableParameters) + + .def("name", &PointToPlaneErrorMinimizer::name) + .def("compute", &PointToPlaneErrorMinimizer::compute, py::arg("mPts")) + .def("compute_in_place", &PointToPlaneErrorMinimizer::compute_in_place, py::arg("mPts")) + .def("getResidualError", &PointToPlaneErrorMinimizer::getResidualError, py::arg("filteredReading"), py::arg("filteredReference"), py::arg("outlierWeights"), py::arg("matches")) + .def("getOverlap", &PointToPlaneErrorMinimizer::getOverlap) + + .def_static("computeResidualError", &PointToPlaneErrorMinimizer::computeResidualError, py::arg("mPts"), py::arg("force2D")); + } +} diff --git a/python/errorminimizers/pointtoplane.h b/python/errorminimizers/pointtoplane.h new file mode 100644 index 00000000..29951f48 --- /dev/null +++ b/python/errorminimizers/pointtoplane.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_POINTTOPLANE_H +#define PYTHON_ERRORMINIMIZERS_POINTTOPLANE_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindPointToPlane(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_POINTTOPLANE_H diff --git a/python/errorminimizers/pointtoplanewithcov.cpp b/python/errorminimizers/pointtoplanewithcov.cpp new file mode 100644 index 00000000..c995a3b0 --- /dev/null +++ b/python/errorminimizers/pointtoplanewithcov.cpp @@ -0,0 +1,24 @@ +#include "pointtoplanewithcov.h" + +namespace pointmatcher +{ + void pybindPointToPlaneWithCov(py::module& p_module) + { + using PointToPlaneErrorMinimizer = ErrorMinimizersImpl::PointToPlaneErrorMinimizer; + using PointToPlaneWithCovErrorMinimizer = ErrorMinimizersImpl::PointToPlaneWithCovErrorMinimizer; + + py::class_, PointToPlaneErrorMinimizer>(p_module, "PointToPlaneWithCovErrorMinimizer") + .def("name", &PointToPlaneWithCovErrorMinimizer::name) + + .def_static("description", &PointToPlaneWithCovErrorMinimizer::description) + .def_static("availableParameters", &PointToPlaneWithCovErrorMinimizer::availableParameters) + + .def_readonly("sensorStdDev", &PointToPlaneWithCovErrorMinimizer::sensorStdDev) + .def_readwrite("covMatrix", &PointToPlaneWithCovErrorMinimizer::covMatrix) + + .def(py::init(), py::arg("params") = Parameters()) + .def("compute", &PointToPlaneWithCovErrorMinimizer::compute, py::arg("mPts")) + .def("getCovariance", &PointToPlaneWithCovErrorMinimizer::getCovariance) + .def("estimateCovariance", &PointToPlaneWithCovErrorMinimizer::estimateCovariance, py::arg("mPts"), py::arg("transformation")); + } +} diff --git a/python/errorminimizers/pointtoplanewithcov.h b/python/errorminimizers/pointtoplanewithcov.h new file mode 100644 index 00000000..e49f93d0 --- /dev/null +++ b/python/errorminimizers/pointtoplanewithcov.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_POINTTOPLANEWITHCOV_H +#define PYTHON_ERRORMINIMIZERS_POINTTOPLANEWITHCOV_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindPointToPlaneWithCov(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_POINTTOPLANEWITHCOV_H diff --git a/python/errorminimizers/pointtopoint.cpp b/python/errorminimizers/pointtopoint.cpp new file mode 100644 index 00000000..3adea1ca --- /dev/null +++ b/python/errorminimizers/pointtopoint.cpp @@ -0,0 +1,18 @@ +#include "pointtopoint.h" + +namespace pointmatcher +{ + void pybindPointToPoint(py::module& p_module) + { + using PointToPointErrorMinimizer = ErrorMinimizersImpl::PointToPointErrorMinimizer; + py::class_, ErrorMinimizer>(p_module, "PointToPointErrorMinimizer") + .def(py::init<>()) + .def(py::init(), + py::arg("className"), py::arg("paramsDoc"), py::arg("params")) + .def("compute", &PointToPointErrorMinimizer::compute, py::arg("mPts")) + .def("compute_in_place", &PointToPointErrorMinimizer::compute_in_place, py::arg("mPts")) + .def("getResidualError", &PointToPointErrorMinimizer::getResidualError, py::arg("filteredReading"), py::arg("filteredReference"), py::arg("outlierWeights"), py::arg("matches")) + .def("getOverlap", &PointToPointErrorMinimizer::getOverlap) + .def_static("computeResidualError", &PointToPointErrorMinimizer::computeResidualError, py::arg("mPts")); + } +} diff --git a/python/errorminimizers/pointtopoint.h b/python/errorminimizers/pointtopoint.h new file mode 100644 index 00000000..b5b9c327 --- /dev/null +++ b/python/errorminimizers/pointtopoint.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_POINTTOPOINT_H +#define PYTHON_ERRORMINIMIZERS_POINTTOPOINT_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindPointToPoint(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_POINTTOPOINT_H diff --git a/python/errorminimizers/pointtopointsimilarity.cpp b/python/errorminimizers/pointtopointsimilarity.cpp new file mode 100644 index 00000000..efc4531d --- /dev/null +++ b/python/errorminimizers/pointtopointsimilarity.cpp @@ -0,0 +1,16 @@ +#include "pointtopointsimilarity.h" + +namespace pointmatcher +{ + void pybindPointToPointSimilarity(py::module& p_module) + { + using PointToPointSimilarityErrorMinimizer = ErrorMinimizersImpl::PointToPointSimilarityErrorMinimizer; + py::class_, ErrorMinimizer>(p_module, "PointToPointSimilarityErrorMinimizer") + .def(py::init<>()) + .def_static("description", &PointToPointSimilarityErrorMinimizer::description) + .def("compute", &PointToPointSimilarityErrorMinimizer::compute, py::arg("mPts")) + .def("getResidualError", &PointToPointSimilarityErrorMinimizer::getResidualError, py::arg("filteredReading"), py::arg("filteredReference"), py::arg("outlierWeights"), py::arg("matches")) + .def("getOverlap", &PointToPointSimilarityErrorMinimizer::getOverlap) + ; + } +} \ No newline at end of file diff --git a/python/errorminimizers/pointtopointsimilarity.h b/python/errorminimizers/pointtopointsimilarity.h new file mode 100644 index 00000000..8af2e1ee --- /dev/null +++ b/python/errorminimizers/pointtopointsimilarity.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_POINTTOPOINTSIMILARITY_H +#define PYTHON_ERRORMINIMIZERS_POINTTOPOINTSIMILARITY_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindPointToPointSimilarity(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_POINTTOPOINTSIMILARITY_H diff --git a/python/errorminimizers/pointtopointwithcov.cpp b/python/errorminimizers/pointtopointwithcov.cpp new file mode 100644 index 00000000..03899ea5 --- /dev/null +++ b/python/errorminimizers/pointtopointwithcov.cpp @@ -0,0 +1,19 @@ +#include "pointtopointwithcov.h" + +namespace pointmatcher +{ + void pybindPointToPointWithCov(py::module& p_module) + { + using PointToPointErrorMinimizer = ErrorMinimizersImpl::PointToPointErrorMinimizer; + using PointToPointWithCovErrorMinimizer = ErrorMinimizersImpl::PointToPointWithCovErrorMinimizer; + py::class_, PointToPointErrorMinimizer>(p_module, "PointToPointWithCovErrorMinimizer") + .def(py::init(), py::arg("params") = Parameters()) + .def_readonly("sensorStdDev", &PointToPointWithCovErrorMinimizer::sensorStdDev) + .def_readwrite("covMatrix", &PointToPointWithCovErrorMinimizer::covMatrix) + .def_static("description", &PointToPointWithCovErrorMinimizer::description) + .def_static("availableParameters", &PointToPointWithCovErrorMinimizer::availableParameters) + .def("compute", &PointToPointWithCovErrorMinimizer::compute, py::arg("mPts")) + .def("getCovariance", &PointToPointWithCovErrorMinimizer::getCovariance) + .def("estimateCovariance", &PointToPointWithCovErrorMinimizer::estimateCovariance, py::arg("mPts"), py::arg("transformation")); + } +} \ No newline at end of file diff --git a/python/errorminimizers/pointtopointwithcov.h b/python/errorminimizers/pointtopointwithcov.h new file mode 100644 index 00000000..d2a5d45b --- /dev/null +++ b/python/errorminimizers/pointtopointwithcov.h @@ -0,0 +1,12 @@ +#ifndef PYTHON_ERRORMINIMIZERS_POINTTOPOINTWITHCOV_H +#define PYTHON_ERRORMINIMIZERS_POINTTOPOINTWITHCOV_H + +#include "pointmatcher/ErrorMinimizersImpl.h" +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindPointToPointWithCov(py::module& p_module); +} + +#endif //PYTHON_ERRORMINIMIZERS_POINTTOPOINTWITHCOV_H diff --git a/python/modules/datapointsfilters_module.cpp b/python/modules/datapointsfilters_module.cpp new file mode 100644 index 00000000..9472c0a4 --- /dev/null +++ b/python/modules/datapointsfilters_module.cpp @@ -0,0 +1,59 @@ +#include "datapointsfilters_module.h" + +#include "datapointsfilters/boundingbox.h" +#include "datapointsfilters/covariancesampling.h" +#include "datapointsfilters/cutatdescriptorthreshold.h" +#include "datapointsfilters/distancelimit.h" +#include "datapointsfilters/ellipsoids.h" +#include "datapointsfilters/fixstepsampling.h" +#include "datapointsfilters/gestalt.h" +#include "datapointsfilters/identity.h" +#include "datapointsfilters/incidenceangle.h" +#include "datapointsfilters/maxdensity.h" +#include "datapointsfilters/maxpointcount.h" +#include "datapointsfilters/maxquantileonaxis.h" +#include "datapointsfilters/normalspace.h" +#include "datapointsfilters/observationdirection.h" +#include "datapointsfilters/octreegrid.h" +#include "datapointsfilters/orientnormals.h" +#include "datapointsfilters/randomsampling.h" +#include "datapointsfilters/removenan.h" +#include "datapointsfilters/removesensorbias.h" +#include "datapointsfilters/samplingsurfacenormal.h" +#include "datapointsfilters/shadow.h" +#include "datapointsfilters/simplesensornoise.h" +#include "datapointsfilters/sphericality.h" +#include "datapointsfilters/surfacenormal.h" + +namespace pointmatcher +{ + void pybindDataPointsFiltersModule(py::module& p_module) + { + py::module datapointsfilterModule = p_module.def_submodule("datapointsfilters"); + + pybindBoundingBox(datapointsfilterModule); + pybindCovarianceSampling(datapointsfilterModule); + pybindCutAtDescriptorThreshold(datapointsfilterModule); + pybindDistanceLimit(datapointsfilterModule); + pybindEllipsoids(datapointsfilterModule); + pybindFixStepSampling(datapointsfilterModule); + pybindGestalt(datapointsfilterModule); + pybindIdentityDPF(datapointsfilterModule); + pybindIncidenceAngle(datapointsfilterModule); + pybindMaxDensity(datapointsfilterModule); + pybindMaxPointCount(datapointsfilterModule); + pybindMaxQuantileOnAxis(datapointsfilterModule); + pybindNormalSpace(datapointsfilterModule); + pybindObservationDirection(datapointsfilterModule); + pybindOctreeGrid(datapointsfilterModule); + pybindOrientNormals(datapointsfilterModule); + pybindRandomSampling(datapointsfilterModule); + pybindRemoveNaN(datapointsfilterModule); + pybindRemoveSensorBias(datapointsfilterModule); + pybindSamplingSurfaceNormal(datapointsfilterModule); + pybindShadow(datapointsfilterModule); + pybindSimpleSensorNoise(datapointsfilterModule); + pybindSphericality(datapointsfilterModule); + pybindSurfaceNormal(datapointsfilterModule); + } +} diff --git a/python/modules/datapointsfilters_module.h b/python/modules/datapointsfilters_module.h new file mode 100644 index 00000000..5485b4a6 --- /dev/null +++ b/python/modules/datapointsfilters_module.h @@ -0,0 +1,11 @@ +#ifndef PYTHON_MODULES_DATAPOINTSFILTERS_MODULE_H +#define PYTHON_MODULES_DATAPOINTSFILTERS_MODULE_H + +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindDataPointsFiltersModule(py::module& p_module); +} + +#endif //PYTHON_MODULES_DATAPOINTSFILTERS_MODULE_H diff --git a/python/modules/errorminimizers_module.cpp b/python/modules/errorminimizers_module.cpp new file mode 100644 index 00000000..d2490ab5 --- /dev/null +++ b/python/modules/errorminimizers_module.cpp @@ -0,0 +1,23 @@ +#include "errorminimizers_module.h" + +#include "errorminimizers/identity.h" +#include "errorminimizers/pointtoplane.h" +#include "errorminimizers/pointtoplanewithcov.h" +#include "errorminimizers/pointtopoint.h" +#include "errorminimizers/pointtopointsimilarity.h" +#include "errorminimizers/pointtopointwithcov.h" + +namespace pointmatcher +{ + void pybindErrorMinimizersModule(py::module& p_module) + { + py::module errorminizersModule = p_module.def_submodule("errorminimizers"); + + pybindIdentityEM(errorminizersModule); + pybindPointToPlane(errorminizersModule); + pybindPointToPlaneWithCov(errorminizersModule); + pybindPointToPoint(errorminizersModule); + pybindPointToPointSimilarity(errorminizersModule); + pybindPointToPointWithCov(errorminizersModule); + } +} diff --git a/python/modules/errorminimizers_module.h b/python/modules/errorminimizers_module.h new file mode 100644 index 00000000..8ed9692c --- /dev/null +++ b/python/modules/errorminimizers_module.h @@ -0,0 +1,11 @@ +#ifndef PYTHON_MODULES_ERRORMINIMIZERS_MODULE_H +#define PYTHON_MODULES_ERRORMINIMIZERS_MODULE_H + +#include "pypointmatcher_helper.h" + +namespace pointmatcher +{ + void pybindErrorMinimizersModule(py::module& p_module); +} + +#endif //PYTHON_MODULES_ERRORMINIMIZERS_MODULE_H diff --git a/python/modules/pointmatcher_module.cpp b/python/modules/pointmatcher_module.cpp new file mode 100644 index 00000000..84eea906 --- /dev/null +++ b/python/modules/pointmatcher_module.cpp @@ -0,0 +1,13 @@ +#include "pointmatcher_module.h" +#include "pointmatcher/pointmatcher.h" +#include "pointmatcher/impl.h" + +namespace pointmatcher +{ + void pybindPointMatcherModule(py::module& p_module) + { + py::module pointmatcherModule = p_module.def_submodule("pointmatcher"); + pybindPointMatcher(pointmatcherModule); + pybindImpl(pointmatcherModule); + } +} \ No newline at end of file diff --git a/python/modules/pointmatcher_module.h b/python/modules/pointmatcher_module.h new file mode 100644 index 00000000..f836f981 --- /dev/null +++ b/python/modules/pointmatcher_module.h @@ -0,0 +1,13 @@ +#ifndef PYTHON_MODULES_POINTMATCHER_MODULE_H +#define PYTHON_MODULES_POINTMATCHER_MODULE_H + +#include "pypointmatcher_helper.h" + +namespace py = pybind11; + +namespace pointmatcher +{ + void pybindPointMatcherModule(py::module& p_module); +} + +#endif //PYTHON_MODULES_POINTMATCHER_MODULE_H diff --git a/python/modules/pointmatchersupport_module.cpp b/python/modules/pointmatchersupport_module.cpp new file mode 100644 index 00000000..03eeae27 --- /dev/null +++ b/python/modules/pointmatchersupport_module.cpp @@ -0,0 +1,41 @@ +#include "pointmatchersupport_module.h" + +#include "pointmatchersupport/bibliography.h" +#include "pointmatchersupport/logger.h" +#include "pointmatchersupport/logger_impl.h" +#include "pointmatchersupport/parametrizable.h" +#include "pointmatchersupport/registrar.h" + +namespace pointmatcher +{ + void pybindPointMatcherSupportModule(py::module& p_module) + { + py::module pointmatchersupportModule = p_module.def_submodule("pointmatchersupport"); + + using InvalidModuleType = pms::InvalidModuleType; + py::register_exception(pointmatchersupportModule, "InvalidModuleType"); + + using TransformationError = pms::TransformationError; + py::register_exception(pointmatchersupportModule, "TransformationError"); + + using ConfigurationError = pms::ConfigurationError; + py::register_exception(pointmatchersupportModule, "ConfigurationError"); + + using InvalidElement = pms::InvalidElement; + py::register_exception(pointmatchersupportModule, "InvalidElement"); + + pybindBibliography(pointmatchersupportModule); + pybindParametrizable(pointmatchersupportModule); + pybindLogger(pointmatchersupportModule); + pybindLoggerImpl(pointmatchersupportModule); + pybindRegistrar(pointmatchersupportModule); + + pointmatchersupportModule.def("setLogger", &pms::setLogger, py::arg("newLogger"), + "Set a new logger, protected by a mutex"); + pointmatchersupportModule.def("validateFile", &pms::validateFile, py::arg("fileName"), + "Throw a runtime_error exception if fileName cannot be opened"); + + using CsvElements = pms::CsvElements; + py::bind_map(pointmatchersupportModule, "CsvElements"); + } +} \ No newline at end of file diff --git a/python/modules/pointmatchersupport_module.h b/python/modules/pointmatchersupport_module.h new file mode 100644 index 00000000..d2bdc7d6 --- /dev/null +++ b/python/modules/pointmatchersupport_module.h @@ -0,0 +1,14 @@ +#ifndef PYTHON_MODULES_POINTMATCHERSUPPORT_MODULE_H +#define PYTHON_MODULES_POINTMATCHERSUPPORT_MODULE_H + +#include "pypointmatcher_helper.h" + +namespace py = pybind11; +namespace pms = PointMatcherSupport; + +namespace pointmatcher +{ + void pybindPointMatcherSupportModule(py::module& p_module); +} + +#endif //PYTHON_MODULES_POINTMATCHERSUPPORT_MODULE_H diff --git a/python/pointmatcher/datapoints.cpp b/python/pointmatcher/datapoints.cpp new file mode 100644 index 00000000..0563a98b --- /dev/null +++ b/python/pointmatcher/datapoints.cpp @@ -0,0 +1,177 @@ +#include "datapoints.h" + +namespace pointmatcher +{ + void pybindDataPoints(py::class_& p_class) + { + using View = DataPoints::View; + using TimeView = DataPoints::TimeView; + using ConstView = DataPoints::ConstView; + using TimeConstView = DataPoints::TimeConstView; + + py::class_ pyDataPoints(p_class, "DataPoints"); + + pyDataPoints.doc() = R"pbdoc( + A point cloud + + For every point, it has features and, optionally, descriptors. + Features are typically the coordinates of the point in the space. + Descriptors contain information attached to the point, such as its color, its normal vector, etc. + In both features and descriptors, every point can have multiple channels. + Every channel has a dimension and a name. + For instance, a typical 3D cloud might have the channels \c x, \c y, \c z, \c w of dimension 1 as features (using homogeneous coordinates), and the channel \c normal of size 3 as descriptor. + There are no sub-channels, such as \c normal.x, for the sake of simplicity. + Moreover, the position of the points is in homogeneous coordinates because they need both translation and rotation, while the normals need only rotation. + All channels contain scalar values of type ScalarType.)pbdoc"; + + py::class_