Point Cloud Metrics

Point Cloud Utils has functions to compute a number of commonly used metrics between point clouds.

Chamfer Distance

The Chamfer distance between two point clouds P1={xiR3}i=1n and P2={xjR3}j=1m is defined as the average distance between pairs of nearest neighbors between P1 and P2 i.e. chamfer(P1,P2)=12ni=1n|xiNN(xi,P2)|+12mj=1n|xjNN(xj,P1)| and NN(x,P)=argminxPxx is the nearest neighbor function.

The following code computes the Chamfer distance between two point clouds:

import point_cloud_utils as pcu

# p1 is an (n, 3)-shaped numpy array containing one point per row
p1 = pcu.load_mesh_v("point_cloud_1.ply")

# p2 is an (m, 3)-shaped numpy array containing one point per row
p2 = pcu.load_mesh_v("point_cloud_2.ply")

# Compute the chamfer distance between p1 and p2
cd = pcu.chamfer_distance(p1, p2)

Hausdorff distance

The Hausdorff distance between two point clouds P1={xiR3}i=1n and P2={xjR3}j=1m is defined as the maxmimum distance between any pair of nearest neighbors between P1 and P2 i.e. hausdorff(P1,P2)=12maxxP1|xNN(x,P2)|+12maxxP2|xNN(x,P1)| and NN(x,P)=argminxPxx is the nearest neighbor function.

The following code computes the Hausdorff distance between two point clouds:

import point_cloud_utils as pcu

# p1 is an (n, 3)-shaped numpy array containing one point per row
p1 = pcu.load_mesh_v("point_cloud_1.ply")

# p2 is an (m, 3)-shaped numpy array containing one point per row
p2 = pcu.load_mesh_v("point_cloud_2.ply")

# Compute the chamfer distance between p1 and p2
hd = pcu.hausdorff_distance(p1, p2)

One sided Hausdorff distance

In some applications, one only needs the one-sided Hausdorff distance between P1 and P2, i.e.

hausdorffP1P2(P1,P2)=maxxP1xNN(x,P2)

The following code computes the one-sided Hausdorff distance between two point clouds:

import point_cloud_utils as pcu

# p1 is an (n, 3)-shaped numpy array containing one point per row
p1 = pcu.load_mesh_v("point_cloud_1.ply")

# p2 is an (m, 3)-shaped numpy array containing one point per row
p2 = pcu.load_mesh_v("point_cloud_2.ply")

# Compute the chamfer distance between p1 and p2
hd_p1_to_p2 = pcu.one_sided_hausdorff_distance(p1, p2)

Note

To get the P2P1 Hausdorff distance, just swap the arguments to pcu.one_sided_hausdorff_distance

Earth-Mover's (Sinkhorn) distance

The Earth Mover's distance between two point clouds P={piR3}i=1n and Q={qjR3}j=1m is computed as the average distance between pairs of points according to an optimal correspondence πΠ(P,Q), where Π(P,Q) is the set of n×m matrices where the rows and columns sum to one. The assignment π is thus a matrix where Πi,j is a number between 0 and 1 denoting how much point pi and qj correspond. We can write the EMD formally as: EMD(P,Q)=minπΠ(P,Q)i=1nj=1mπi,j|piqj|

Point Cloud Utils implements the sinkhorn algorithm for computing the (approximate) Earth Mover's Distance. To compute the EMD, run:

import point_cloud_utils as pcu

# p1 is an (n, 3)-shaped numpy array containing one point per row
p1 = pcu.load_mesh_v("point_cloud_1.ply")

# p2 is an (m, 3)-shaped numpy array containing one point per row
p2 = pcu.load_mesh_v("point_cloud_2.ply")

# Compute the chamfer distance between p1 and p2
emd, pi = pcu.earth_movers_distance(p1, p2)