Spherical morphology¶
Mathematical morphology asks whether nearby values satisfy an ordering: a
dilation takes a supremum, an erosion takes an infimum, and opening/closing
compose those two operations. On a sphere, the important question is what
nearby means.
Why a Pillow-style image window is insufficient¶
A rectangular window on an equirectangular raster is not a fixed physical neighbourhood. Longitude pixels converge toward the poles, the left and right columns are adjacent, and a planar disk changes angular size when the ERP is resized. Applying Pillow, OpenCV, or SciPy morphology directly to ERP indices therefore makes the result depend on latitude, seam placement, and resolution.
PanorAi’s GeodesicDisk instead measures its radius in degrees of
great-circle distance. At every ERP pixel centre it samples a disk in the
local east/north tangent plane and maps that disk onto the sphere. The
operation wraps longitude and remains meaningful at high latitudes.
The finite-lattice contract¶
For a finite ERP, a continuous geodesic disk must be sampled. The default
sampling step follows the ERP angular lattice; callers can declare a fixed
angular_step_deg when comparisons must remain independent of raster
resolution. The sampled neighbour relation is symmetrized. This detail gives
the discrete dilation and erosion an adjunction, so the expected morphology
laws hold exactly on the finite lattice:
dilation is extensive and erosion is anti-extensive;
both are monotone;
erosion is dual to dilation under sign inversion;
opening and closing are idempotent.
The approximation to a continuum cap is bounded by the declared sampling
lattice, rather than being silently described as exact continuum morphology.
Execution is deterministically chunked by default; max_sampled_elements
can lower the temporary-memory budget or be set to None to request one
unbounded pass without changing the numerical result.
Types, masks and validity¶
The Stable NumPy v1 contract accepts boolean masks and scalar float32 or
float64 HW fields. It rejects multi-class labels because numeric label
order has no semantic meaning, and rejects untyped HWC channel vectors
because component-wise max/min does not define a canonical vector order. The
Torch API accepts floating NCHW tensors and defines each channel as an
independent scalar field; it does not order vectors across channels. Sampling
is nearest-only.
Support and data validity remain separate and propagate strictly: an output is
supported/valid only when every sample required by the structuring element is
supported/valid. The operation never treats False, numeric zero, or black
as missing data.
Use the tutorial for container, Pipeline and Torch composition, and the API reference for the exact public surface.