HEALPix connected components#
healpix-analyse provides connected-component analysis for binary fields
defined on NESTED HEALPix cells.
Basic usage#
from healpix_analyse import connected_components
labels, n_components = connected_components(
mask,
cell_ids,
refinement_level,
connectivity="edge",
)
Background cells receive label 0.
Foreground components receive deterministic labels:
1, 2, 3, ...
Component numbering follows the first active cell encountered in the processing-domain order.
Connectivity#
Two HEALPix connectivity definitions are supported.
Edge connectivity#
connectivity="edge"
Cells are connected only when they share a HEALPix cell edge.
This is the HEALPix analogue of Cartesian 4-connectivity.
For a Cartesian raster:
. X .
X C X
. X .
For the HEALPix topology, the four edge-sharing directional neighbours are:
SW, NW, NE, SE
Edge-or-vertex connectivity#
connectivity="edge_or_vertex"
Cells are connected when they share either a HEALPix edge or a HEALPix vertex.
This is the HEALPix analogue of Cartesian 8-connectivity.
For a Cartesian raster:
X X X
X C X
X X X
For the HEALPix topology, the full immediate neighbourhood contains up to eight directional positions:
SW, W, NW, N, NE, E, SE, S
At HEALPix topological special locations, one of the vertex-touching positions may be absent, giving seven distinct immediate neighbours.
NESTED indexing only#
The current implementation supports NESTED HEALPix indexing only.
RING indexing and automatic indexing-scheme detection are intentionally not supported.
Processing domain#
cell_ids defines the cells for which input values are available.
domain defines the cells that participate in the connected-component
graph.
labels, n_components = connected_components(
mask,
cell_ids,
refinement_level,
domain=domain,
)
domain must be a subset of cell_ids.
Cells outside domain are absent from the topology.
For example:
A -- X -- B
if X lies outside the domain, connectivity cannot pass through X,
even if its input mask value is active.
Output order follows the exact order supplied by domain.
Component size#
from healpix_analyse import component_size
sizes = component_size(labels)
The returned array is indexed by component label.
For:
labels = [1, 1, 0, 2, 2, 2]
the result is:
sizes = [0, 2, 3]
Background label 0 is assigned size zero.
Component area#
from healpix_analyse import component_area
areas = component_area(
labels,
refinement_level,
ellipsoid="WGS84",
)
HEALPix cells at one refinement level have equal area.
The component area is therefore:
component cell count × HEALPix cell area
For the Sentinel-2 HEALPix processing use case, WGS84 is the intended ellipsoid.
The area computation uses the WGS84 ellipsoid surface area rather than an independently selected spherical-Earth radius.
Remove small components#
Components can be filtered by cell count:
from healpix_analyse import remove_small_components
cleaned = remove_small_components(
mask,
cell_ids,
refinement_level,
min_cells=4,
connectivity="edge",
)
or by physical area:
cleaned = remove_small_components(
mask,
cell_ids,
refinement_level,
min_area_m2=10_000.0,
connectivity="edge",
ellipsoid="WGS84",
)
Exactly one of min_cells or min_area_m2 must be supplied.
Threshold semantics#
Component thresholds are inclusive.
component size >= threshold -> retained
component size < threshold -> removed
For example, a two-cell component is retained when:
cleaned = remove_small_components(
mask,
cell_ids,
refinement_level,
min_cells=2,
)
The same rule applies to physical-area thresholds.
Background label 0 always remains background, including when the selected threshold is zero.
Generic Earth Observation example#
Connected-component filtering is useful as a generic post-processing step for binary Earth Observation segmentations.
For example, small isolated regions can be removed from a segmentation mask using a cell-count threshold:
from healpix_analyse import remove_small_components
cleaned = remove_small_components(
segmentation_mask,
cell_ids,
refinement_level,
min_cells=4,
connectivity="edge",
)
The same operation can use a physical-area threshold instead:
cleaned = remove_small_components(
segmentation_mask,
cell_ids,
refinement_level,
min_area_m2=100_000.0,
connectivity="edge",
ellipsoid="WGS84",
)
This pattern is generic and can be applied to cloud, snow or ice, water, land-cover, habitat, or other binary segmentation masks.
The library itself does not assign application-specific meanings or class identifiers to the foreground mask.
Topological edge cases#
Connectivity is defined by HEALPix topology rather than geographic coordinate proximity.
As a consequence, connected components work continuously across:
HEALPix base-pixel boundaries,
polar regions,
the longitude coordinate wrap-around,
and other HEALPix topological special locations.
No special treatment of the longitude seam or poles is required by the caller.
A component may also touch the boundary of a partial processing domain. Cells outside the domain are simply absent from the connectivity graph; valid foreground cells on the domain boundary remain part of their component.
Background cells may form holes inside a connected foreground region. A hole remains background and does not split the surrounding foreground when an alternative topological path connects that foreground.
NumPy and PyTorch#
NumPy arrays and PyTorch tensors are supported.
For Torch input, outputs are returned on the original device.
Connected-component operations are discrete and are therefore not differentiable.
Temporary topology backend#
Immediate HEALPix topology is currently obtained through a private
healpix_analyse._topology helper.
That helper temporarily uses:
healpy.get_all_neighbours(..., nest=True)
That call is a leftover compatibility shim, not the intended design: the rest
of the package takes its topology from healpix-geo
(nested.neighbours(..., connectivity="all")), and this helper is expected to
follow.
The planned final architecture is:
healpix-analyse
|
v
private topology helper
|
v
healpix-geo
|
v
CDSHEALPix
Once direction-aware neighbour access is exposed by healpix-geo, the
private backend can be replaced without changing the public
connected-component API.