Skip to content

Filters Module

classify_ground_points(arrays, ignore_class='Classification[7:7]', cell=1.0, cut=0.0, returns='last,only', scalar=1.25, slope=0.15, threshold=0.5, window=18.0)

Apply the SMRF (Simple Morphological Filter) to classify ground points in the point cloud arrays.

Parameters:

Name Type Description Default
arrays list

Cleaned point cloud arrays after outlier removal, typically as a list of structured arrays.

required
ignore_class str

Classification codes to ignore during filtering, e.g., "Classification[7:7]". Defaults to "Classification[7:7]".

'Classification[7:7]'
cell float

Cell size in meters for the morphological filter grid. Defaults to 1.0.

1.0
cut float

Cut net size; if set to 0, net cutting is skipped. Defaults to 0.0.

0.0
returns str

Return types to include in output. Supported values include "first", "last", "intermediate", "only". Defaults to "last,only".

'last,only'
scalar float

Elevation scalar for filter sensitivity. Defaults to 1.25.

1.25
slope float

Slope threshold for ground classification. Defaults to 0.15.

0.15
threshold float

Elevation threshold for morphological operations. Defaults to 0.5.

0.5
window float

Maximum window size in meters for filter application. Defaults to 18.0.

18.0

Returns:

Name Type Description
list List

Point cloud arrays with classified ground points.

Raises:

Type Description
RuntimeError

If there is an error during pipeline execution.

ValueError

If no data is returned after SMRF classification.

Source code in pyforestscan/filters.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def classify_ground_points(
        arrays,
        ignore_class="Classification[7:7]",
        cell=1.0,
        cut=0.0,
        returns="last,only",
        scalar=1.25,
        slope=0.15,
        threshold=0.5,
        window=18.0
) -> List:
    """
    Apply the SMRF (Simple Morphological Filter) to classify ground points in the point cloud arrays.

    Args:
        arrays (list): Cleaned point cloud arrays after outlier removal, typically as a list
            of structured arrays.
        ignore_class (str, optional): Classification codes to ignore during filtering,
            e.g., "Classification[7:7]". Defaults to "Classification[7:7]".
        cell (float, optional): Cell size in meters for the morphological filter grid. Defaults to 1.0.
        cut (float, optional): Cut net size; if set to 0, net cutting is skipped. Defaults to 0.0.
        returns (str, optional): Return types to include in output. Supported values include
            "first", "last", "intermediate", "only". Defaults to "last,only".
        scalar (float, optional): Elevation scalar for filter sensitivity. Defaults to 1.25.
        slope (float, optional): Slope threshold for ground classification. Defaults to 0.15.
        threshold (float, optional): Elevation threshold for morphological operations. Defaults to 0.5.
        window (float, optional): Maximum window size in meters for filter application. Defaults to 18.0.

    Returns:
        list: Point cloud arrays with classified ground points.

    Raises:
        RuntimeError: If there is an error during pipeline execution.
        ValueError: If no data is returned after SMRF classification.
    """
    pipeline_stages = [
        _filter_smrf(
            cell=cell,
            cut=cut,
            ignore=ignore_class,
            returns=returns,
            scalar=scalar,
            slope=slope,
            threshold=threshold,
            window=window
        )
    ]

    try:
        pipeline = _build_pdal_pipeline(arrays, pipeline_stages)
    except RuntimeError as e:
        raise RuntimeError(f"SMRF Classification Pipeline Failed: {e}")

    processed_arrays = pipeline.arrays

    if not processed_arrays:
        raise ValueError("No data returned after SMRF classification.")

    return processed_arrays

downsample_poisson(arrays, thin_radius)

Downsample point cloud arrays using Poisson (radius-based) thinning.

This function applies a radius-based filter to the input point cloud arrays, reducing the point density so that no two points are closer than the specified radius.

Parameters:

Name Type Description Default
arrays list

List of point cloud arrays to be downsampled.

required
thin_radius float

Minimum allowed distance (radius) between retained points, in the same units as the point cloud coordinates.

required

Returns:

Name Type Description
list List

List of downsampled point cloud arrays.

Source code in pyforestscan/filters.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
def downsample_poisson(arrays, thin_radius) -> List:
    """
    Downsample point cloud arrays using Poisson (radius-based) thinning.

    This function applies a radius-based filter to the input point cloud arrays,
    reducing the point density so that no two points are closer than the specified radius.

    Args:
        arrays (list): List of point cloud arrays to be downsampled.
        thin_radius (float): Minimum allowed distance (radius) between retained points, in the same units as the point cloud coordinates.

    Returns:
        list: List of downsampled point cloud arrays.
    """
    pipeline = _build_pdal_pipeline(arrays, [_filter_radius(thin_radius)])
    return pipeline.arrays

filter_ground(arrays)

Remove ground points (classification 2) from a list of point cloud arrays.

Parameters:

Name Type Description Default
arrays list

List of point cloud arrays to be processed.

required

Returns:

Name Type Description
list List

List of point cloud arrays after removing points classified as ground (classification 2).

Source code in pyforestscan/filters.py
32
33
34
35
36
37
38
39
40
41
42
43
def filter_ground(arrays) -> List:
    """
    Remove ground points (classification 2) from a list of point cloud arrays.

    Args:
        arrays (list): List of point cloud arrays to be processed.

    Returns:
        list: List of point cloud arrays after removing points classified as ground (classification 2).
    """
    pipeline = _build_pdal_pipeline(arrays, [_filter_ground()])
    return pipeline.arrays

filter_hag(arrays, lower_limit=0, upper_limit=None)

Apply a Height Above Ground (HAG) filter to a list of point cloud arrays.

Filters each input array to include only points where Height Above Ground is within the specified range.

Parameters:

Name Type Description Default
arrays list

List of point cloud arrays to be processed.

required
lower_limit int or float

Minimum Height Above Ground value to keep. Defaults to 0.

0
upper_limit int or float

Maximum Height Above Ground value to keep. If None, no upper limit is applied. Defaults to None.

None

Returns:

Name Type Description
list List

List of processed point cloud arrays after applying the HAG filter.

Raises:

Type Description
ValueError

If upper_limit is specified and is less than lower_limit.

Source code in pyforestscan/filters.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def filter_hag(arrays, lower_limit=0, upper_limit=None) -> List:
    """
    Apply a Height Above Ground (HAG) filter to a list of point cloud arrays.

    Filters each input array to include only points where Height Above Ground is
    within the specified range.

    Args:
        arrays (list): List of point cloud arrays to be processed.
        lower_limit (int or float, optional): Minimum Height Above Ground value to keep.
            Defaults to 0.
        upper_limit (int or float, optional): Maximum Height Above Ground value to keep.
            If None, no upper limit is applied. Defaults to None.

    Returns:
        list: List of processed point cloud arrays after applying the HAG filter.

    Raises:
        ValueError: If upper_limit is specified and is less than lower_limit.
    """
    pipeline = _build_pdal_pipeline(arrays, [_filter_hag(lower_limit, upper_limit)])
    return pipeline.arrays

filter_select_ground(arrays)

Select only ground points (classification 2) from a list of point cloud arrays.

Parameters:

Name Type Description Default
arrays list

List of point cloud arrays to be processed.

required

Returns:

Name Type Description
list List

List of point cloud arrays containing only points classified as ground (classification 2).

Source code in pyforestscan/filters.py
46
47
48
49
50
51
52
53
54
55
56
57
def filter_select_ground(arrays) -> List:
    """
    Select only ground points (classification 2) from a list of point cloud arrays.

    Args:
        arrays (list): List of point cloud arrays to be processed.

    Returns:
        list: List of point cloud arrays containing only points classified as ground (classification 2).
    """
    pipeline = _build_pdal_pipeline(arrays, [_select_ground()])
    return pipeline.arrays

remove_outliers_and_clean(arrays, mean_k=8, multiplier=3.0, remove=False)

Processes input arrays by removing statistical outliers and optionally cleans the data, filtering out specific classifications. By default, this function only labels outliers as "7" (outlier).

todo: this function will be renamed in a future release.

Parameters:

Name Type Description Default
arrays list

Input arrays to process, typically a list of structured arrays or similar data types (e.g., numpy structured arrays with a 'Classification' field).

required
mean_k int

Number of neighbors to analyze for each point during statistical outlier removal. Defaults to 8.

8
multiplier float

Multiplication factor for the standard deviation threshold to classify a point as an outlier. Defaults to 3.0.

3.0
remove bool

If True, remove points classified as outliers (Classification == 7) after labeling. If False, only label outliers. Defaults to False.

False

Returns:

Name Type Description
list List

List of processed arrays after outlier removal and, if specified, cleaning.

Raises:

Type Description
RuntimeError

If the outlier removal pipeline fails during execution.

ValueError

If no data is returned after applying outlier removal.

Source code in pyforestscan/filters.py
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def remove_outliers_and_clean(arrays, mean_k=8, multiplier=3.0, remove=False) -> List:
    """
    Processes input arrays by removing statistical outliers and optionally cleans
    the data, filtering out specific classifications.
    By default, this function only labels outliers as "7" (outlier).

    # todo: this function will be renamed in a future release.

    Args:
        arrays (list): Input arrays to process, typically a list of structured arrays or
            similar data types (e.g., numpy structured arrays with a 'Classification' field).
        mean_k (int, optional): Number of neighbors to analyze for each point during
            statistical outlier removal. Defaults to 8.
        multiplier (float, optional): Multiplication factor for the standard deviation
            threshold to classify a point as an outlier. Defaults to 3.0.
        remove (bool, optional): If True, remove points classified as outliers (Classification == 7)
            after labeling. If False, only label outliers. Defaults to False.

    Returns:
        list: List of processed arrays after outlier removal and, if specified, cleaning.

    Raises:
        RuntimeError: If the outlier removal pipeline fails during execution.
        ValueError: If no data is returned after applying outlier removal.
    """
    pipeline_stages = [
        _filter_statistical_outlier(mean_k=mean_k, multiplier=multiplier)
    ]

    try:
        pipeline = _build_pdal_pipeline(arrays, pipeline_stages)
    except RuntimeError as e:
        raise RuntimeError(f"Outlier Removal Pipeline Failed: {e}")

    if remove:
        clean_arrays = []
        for arr in pipeline.arrays:
            mask = (arr["Classification"] != 7)
            cleaned = arr[mask]
            clean_arrays.append(cleaned)
        processed_arrays = clean_arrays
    else:
        processed_arrays = pipeline.arrays

    if not processed_arrays:
        raise ValueError("No data returned after outlier removal.")

    return processed_arrays