Skip to content

sylva.filters

sylva.filters

Subsampling, cropping, noise filtering and local geometry.

voxel_downsample

voxel_downsample(cloud: PointCloud, voxel_size: float, method: str = 'first', origin=None) -> PointCloud

Thin a cloud to at most one point per cubic voxel.

Evens out the density falloff with range from each scanner, which otherwise weights everything near the scanner. The grid starts at the cloud's minimum corner, or at origin.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
voxel_size float

Voxel edge length (m).

required
method ('first', 'centroid')

"first" keeps one original point per voxel (the first in file order), with its attributes; "centroid" returns the mean of the points in each voxel and drops attributes.

"first"
origin

(x, y, z) of a corner of the voxel grid, so that different clouds are thinned on one grid ((0, 0, 0) for voxels at multiples of voxel_size, as sylva.als.tiles.from_scans and sylva.als.tiles.voxel_downsample use); "first" only.

None

Returns:

Type Description
PointCloud

With "first", points stay in their original order.

Raises:

Type Description
ValueError

For an unknown method, or an origin with "centroid".

random_subsample

random_subsample(cloud: PointCloud, n: int | None = None, fraction: float | None = None, seed: int = 0) -> PointCloud

Random subsample without replacement.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
n int | None

Number of points to keep.

None
fraction float | None

Fraction of points to keep (0-1). Give exactly one of n and fraction.

None
seed int

Random seed; the same seed gives the same subsample.

0

Returns:

Type Description
PointCloud

The selected points in their original order.

Raises:

Type Description
ValueError

If both or neither of n and fraction are given.

min_distance_subsample

min_distance_subsample(cloud: PointCloud, distance: float) -> PointCloud

Thin to an even spacing: no two kept points closer than distance.

An approximate Poisson-disk sample. Unlike voxel_downsample the result has no grid pattern, which suits normals, curvature and segmentation.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
distance float

Minimum spacing (m).

required

Returns:

Type Description
PointCloud

Original points (with attributes) in their original order.

crop_box

crop_box(cloud: PointCloud, min_xyz, max_xyz) -> PointCloud

Keep points inside an axis-aligned box (bounds inclusive).

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
min_xyz

Three lower and three upper bounds. None or NaN leaves that side open, e.g. crop_box(c, (None, None, 0.5), (None, None, None)).

required
max_xyz

Three lower and three upper bounds. None or NaN leaves that side open, e.g. crop_box(c, (None, None, 0.5), (None, None, None)).

required

Returns:

Type Description
PointCloud

crop_cylinder

crop_cylinder(cloud: PointCloud, center_xy, radius: float, zmin: float = -np.inf, zmax: float = np.inf) -> PointCloud

Keep points inside a vertical cylinder, e.g. a circular plot.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
center_xy

Plot centre (x, y).

required
radius float

Horizontal radius (m).

required
zmin float

Vertical limits on z (not on height above ground).

-inf
zmax float

Vertical limits on z (not on height above ground).

-inf

Returns:

Type Description
PointCloud

range_filter

range_filter(cloud: PointCloud, origin=(0.0, 0.0, 0.0), min_range: float = 0.0, max_range: float = np.inf) -> PointCloud

Keep points by 3D distance from a scanner.

Parameters:

Name Type Description Default
cloud PointCloud

Input points, in the same frame as origin.

required
origin

Scanner position.

(0.0, 0.0, 0.0)
min_range float

Distance limits (m), inclusive.

0.0
max_range float

Distance limits (m), inclusive.

0.0

Returns:

Type Description
PointCloud

statistical_outlier_removal

statistical_outlier_removal(cloud: PointCloud, k: int = 8, std_ratio: float = 2.0, return_mask: bool = False)

Remove isolated points by their distance to neighbours (Rusu et al. 2008).

For each point the mean distance to its k nearest neighbours is computed; points where this exceeds mean + std_ratio * std over the whole cloud are dropped. Removes flying points and edge effects. Because the threshold is global, run it per scan or on a thinned cloud when density varies strongly with range.

This is the SOR filter of CloudCompare (CloudSamplingTools::sorFilter): the same mean distance (the point itself excluded), population mean and standard deviation, and keep condition. k=6, std_ratio=1.0 gives CloudCompare's defaults.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
k int

Neighbours per point.

8
std_ratio float

Threshold in standard deviations; lower removes more.

2.0
return_mask bool

Return the boolean keep-mask instead of the filtered cloud.

False

Returns:

Type Description
PointCloud or ndarray

The kept points, or the mask (True = keep) with return_mask.

radius_outlier_removal

radius_outlier_removal(cloud: PointCloud, radius: float, min_neighbors: int = 4, return_mask: bool = False)

Remove points with too few neighbours within a fixed radius.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
radius float

Search radius (m).

required
min_neighbors int

Points with fewer other points within radius are dropped.

4
return_mask bool

Return the boolean keep-mask instead of the filtered cloud.

False

Returns:

Type Description
PointCloud or ndarray

The kept points, or the mask (True = keep) with return_mask.

estimate_normals

estimate_normals(cloud: PointCloud, k: int = 12) -> np.ndarray

Surface normals from local principal components.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
k int

Neighbours used for each point's covariance.

12

Returns:

Type Description
ndarray

(N, 3) unit normals (eigenvector of the smallest eigenvalue). The sign is arbitrary; orient them yourself if needed.

planarity_linearity

planarity_linearity(cloud: PointCloud, k: int = 20) -> tuple[np.ndarray, np.ndarray]

Local shape descriptors from neighbourhood eigenvalues.

With the covariance eigenvalues of the k neighbours sorted l1 <= l2 <= l3, planarity is (l2 - l1) / l3 and linearity is (l3 - l2) / l3 (Weinmann et al. 2015). Both lie in 0-1; stems and branches are linear, leaves and ground planar.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
k int

Neighbours per point.

20

Returns:

Type Description
planarity, linearity : numpy.ndarray

One value per point.

euclidean_clusters

euclidean_clusters(xyz: ndarray, radius: float, min_points: int = 1) -> np.ndarray

Group points into clusters joined by chains of close points.

Two points are connected if they are within radius; clusters are the connected components.

Parameters:

Name Type Description Default
xyz ndarray

(N, 3) coordinates (e.g. cloud.xyz).

required
radius float

Linking distance (m).

required
min_points int

Clusters smaller than this are labelled -1.

1

Returns:

Type Description
ndarray

int64 label per point: 0 is the largest cluster, 1 the next, ...; -1 for points in clusters that are too small.

knn

knn(xyz: ndarray, queries: ndarray, k: int) -> tuple[np.ndarray, np.ndarray]

k nearest neighbours of query points (kd-tree).

Parameters:

Name Type Description Default
xyz ndarray

(N, 3) points to search.

required
queries ndarray

(M, 3) query points. A query that is also in xyz finds itself at distance 0.

required
k int

Neighbours per query.

required

Returns:

Type Description
distances, indices : numpy.ndarray

(M, k) arrays, nearest first.