Skip to contents

Native (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_WEIGHTS environment variable if set, then the ocm_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(): band LazyRasters on the same grid and graph. For ocm_mask(): names of the dataset bands to predict from (e.g. "B04", "B03", "B8A").

model

An ocm_model object, from ocm_model().

x

A LazyDataset whose slices carry the three bands.

where

Classes to mask out (default thick cloud, thin cloud, and shadow).

open, dilate

Morphological cleanup, as in 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 (see ocm_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 band LazyRasters and returns the class band as a new LazyRaster. Like every garry verb it is lazy: nothing reads or computes until collect().

  • ocm_mask() is the one-step verb for a LazyDataset: it derives the class band from three of the dataset's bands for every time slice, then masks every value band with it via mask(). The derived class band is consumed by the masking, exactly like a QA mask_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; 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("time", "median") |> collect()
} # }