Basic M3C2 algorithm

This presents how the M3C2 algorithm (Lague et al., 2013) for point cloud distance computation can be run using the py4dgeo package. As a first step, we import the py4dgeo and numpy packages:

[1]:
import numpy as np
import py4dgeo

Next, we need to load two datasets that cover the same scene at two different points in time. Point cloud datasets are represented by numpy arrays of shape n x 3 using a 64 bit floating point type (np.float64). Here, we work with a rather small synthetical data set:

[2]:
epoch1, epoch2 = py4dgeo.read_from_xyz(
    "plane_horizontal_t1.xyz", "plane_horizontal_t2.xyz"
)
[2024-05-14 13:00:45][INFO] Reading point cloud from file '/home/docs/.cache/py4dgeo/./plane_horizontal_t1.xyz'
[2024-05-14 13:00:45][INFO] Reading point cloud from file '/home/docs/.cache/py4dgeo/./plane_horizontal_t2.xyz'

The analysis of point cloud distances is executed on so-called core points (cf. Lague et al., 2013). These could be, e.g., one of the input point clouds, a subsampled version thereof, points in an equidistant grid, etc. Here, we choose a subsampling by taking every 50th point of the reference point cloud:

[3]:
corepoints = epoch1.cloud[::50]

Next, we instantiate the algorithm class and run the distance calculation:

[4]:
m3c2 = py4dgeo.M3C2(
    epochs=(epoch1, epoch2),
    corepoints=corepoints,
    cyl_radii=(2.0,),
    normal_radii=(0.5, 1.0, 2.0),
)

distances, uncertainties = m3c2.run()
[2024-05-14 13:00:45][INFO] Building KDTree structure with leaf parameter 10
[2024-05-14 13:00:45][INFO] Building KDTree structure with leaf parameter 10

The calculated result is an array with one distance per core point. The order of distances corresponds exactly to the order of input core points.

[5]:
distances
[5]:
array([-0.10269298, -0.09957772, -0.10179986, -0.10063675, -0.10091512,
       -0.10070981, -0.09819643, -0.09926434, -0.09911222])

Corresponding to the derived distances, an uncertainty array is returned which contains several quantities that can be accessed individually: The level of detection lodetection, the spread of the distance across points in either cloud (spread1 and spread2, by default measured as the standard deviation of distances) and the total number of points taken into consideration in either cloud (num_samples1 and num_samples2):

[6]:
uncertainties["lodetection"]
[6]:
array([0.00565384, 0.00181819, 0.00255157, 0.00332511, 0.00281475,
       0.00299644, 0.00295429, 0.00199006, 0.00360769])
[7]:
uncertainties["spread1"]
[7]:
array([0.00417673, 0.00193209, 0.00203436, 0.00368965, 0.00259167,
       0.00286324, 0.0032822 , 0.00247362, 0.00356988])
[8]:
uncertainties["num_samples1"]
[8]:
array([ 5, 11, 11, 11, 12, 10, 11, 12, 10])

References

  • Lague, D., Brodu, N., & Leroux, J. (2013). Accurate 3D comparison of complex topography with terrestrial laser scanner: Application to the Rangitikei canyon (N-Z). ISPRS Journal of Photogrammetry and Remote Sensing, 82, pp. 10-26. doi: 10.1016/j.isprsjprs.2013.04.009.