Point Cloud Registration
In order to lower the uncertainty of calculations done with py4dgeo
, point cloud registration should be performed to tightly align the point clouds. py4dgeo
supports this in two ways:
It allows you to apply arbitrary affine transformations to epochs and stores the transformation parameters as part of the epoch. You can use the tooling of your choice to calculate these.
It provides a number of registration algorithms that allow you to calculate the transformation directly in
py4dgeo
. Currently, this is limited to standard ICP.
This notebook show cases both ways of usage.
Note: Be aware that an initial transformation is required that roughly aligns the two point clouds.
[1]:
import py4dgeo
import numpy as np
We load two epochs and register them to each other:
[2]:
epoch1 = py4dgeo.read_from_xyz("plane_horizontal_t1.xyz") # replace with own data
epoch2 = py4dgeo.read_from_xyz("plane_horizontal_t2.xyz") # replace with own data
[2024-05-14 13:04:38][INFO] Reading point cloud from file '/home/docs/.cache/py4dgeo/./plane_horizontal_t1.xyz'
[2024-05-14 13:04:38][INFO] Reading point cloud from file '/home/docs/.cache/py4dgeo/./plane_horizontal_t2.xyz'
Registration algorithms use a simple function call interface. It returns an affine transformation as a 3x4
matrix which contains the Rotation matrix \(\mathbf{R}\) and the translation vector \(\mathbf{t}\):
When calculating and applying such transformations in py4dgeo
, it is always possible to specify the reduction point \(\mathbf{x_0}\). This allows shifting coordinates towards the origin before applying rotations - leading to a numerically robust operation. The algorithm for a transformation is:
[3]:
trafo = py4dgeo.iterative_closest_point(
epoch1, epoch2, reduction_point=np.array([0, 0, 0])
)
[2024-05-14 13:04:38][INFO] Building KDTree structure with leaf parameter 10
This transformation can then be used to transform epoch2
:
[4]:
epoch2.transform(trafo)
## or use an external transformation matrix
# external_trafo = np.loadtxt("trafo.txt") # replace with own data
# epoch2.transform(external_trafo)
The Epoch
class records applied transformations and makes them available through the transformation
property:
[5]:
epoch2.transformation
[5]:
[Transformation(affine_transformation=array([[ 1.00000000e+00, 6.34089843e-10, -1.42106695e-05,
-7.59183919e-03],
[-1.25012920e-10, 9.99999999e-01, 3.58235678e-05,
7.09922947e-03],
[ 1.42106695e-05, -3.58235678e-05, 9.99999999e-01,
2.11030351e+01],
[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
1.00000000e+00]]), reduction_point=array([0, 0, 0]))]
Finally, we can export the transformed epoch to inspect the registration quality e.g. in CloudCompare.
[6]:
# epoch2.save("plane_horizontal_t2_transformed.xyz") # replace with own data
Available registration algorithms
Currently only standard point to point ICP is available, but other algorithms are currently implemented:
[7]:
?py4dgeo.iterative_closest_point