Skip to content

utils

estimate_spacing(coords)

Estimate the spacing between points in a point cloud. This is just the median distance between nearest neighbors.

Parameters:

Name Type Description Default
coords NDArray[floating]

The point cloud to estimate spacing of. Should have shape (npoint, ndim).

required

Returns:

Name Type Description
spacing float

The spacing between points.

Source code in megham/utils.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
def estimate_spacing(coords: NDArray[np.floating]) -> float:
    """
    Estimate the spacing between points in a point cloud.
    This is just the median distance between nearest neighbors.

    Parameters
    ----------
    coords : NDArray[np.floating]
        The point cloud to estimate spacing of.
        Should have shape (npoint, ndim).

    Returns
    -------
    spacing : float
        The spacing between points.
    """
    edm = make_edm(coords)
    edm[edm == 0] = np.nan
    nearest_dists = np.nanmin(edm, axis=0)

    return np.median(nearest_dists)

estimate_var(src, dst, dim_groups=None)

Estimate variance between point clouds for use with something like a GMM.

Parameters:

Name Type Description Default
src NDArray[floating]

The set of source points to be mapped onto the target points. Should have shape (nsrcpoints, ndim).

required
dst NDArray[floating]

The set of destination points to be mapped onto. Should have shape (ndstpoints, ndim).

required
dim_groups Optional[Sequence[Sequence[int] | NDArray[int_]]]

Which dimensions should be computed together. If None all dimensions will be treated seperately.

None

Returns:

Name Type Description
var NDArray[floating]

The estimated variance. Will have shape (ndim,).

Source code in megham/utils.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def estimate_var(
    src: NDArray[np.floating],
    dst: NDArray[np.floating],
    dim_groups: Optional[Sequence[Sequence[int] | NDArray[np.int_]]] = None,
) -> NDArray[np.floating]:
    """
    Estimate variance between point clouds for use with something like a GMM.

    Parameters
    ----------
    src : NDArray[np.floating]
        The set of source points to be mapped onto the target points.
        Should have shape (nsrcpoints, ndim).
    dst : NDArray[np.floating]
        The set of destination points to be mapped onto.
        Should have shape (ndstpoints, ndim).
    dim_groups : Optional[Sequence[Sequence[int] | NDArray[np.int_]]], default: None
        Which dimensions should be computed together.
        If None all dimensions will be treated seperately.

    Returns
    -------
    var : NDArray[np.floating]
        The estimated variance.
        Will have shape (ndim,).
    """
    nsrcpoints, ndim = src.shape
    ndstpoints = len(dst)

    if dim_groups is None:
        dim_groups = [[dim] for dim in range(ndim)]
    else:
        dims_flat = np.concatenate(dim_groups)
        no_group = np.setdiff1d(np.arange(ndim), dims_flat)
        dim_groups = list(dim_groups)
        dim_groups = dim_groups + [[dim] for dim in no_group]

    var = np.zeros(ndim)
    for dim_group in dim_groups:
        sq_diff = dist.cdist(src[:, dim_group], dst[:, dim_group], metric="sqeuclidean")
        var[dim_group] = np.nansum(sq_diff) / (len(dim_group) * nsrcpoints * ndstpoints)

    return var

gen_weights(src, dst, var=None, pdf=False)

Generate weights between points in two registered point clouds. The weight here is just the liklihood from a gaussian. Note that this is not a GMM, each weight is computed from a single gaussian since we are assuming a known registration.

Parameters:

Name Type Description Default
src NDArray[floating]

The set of source points to be mapped onto the target points. Should have shape (nsrcpoints, ndim).

required
dst NDArray[floating]

The set of destination points to be mapped onto. Should have shape (ndstpoints, ndim).

required
var Optional[NDArray[floating]]

The variance along each axis. Should have shape (ndim,) if provided. If None, will be computed with estimate_var

None
pdf bool

If True apply the 1/sqrt(2pivar) normalization factor. This makes the weights the PDF of a normal distribution.

False

Returns:

Name Type Description
weights NDArray[floating]

(npoints,) array of weights.

Source code in megham/utils.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def gen_weights(
    src: NDArray[np.floating],
    dst: NDArray[np.floating],
    var: Optional[NDArray[np.floating]] = None,
    pdf: bool = False,
) -> NDArray[np.floating]:
    """
    Generate weights between points in two registered point clouds.
    The weight here is just the liklihood from a gaussian.
    Note that this is not a GMM, each weight is computed from a single
    gaussian since we are assuming a known registration.

    Parameters
    ----------
    src : NDArray[np.floating]
        The set of source points to be mapped onto the target points.
        Should have shape (nsrcpoints, ndim).
    dst : NDArray[np.floating]
        The set of destination points to be mapped onto.
        Should have shape (ndstpoints, ndim).
    var : Optional[NDArray[np.floating]], default: None
        The variance along each axis.
        Should have shape (ndim,) if provided.
        If None, will be computed with estimate_var
    pdf : bool, default: False
        If True apply the 1/sqrt(2*pi*var) normalization factor.
        This makes the weights the PDF of a normal distribution.

    Returns
    -------
    weights : NDArray[np.floating]
        (npoints,) array of weights.
    """
    if var is None:
        var = estimate_var(src, dst)
    norm = np.ones_like(var)
    if pdf:
        norm = 1.0 / np.sqrt(2 * np.pi * var)

    # Compute nd gaussian for each pair
    weights = np.prod(norm * np.exp(-0.5 * (src - dst) ** 2 / var), axis=1)

    return weights

make_edm(coords)

Make an Euclidean distance matrix from a set of points.

Parameters:

Name Type Description Default
coords NDArray[floating]

The (npoint, ndim) array of input points.

required

Returns:

Name Type Description
edm NDArray[floating]

The (npoint, npoint) euclidean distance matrix.

Source code in megham/utils.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def make_edm(coords: NDArray[np.floating]) -> NDArray[np.floating]:
    """
    Make an Euclidean distance matrix from a set of points.

    Parameters
    ----------
    coords : NDArray[np.floating]
        The (npoint, ndim) array of input points.

    Returns
    -------
    edm : NDArray[np.floating]
        The (npoint, npoint) euclidean distance matrix.
    """
    dist_vec = dist.pdist(coords)
    edm = dist.squareform(dist_vec)

    return edm