
Cloud and shadow masking with OmniCloudMask
ocm.RdNative (no-Python) implementation of the OmniCloudMask v4 cloud and shadow segmentation model, which predicts per-pixel classes from red, green, and NIR reflectance at 10-50 m resolution. Three functions cover the workflow:
Usage
ocm_model(weights_dir = NULL, models = c("regnety", "edgenext"), halo = 128L)
ocm_predict(red, green, nir, model = ocm_model())
ocm_mask(
x,
red,
green,
nir,
model = ocm_model(),
where = 1:3,
open = 0L,
dilate = 0L
)Arguments
- weights_dir
Directory with the OCM v4 safetensors files. Defaults to the
GARRY_OCM_WEIGHTSenvironment variable if set, then theocm_fetch_weights()download directory, then the newest version under the Python package's cache (~/.local/share/omnicloudmask).- models
Ensemble members to run; the default matches OmniCloudMask v4 exactly (both U-Nets, logits averaged). A single member is roughly twice as fast at slightly lower accuracy.
- halo
Chunk overlap margin in pixels (multiple of 32 recommended).
- red, green, nir
For
ocm_predict(): bandLazyRasters on the same grid and graph. Forocm_mask(): names of the dataset bands to predict from (e.g."B04","B03","B8A").- model
An
ocm_modelobject, fromocm_model().- x
A
LazyDatasetwhose slices carry the three bands.- where
Classes to mask out (default thick cloud, thin cloud, and shadow).
- open, dilate
Morphological cleanup, as in
apply_mask().
Value
ocm_model() returns an ocm_model object; ocm_predict()
a class LazyRaster on the shared spatial grid; ocm_mask() the
masked LazyDataset (class band consumed).
Details
ocm_model()loads the pre-trained weights (seeocm_fetch_weights()) and builds the reusable inference kernel. One model object serves any number of scenes and datasets; all stages sharing a model compile to a single kernel per worker.ocm_predict()runs the model over three bandLazyRasters and returns the class band as a newLazyRaster. Like every garry verb it is lazy: nothing reads or computes untilcollect().ocm_mask()is the one-step verb for aLazyDataset: it derives the class band from three of the dataset's bands for every time slice, then masks every value band with it viaapply_mask(). The derived class band is consumed by the masking, exactly like a QAmask_asset.
Predicted classes are 0 (clear), 1 (thick cloud), 2 (thin cloud),
and 3 (cloud shadow), with NaN wherever the input had nodata.
halo is the overlap margin each chunk recomputes so that chunk
seams carry full spatial context (OmniCloudMask itself blends
overlapping patches; garry crops instead). The per-window
normalisation makes results inherently window-dependent, exactly as
OmniCloudMask's are patch-dependent, so expect class agreement with
the Python implementation, not bit identity, except in the
single-chunk case.
Weights are the OmniCloudMask authors'
(https://github.com/DPIRD-DMA/OmniCloudMask) and are not
distributed with garry; download them once with
ocm_fetch_weights().
See also
ocm_fetch_weights() to download the weights; apply_mask() and
qa_bits() for masking from an existing QA band;
vignette("omnicloudmask", package = "garry") for a worked
example.
Examples
if (FALSE) { # \dontrun{
ocm_fetch_weights() # once per machine
ds <- ds |> ocm_mask(red = "B04", green = "B03", nir = "B8A")
composite <- ds |> reduce_over("median", over = "t") |> collect()
} # }