icp.py
Go to the documentation of this file.
1 # Code example for ICP taking 2 points clouds (2D or 3D) relatively close
2 # and computing the transformation between them.
3 #
4 # This code is more complete than icp_simple. It can load parameter files and
5 # has more options.
6 
7 import numpy as np
8 
9 from pypointmatcher import pointmatcher as pm
10 from utils import parse_translation, parse_rotation
11 
12 PM = pm.PointMatcher
13 DP = PM.DataPoints
14 
15 # Save transformation matrix in three different files:
16 # - BASEFILENAME_inti_transfo.txt
17 # - BASEFILENAME_icp_transfo.txt
18 # - BASEFILENAME_complete_transfo.txt
19 # (default: false)
20 is_transfo_saved = False
21 
22 # Be more verbose (info logging to the console)
23 is_verbose = True
24 
25 # Load the config from a YAML file (default: default.yaml)
26 # Leave empty to set the ICP default configuration
27 config_file = "../data/default.yaml"
28 
29 # Path of output directory (default: tests/icp/)
30 # The output directory must already exist
31 # Leave empty to save in the current directory
32 output_base_directory = "tests/icp/"
33 
34 # Name of output files (default: test)
35 output_base_file = "test"
36 
37 # Toggle to switch between 2D and 3D point clouds
38 is_3D = True
39 
40 # Add an initial 3D translation before applying ICP (default: 0,0,0)
41 # Add an initial 2D translation before applying ICP (default: 0,0)
42 init_translation = "0,0,0" if is_3D else "0,0"
43 # Add an initial 3D rotation before applying ICP (default: 1,0,0;0,1,0;0,0,1)
44 # Add an initial 2D rotation before applying ICP (default: 1,0;0,1)
45 init_rotation = "1,0,0;0,1,0;0,0,1" if is_3D else "1,0;0,1"
46 
47 if is_3D:
48  # Load 3D point clouds
49  ref = DP(DP.load('../data/car_cloud400.csv'))
50  data = DP(DP.load('../data/car_cloud401.csv'))
51  test_base = "3D"
52 else:
53  # Load 2D point clouds
54  ref = DP(DP.load('../data/2D_twoBoxes.csv'))
55  data = DP(DP.load('../data/2D_oneBox.csv'))
56  test_base = "2D"
57 
58 # Create the default ICP algorithm
59 icp = PM.ICP()
60 
61 if len(config_file) == 0:
62  # See the implementation of setDefault() to create a custom ICP algorithm
63  icp.setDefault()
64 else:
65  # load YAML config
66  icp.loadFromYaml(config_file)
67 
68 cloud_dimension = ref.getEuclideanDim()
69 
70 assert cloud_dimension == 2 or cloud_dimension == 3, "Invalid input point clouds dimension"
71 
72 # Parse the translation and rotation to be used to compute the initial transformation
73 translation = parse_translation(init_translation, cloud_dimension)
74 rotation = parse_rotation(init_rotation, cloud_dimension)
75 
76 init_transfo = np.matmul(translation, rotation)
77 
78 rigid_trans = PM.get().TransformationRegistrar.create("RigidTransformation")
79 
80 if not rigid_trans.checkParameters(init_transfo):
81  print("Initial transformations is not rigid, identiy will be used")
82  init_transfo = np.identity(cloud_dimension + 1)
83 
84 initialized_data = rigid_trans.compute(data, init_transfo)
85 
86 # Compute the transformation to express data in ref
87 T = icp(initialized_data, ref)
88 
89 if is_verbose:
90  print(f"match ratio: {icp.errorMinimizer.getWeightedPointUsedRatio():.6}")
91 
92 # Transform data to express it in ref
93 data_out = DP(initialized_data)
94 icp.transformations.apply(data_out, T)
95 
96 # Save files to see the results
97 ref.save(f"{output_base_directory + test_base}_{output_base_file}_ref.vtk")
98 data.save(f"{output_base_directory + test_base}_{output_base_file}_data_in.vtk")
99 data_out.save(f"{output_base_directory + test_base}_{output_base_file}_data_out.vtk")
100 
101 if is_transfo_saved:
102  init_file_name = f"{output_base_directory + test_base}_{output_base_file}_init_transfo.txt"
103  icp_file_name = f"{output_base_directory + test_base}_{output_base_file}_icp.transfo.txt"
104  complete_file_name = f"{output_base_directory + test_base}_{output_base_file}_complete_transfo.txt"
105 
106  with open(init_file_name, "w") as f:
107  f.write(f"{init_transfo}".replace("[", " ").replace("]", " "))
108 
109  with open(icp_file_name, "w") as f:
110  f.write(f"{T}".replace("[", " ").replace("]", " "))
111 
112  with open(complete_file_name, "w") as f:
113  f.write(f"{np.matmul(T, init_transfo)}".replace("[", " ").replace("]", " "))
114 
115 else:
116  if is_verbose:
117  print(f"{test_base} ICP transformation:\n{T}".replace("[", " ").replace("]", " "))
utils.parse_translation
def parse_translation(str p_translation, int p_cloud_dim)
Definition: utils.py:9
PointMatcher::DataPoints
A point cloud.
Definition: PointMatcher.h:207
icp
Definition: icp.py:1
utils.parse_rotation
def parse_rotation(str p_rotation, int p_cloud_dim)
Definition: utils.py:22


libpointmatcher
Author(s):
autogenerated on Thu Mar 28 2024 02:22:22