API Reference
nrt.validate.utils module
- nrt.validate.utils.combine_transforms(*transforms)
Utility function to combine multiple transforms
- nrt.validate.utils.get_chips(ds, geom, size, compositor=<nrt.validate.composites.SimpleComposite object>, res=None, scale=4, outline_color='magenta')
Prepare a list of chips (ipywidget.Images) croped from a xarray Dataset
- Parameters:
ds (xarray.Dataset) – A mulivariate and multidimentional data cube containing the data to create the chips
geom (dict) – A geojson geometry to define the cropping location and overlay on each chip. Must spatially intersect with
dsand be in the same CRSsize (float) – Size of the bounding box used for cropping (created around the centroid of
geom). In CRS unit.compositor (callable) – Callable to transform a temporal slice of the provided Dataset into a 3D numpy array. See the
nrt.validate.compositesmodule for examplesres (float) – An optional value defining the size of the overlayed square geometry in case
geomis a Point. IfNoneandgeomis a point, the Dataset resolution is used.scale (int) – Scaling factor to increase image size
outline_color (str) – Color of the (expanded) geometry outline. See the Matplotlib Named Colors Gallery
Examples
>>> import xarray as xr >>> from nrt.validate import utils >>> from nrt.validate.composites import TasseledCapComposite >>> import ipywidgets as ipw >>> #TODO: Change the line below with cube from nrt.data package >>> cube = xr.open_dataset('/home/loic/Downloads/czechia_nrt_test.nc') >>> geom_point = {'type': 'Point', 'coordinates': [4813210, 2935950]} >>> geom_poly = {"type": "Polygon", "coordinates": [[[4813283, 2935951], ... [4813250, 2935998], ... [4813193, 2936019], ... [4813159, 2936013], ... [4813134, 2935956], ... [4813146, 2935899], ... [4813204, 2935877], ... [4813232, 2935869], ... [4813279, 2935927], ... [4813277, 2935967], ... [4813283, 2935951]]]} >>> box_layout = ipw.Layout(display='flex', ... flex_flow='row wrap', ... align_items='stretch', ... width='100%', ... height='800px', ... overflow='auto') >>> chips_point = utils.get_chips(ds=cube, geom=geom_point, size=300, ... compositor=TasseledCapComposite(), res=None) >>> box = ipw.Box(children=chips_point, layout=box_layout) >>> box >>> chips_poly = utils.get_chips(ds=cube, geom=geom_poly, size=200, res=None) >>> box = ipw.Box(children=chips_poly, layout=box_layout) >>> box
- Returns:
List of ipywidgets.Image with geometry overlay
- Return type:
list
- nrt.validate.utils.get_ts(ds, geom, vi_calculator=NDVI(blue='B02', green='B03', red='B04', nir='B8A', re1='B05', re2='B06', re3='B07', swir1='B11', swir2='B12'))
Extract a time-series and compute desired index for a geometry overlayed on a Dataset
- Parameters:
ds (xarray.Dataset) – The dataset from which to compute and extract the time-series
geom (dict) – A geojson geometry (Point or Polygon). If point, the nearest pixel is extracted; if Polygon, spatial average excluding
nans is computed for each time-step.vi_calculator (callable) – A callable to process a DataArray containing the desired index from the dataset. See the
nrt.validate.indicesmodule for examples and already implemented simple transforms
Examples
>>> import xarray as xr >>> from nrt.validate import utils >>> from nrt.validate.indices import NDVI, CR_SWIR >>> from nrt.validate.xr_transforms import S2CloudMasking >>> import ipywidgets as ipw >>> from bqplot import DateScale, LinearScale, Axis, Scatter, Figure
>>> cube = xr.open_dataset('/home/loic/Downloads/czechia_nrt_test.nc') >>> geom_point = {'type': 'Point', 'coordinates': [4813210, 2935950]} >>> geom_poly = {"type": "Polygon", "coordinates": [[[4813283, 2935951], ... [4813250, 2935998], ... [4813193, 2936019], ... [4813159, 2936013], ... [4813134, 2935956], ... [4813146, 2935899], ... [4813204, 2935877], ... [4813232, 2935869], ... [4813279, 2935927], ... [4813277, 2935967], ... [4813283, 2935951]]]} >>> dates, ts_point = utils.get_ts(ds=cube, geom=geom_point, ... vi_calculator=utils.combine_transforms(S2CloudMasking(), NDVI())) >>> _, ts_poly = utils.get_ts(ds=cube, geom=geom_poly, ... vi_calculator=utils.combine_transforms(S2CloudMasking(), CR_SWIR())) >>> # Visualize using bqplot >>> x_scale = DateScale() >>> y_scale = LinearScale() >>> x_ax = Axis(label='Date', scale=x_scale, tick_format='%m-%Y', tick_rotate=45) >>> y_ax = Axis(label='Value', scale=y_scale, orientation='vertical') >>> point_values = Scatter(x=dates, y=ts_point, scales={'x': x_scale, 'y': y_scale}, colors='green') >>> polygon_values = Scatter(x=dates, y=ts_poly, scales={'x': x_scale, 'y': y_scale}, colors='blue') >>> fig = Figure(marks=[point_values, polygon_values], axes=[x_ax, y_ax]) >>> fig
- Returns:
Tuple of two elements; Array of dates and array of VI values
- Return type:
tuple
- nrt.validate.utils.np2ipw(arr, geom=None, transform=None, res=20, scale=4, outline_color='magenta')
Convert a 3 bands numpy array to an ipywidgets Image
- Parameters:
arr (np.ndarray) – Array of rescaled values between 0 and 1, 3 bands in RGB order. Bands are the last dimension
geom (dict) – A geojson geometry to draw on top of the image. Must be in the same Coordinate Reference System as the array
transform (affine.Affine) – The affine transform of the image/array
res (float) – The image resolution in the unit of CRS. It is used to outline the center pixel in case
geomis a Point and does not necessarily need to match the actual image resolution (e.g. if a value of 3 times the actual resolution is provided, the 9 central pixels will be outlined).scale (int) – Scaling factor to increase image size
outline_color (str) –
Color of the (expanded) geometry outline. See the Matplotlib Named Colors Gallery
- Returns:
The image with geometry overlay, in ipywidgets Image format
- Return type:
ipywidgets.Image
nrt.validate.composites module
- class nrt.validate.composites.BaseComposite
Bases:
ABCAbstract base class for all color compositors
- static stretch(arr, blim=[20, 2000], glim=[50, 2000], rlim=[20, 2000])
Apply color stretching and [0,1] clipping to a 3 bands image.
- Parameters:
arr (np.ndarray) – 3D array; bands as last dimension in RGB order.
blim (list) – min and max values between which to stretch the individual bands.
glim (list) – min and max values between which to stretch the individual bands.
rlim (list) – min and max values between which to stretch the individual bands.
- Returns:
Stretched and clipped array.
- Return type:
np.ndarray
- class nrt.validate.composites.S2CIR(b='B03', g='B04', r='B08', blim=[250, 1300], glim=[150, 1700], rlim=[1500, 4000])
Bases:
SimpleComposite
- class nrt.validate.composites.S2SWIR(b='B04', g='B8A', r='B11', blim=[150, 1200], glim=[1800, 3500], rlim=[800, 3000])
Bases:
SimpleComposite
- class nrt.validate.composites.S2SWIRx2(b='B12', g='B11', r='B8A', blim=[250, 1800], glim=[600, 3000], rlim=[1200, 4500])
Bases:
SimpleComposite
- class nrt.validate.composites.S2TasseledCapComposite(blue='B02', green='B03', red='B04', nir='B8A', swir1='B11', swir2='B12', rlim=[300, 1500], glim=[1200, 4500], blim=[600, 2900])
Bases:
BaseComposite- brightness(ds)
- greenness(ds)
- wetness(ds)
- class nrt.validate.composites.SimpleComposite(b='B02', g='B03', r='B04', blim=[20, 2000], glim=[50, 2000], rlim=[20, 2000])
Bases:
BaseComposite
nrt.validate.estimators module
Statistical estimators for map accuracy assessment.
- class nrt.validate.estimators.BaseEstimator
Bases:
ABCAbstract strategy for accuracy estimation.
- abstractmethod estimate_mean(mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Returns (Estimate, Standard Error) for a population mean/proportion.
- abstractmethod estimate_ratio(numerator_mask: ndarray, denominator_mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Returns (Estimate, Standard Error) for a ratio Y/X.
- f1_score(y_true: ndarray, y_pred: ndarray, label: Any, se_method: str = None, n_boot: int = 500) Tuple[float, float]
Computes the F1 Score for a specific class with optional SE estimation.
- Parameters:
y_true – 1D array of reference labels.
y_pred – 1D array of map labels.
label – The specific class ID to evaluate.
se_method – Method for Standard Error calculation. Options: [None, ‘simple_bootstrap’, ‘bootstrap’]. Default is None (returns 0.0 for SE).
n_boot – Number of bootstrap iterations if se_method is ‘simple_bootstrap’.
- Returns:
(F1 Estimate, Standard Error)
- overall_accuracy(y_true: ndarray, y_pred: ndarray) Tuple[float, float]
Computes Overall Accuracy (OA).
- Parameters:
y_true – 1D array of reference labels.
y_pred – 1D array of map labels (must be aligned with y_true and strata).
- Returns:
(Estimate, Standard Error)
- producer_accuracy(y_true: ndarray, y_pred: ndarray, label: Any) Tuple[float, float]
Computes Producer’s Accuracy (Recall) for a specific class.
Formula: P(Map = label | Reference = label)
- Parameters:
y_true – 1D array of reference labels.
y_pred – 1D array of map labels.
label – The specific class ID to evaluate.
- Returns:
(Estimate, Standard Error)
- user_accuracy(y_true: ndarray, y_pred: ndarray, label: Any) Tuple[float, float]
Computes User’s Accuracy (Precision) for a specific class.
Formula: P(Reference = label | Map = label)
- Parameters:
y_true – 1D array of reference labels.
y_pred – 1D array of map labels.
label – The specific class ID to evaluate.
- Returns:
(Estimate, Standard Error)
- class nrt.validate.estimators.SimpleRandomEstimator
Bases:
BaseEstimatorEstimator for Simple Random Sampling (SRS).
- estimate_mean(mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Returns (Estimate, Standard Error) for a population mean/proportion.
- estimate_ratio(numerator_mask: ndarray, denominator_mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Returns (Estimate, Standard Error) for a ratio Y/X.
- class nrt.validate.estimators.StratifiedEstimator(strata_labels: ndarray | list, stratum_pop_sizes: Dict[Any, int])
Bases:
BaseEstimatorAccuracy and area estimators for Stratified Random Sampling (StrRS).
This class implements the methodology described in Stehman (2014). It is a generalized estimator that should be used whenever the sampling design is stratified (i.e., sample sizes $n_h$ are fixed in advance per stratum), regardless of how the strata are defined.
- Use Cases:
Strata ≠ Map Classes: The primary use case described in Stehman (2014). For example, when validating a change map using strata defined by “buffer zones” or “likely change” areas that do not map 1:1 to the final map classes.
Strata = Map Classes: The standard case often associated with Olofsson et al. (2013/2014). When strata exactly match the map classes, the formulas in this class mathematically simplify to the standard “confusion matrix” estimators.
- Reference:
Stehman, S. V. (2014). Estimating area and map accuracy for stratified random sampling when the strata are different from the map classes. International Journal of Remote Sensing, 35(13), 4923-4939.
- strata_labels
Stratum ID for each sample unit.
- Type:
np.ndarray
- meta
Stratum metadata (N_h, n_h, weights).
- Type:
pd.DataFrame
Examples
>>> import numpy as np >>> # numerical example based on Stehman (2014) data >>> # Strata sizes (Nh) >>> Nh_strata = {1: 40000, 2: 30000, 3: 20000, 4: 10000}
>>> # Reconstructing vectors to exactly match the paper's CSV counts (n=10 per stratum) >>> # Stratum 1: Map (7A, 3B). Ref (pairs with Map): 5(A,A), 1(A,C), 1(A,B), 1(B,A), 1(B,B), 1(B,C) >>> s1 = [1]*10 >>> m1 = ["A"]*7 + ["B"]*3 >>> r1 = ["A"]*5 + ["C", "B"] + ["A", "B", "C"]
>>> # Stratum 2: Map (1A, 9B). Ref: 1(A,A), 5(B,B), 2(B,A), 2(B,B) >>> s2 = [2]*10 >>> m2 = ["A"] + ["B"]*9 >>> r2 = ["A"] + ["B"]*5 + ["A"]*2 + ["B"]*2
>>> # Stratum 3: Map (4B, 6C). Ref: 2(B,C), 1(B,B), 1(B,A), 3(C,C), 2(C,D), 1(C,B) >>> s3 = [3]*10 >>> m3 = ["B"]*4 + ["C"]*6 >>> r3 = ["C"]*2 + ["B", "A"] + ["C"]*3 + ["D"]*2 + ["B"]
>>> # Stratum 4: Map (10D). Ref: 7(D,D), 2(D,C), 1(D,B) >>> s4 = [4]*10 >>> m4 = ["D"]*10 >>> r4 = ["D"]*7 + ["C"]*2 + ["B"]
>>> # Combine >>> s = np.array(s1 + s2 + s3 + s4) >>> m_arr = np.array(m1 + m2 + m3 + m4) >>> r_arr = np.array(r1 + r2 + r3 + r4)
>>> est = StratifiedEstimator(s, Nh_strata)
>>> # 1. Proportion of Area of Class A (Paper: 0.35, SE: 0.082) >>> area_A, se_area_A = est.estimate_mean(r_arr == "A") >>> print(f"{area_A:.2f}, {se_area_A:.3f}") 0.35, 0.082
>>> # 2. Proportion of Area of Class C (Paper: 0.20, SE: 0.064) >>> area_C, se_area_C = est.estimate_mean(r_arr == "C") >>> print(f"{area_C:.2f}, {se_area_C:.3f}") 0.20, 0.064
>>> # 3. Overall Accuracy (Paper: 0.63, SE: 0.085) >>> oa, se_oa = est.estimate_mean(m_arr == r_arr) >>> print(f"{oa:.2f}, {se_oa:.3f}") 0.63, 0.085
>>> # 4. User's Accuracy of Class B (Paper: 0.574, SE: 0.125) >>> # Num: Map is B AND Ref is B. Denom: Map is B. >>> ua_B, se_ua_B = est.estimate_ratio((m_arr == "B") & (r_arr == "B"), (m_arr == "B")) >>> print(f"{ua_B:.3f}, {se_ua_B:.3f}") 0.574, 0.125
>>> # 5. Producer's Accuracy of Class B (Paper: 0.794, SE: 0.114) >>> # Note: Code result is 0.117 due to slight data reconstruction variance vs paper >>> pa_B, se_pa_B = est.estimate_ratio((r_arr == "B") & (m_arr == "B"), (r_arr == "B")) >>> print(f"{pa_B:.3f}, {se_pa_B:.3f}") 0.794, 0.117
- estimate_mean(mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Estimates population mean (Eq. 2) and SE (Eq. 25).
- estimate_ratio(numerator_mask: ndarray, denominator_mask: ndarray, weights: ndarray | None = None) Tuple[float, float]
Estimates ratio R = Y/X and SE (Eq. 28).
- class nrt.validate.estimators.TwoStageClusterEstimator(psu_ids: ndarray, strata_1_ids: ndarray, global_weights: ndarray, se_method: str = 'analytical', n_boot: int = 500, strata_1_pop_sizes: Dict[Any, int] | None = None)
Bases:
BaseEstimatorEstimator for Stratified Two-Stage Cluster Sampling.
METHODOLOGY NOTE: This class implements the “Ultimate Cluster” variance estimator (Särndal et al., 1992). It simplifies variance estimation by treating the Primary Sampling Unit (PSU) as the fundamental unit of analysis.
Instead of explicitly summing “Between-PSU Variance” + “Within-PSU Variance”, this method aggregates all SSUs (pixels) to calculate a weighted total for each PSU, and then calculates the variance between these PSU totals. This automatically captures the total variance (both stages) under the assumption that PSUs are sampled with replacement (or that the sampling fraction is small).
This approach is standard for large-scale remote sensing (e.g., Stehman & Selkowitz, 2010) because it is robust to complex second-stage designs (like pixel stratification) without requiring complex covariance formulas.
Examples
>>> import numpy as np >>> # Synthetic Data verified against R 'survey' package (v4.0) >>> # Scenario: >>> # - 2 Stratum (Region_A, Region_B) >>> # - 4 PSUs sampled per Stratum (8 PSUs total) -> No lonely PSUs! >>> # - 5 SSUs sampled per PSU (40 SSUs total) >>> # - Weights: Region_A=10, Region_B=20 (representing different sampling probs) >>> >>> # Data Setup >>> strata_1 = np.array(['A']*20 + ['B']*20) # 20 pixels in A, 20 in B >>> psu_ids = np.concatenate([ ... [1]*5, [2]*5, [3]*5, [4]*5, # 4 PSUs in A ... [5]*5, [6]*5, [7]*5, [8]*5 # 4 PSUs in B ... ]) >>> weights = np.concatenate([[10]*20, [20]*20]) >>> >>> # Target Variable (Mask): >>> # Region A: PSUs are fairly consistent (mostly True) >>> # Region B: PSUs are highly variable (some all True, some all False) >>> # Constructing a pattern: >>> # PSU 1: 5/5 True >>> # PSU 2: 4/5 True >>> # PSU 3: 5/5 True >>> # PSU 4: 4/5 True (Region A is "High Accuracy") >>> # PSU 5: 0/5 True >>> # PSU 6: 1/5 True >>> # PSU 7: 0/5 True >>> # PSU 8: 5/5 True (Region B is "Noisy/Mixed") >>> mask = np.array([ ... 1,1,1,1,1, 1,1,1,1,0, 1,1,1,1,1, 1,1,1,1,0, # A ... 0,0,0,0,0, 1,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1 # B ... ], dtype=bool) >>> >>> # Initialize Estimator >>> est = TwoStageClusterEstimator(psu_ids, strata_1, weights, se_method='analytical') >>> >>> # 1. Point Estimate (Mean) >>> # Manual Logic: >>> # Stratum A Est: High proportion (~0.9) * Weight 10 >>> # Stratum B Est: Low proportion (~0.3) * Weight 20 >>> # Region B dominates due to weight. Expect mean around 0.5. >>> mean, se = est.estimate_mean(mask) >>> >>> # Validated against R: svyratio(~y, ~ind, design=svydesign(id=~psu, strata=~strata, weights=~w)) >>> # R Result: Mean = 0.500 >>> print(f"{mean:.3f}") 0.500
>>> # 2. Standard Error (Ultimate Cluster) >>> # Validated against R Result: SE = 0.1598611 >>> print(f"{se:.7f}") 0.1598611
>>> # 3. Effective Sample Size >>> # Count of PSUs with at least 1 positive sample >>> # In A: All 4 PSUs have positives. >>> # In B: PSU 6 has 1 positive, PSU 8 has 5 positives. (PSU 5, 7 have 0). >>> # Total = 4 + 2 = 6 >>> est.effective_sample_size(mask) 6
- effective_sample_size(mask: ndarray) int
Returns ‘tPSU’: the count of unique PSUs containing at least one positive sample. Reference: Wickham et al. (2003).
- estimate_mean(mask: ndarray, weights: ndarray | None = None, compute_se: bool = True) Tuple[float, float]
Estimates population mean/proportion. Technically implemented as a Ratio of Totals (Total Y / Total Pop) to handle variable PSU sizes correctly.
- estimate_ratio(numerator_mask: ndarray, denominator_mask: ndarray, weights: ndarray | None = None, compute_se: bool = True) Tuple[float, float]
Returns (Estimate, Standard Error) for a ratio Y/X.
nrt.validate.fitting module
- class nrt.validate.fitting.PartitionedHarmonicTrendModel(dates, delta_predict=np.timedelta64(5, 'D'))
Bases:
objectLeast square harmonic fitting of partitioned time-series
- Parameters:
dates (np.ndarray) – Array of datetime64 dates
delta_predict (np.timedelta64) – Temporal interval for smooth predictions
Examples
>>> import numpy as np >>> from nrt.validate.fitting import PartitionedHarmonicTrendModel
>>> np.random.seed(42)
>>> # Random time-series with irregularly spaced observations >>> start_date = np.datetime64('2020-01-01') >>> n_samples = 120 >>> days_between = np.random.randint(5, 21, size=n_samples) >>> dates = np.cumsum(days_between) >>> dates = start_date + np.array(dates, dtype='timedelta64[D]') >>> y = np.random.random(size=n_samples) >>> breakpoints = [dates[0], dates[40], dates[-1]]
>>> model = PartitionedHarmonicTrendModel(dates) >>> dates, predictions = model.fit_predict(y, breakpoints, 2) >>> print(dates) >>> print(predictions)
- static decimal_dates(dates)
Convert a datetime64 array to decimal years
- fit_predict(y, breakpoints, order)
Fit a harmonic trend model for each segment and returns a smoothed prediction
Note that the last value of the time-series is not used for the fitting. A segment starts at a breakpoint and ends one observation before the next breakpoint
- Parameters:
y (np.ndarray) – Array of values
breakpoints (list) – List of datetime64 dates corresponding to breakpoints dates. Usually include extremities of the time-series too.
order (int) – Harmonic order, between 0 and 5
- Returns:
List of datetime64 arrays each corresponding to a segment - predicted values: List of matching arrays containing predicted values
- Return type:
Dates
nrt.validate.indices module
- class nrt.validate.indices.BaseS2Index(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12')
Bases:
ABCAbstract base class for Sentinel2 based indices
- blue: str = 'B02'
- green: str = 'B03'
- nir: str = 'B8A'
- re1: str = 'B05'
- re2: str = 'B06'
- re3: str = 'B07'
- red: str = 'B04'
- swir1: str = 'B11'
- swir2: str = 'B12'
- class nrt.validate.indices.CR_SWIR(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12')
Bases:
BaseS2IndexCR_SWIR calculator for Sentinel 2 data organized in an xarray Dataset
This Continuum removal corresponds to the division between the observed SWIR1 value and a value interpolated between NIR and SWIR2 hence amplifying the absoption feature of the SWIR1 region. The index was first proposed by Dutrieux et al. (2021) for the development of a near real time spruce dieback detection system named FORDEAD. Note that Sentinel 2A and 2B have slightly different central wavelengths, especially for SWIR2. The mean of the two sensors is used here
- class nrt.validate.indices.NCDI(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12')
Bases:
BaseS2IndexExperimental Normalized SWIR1 Continuum Difference Index
A normalized variation of the
CR_SWIRindex. Instead of dividing the SWIR1 reflectance by the SWIR1 continuum, this index computes a normalized difference between them. It is therefore calculated as:\[NDCI =\]rac{{ ext{SWIR}_{1-C} - ext{SWIR}_{1-R}}}{{ ext{SWIR}_{1-C} + ext{SWIR}_{1-R}}}
Where:
\(SWIR_{1-C}\) is the continuum interpolated between NIR and SWIR2 for SWIR1 wavelength.
\(SWIR_{1-R}\) is the SWIR1 reflectance value.
- class nrt.validate.indices.NDMI(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12')
Bases:
BaseS2IndexNDMI calculator for Sentinel 2 data organized in an xarray Dataset
By default, the swir channel must be named
'B11'and the nir channel'B8A'as per theBaseS2Indexbase class. These defaults can be modified at instantiation by passing for instancendmi = NDMI(nir='B08')
- class nrt.validate.indices.NDVI(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12')
Bases:
BaseS2IndexNDVI calculator for Sentinel 2 data organized in an xarray Dataset
By default, the red channel must be named
'B03'and the nir channel'B8A'as per theBaseS2Indexbase class. These defaults can be modified at instantiation by passing for instancendvi = NDVI(red='B03_20', nir='B08_20')
nrt.validate.interface module
- class nrt.validate.interface.Chips(**kwargs: Any)
Bases:
HasTraits- add_or_remove_breakpoint(idx)
- breakpoints
An instance of a Python list.
- display()
- classmethod from_cube_and_geom(ds, geom, breakpoints=[], compositor=<nrt.validate.composites.SimpleComposite object>, window_size=500, **kwargs)
Instantiate Chips from an xarray Dataset and a geometry
Geometry and cube/Dataset must share the same coordinate reference system
- Parameters:
ds (xarray.Dataset) – The Dataset containing the data to display
geom (dict) – A geojson geometry (Point or Polygon) around which Dataset will be cropped and for which index time-series will be extracted
breakpoints (list) – Optional list of dates
compositor (callable) – Callable to transform a temporal slice of the provided Dataset into a 3D numpy array. See `nrt.validate.composites module for examples
window_size (float) – Size of the bounding box used for cropping (created around the centroid of `geom). In CRS unit.
**kwargs – Additional arguments passed to `nrt.validate.utils.get_chips
- highlight
A container with observable traits and many elementary methods to host image chips
Examples
>>> import xarray as xr >>> import numpy as np >>> from nrt.validate.interface import Chips
>>> cube = xr.open_dataset('/home/loic/Downloads/czechia_nrt_test.nc') >>> geom = {'type': 'Point', 'coordinates': [4813210, 2935950]} >>> chips = Chips.from_cube_and_geom(ds=cube, geom=geom, ... breakpoints=[np.datetime64('2018-09-28T10:00:19.024000000'), ... np.datetime64('2019-02-27T09:50:31.024000000'), ... np.datetime64('2021-10-29T09:50:29.024000000')]) >>> chips.display() >>> # Add breakpoint either by clicking on a chip, or running the following method >>> chips.add_or_remove_breakpoint(33)
- class nrt.validate.interface.SegmentsLabellingInterface(**kwargs: Any)
Bases:
HasTraits- create_button(idx, feature_id, color)
Create a button related to a sample
- create_interactive_list(samples, color)
Create lists of samples buttons
- Agrs:
samples (list): List of (idx, feature_id) tuples
- current_idx
An int trait.
- display()
- draw_webmap(geom, res, crs)
- get_fids()
Get two mutually exclusive lists of feature ids First list is the not yet interpreted Second list is the already interpreted
- load_sample(idx)
- on_sample_click(button)
- save_to_db(button)
Save current segmentation to database
- update_interface
- update_lists()
Update lists of samples
- update_webmap(geom, res, crs)
- class nrt.validate.interface.Vits(**kwargs: Any)
Bases:
HasTraits- breakpoints
An instance of a Python list.
- current_vi
Handle and display the vegetation index time-series
- display()
- classmethod from_cube_and_geom(ds, geom, breakpoints=[], vis={'CR-SWIR': CR_SWIR(blue='B02', green='B03', red='B04', nir='B8A', re1='B05', re2='B06', re3='B07', swir1='B11', swir2='B12'), 'NDVI': NDVI(blue='B02', green='B03', red='B04', nir='B8A', re1='B05', re2='B06', re3='B07', swir1='B11', swir2='B12')}, default_vi='NDVI')
Instantiate Vits from an xarray Dataset and a geometry
Geometry and cube/Dataset must share the same coordinate reference system
- Parameters:
ds (xarray.Dataset) – The Dataset containing the data to display
geom (dict) – A geojson geometry (Point or Polygon) with which the time-series will be extracted (nearest pixel in case of Point, spatial average for Polygons)
breakpoints (list) – Optional list of dates
vis (dict) – Dictionary of callables to compute vegetation indices see `nrt.validate.indices module for examples and already implemented indices
- order
An int trait.
- redraw_fit_lines
- redraw_vlines
- update_highlighted_point(idx)
Update the color of the highlighted point based on idx.
- Parameters:
idx (int or None) – Index of the point to highlight or None.
nrt.validate.loaders module
Data loaders from various sources (disk, STAC, gee) to be used by the Interface
Loaders inputs are at least a feature collection with a property that can be used as a primary key and a way to retrieve xarray Dataset (a single or multiple netcdf files/zarr stores; a STAC API collection; etc). The loader are subscritable (loader[n] is used to access data of n-th element), have at least a __len__ method. Data returned by subscript are in the form of a 6 element tuple (unique_id, dates, chips, ts, geom, crs).
- TODOs/questions:
Should WKT geometries be stored in the database? To facilitate disaster recovery
CRS handling, none for now. Needed? Yes, it may be needed for webmap overlay.
The dates array must be numpy.datetime64 with Day precision. Document that somewhere for people who wish to write their own loader
- class nrt.validate.loaders.BaseLoader(fc: List[Dict[str, Any]], key: str, crs: Any, prefetch: int | None = None, cache_size: int | None = 20)
Bases:
ABC- property fids
Return the list of unique feature ids
- class nrt.validate.loaders.FileLoader(fc: List[Dict[str, Any]], key: str, crs: Any, datasets: Dataset | List[Dataset], vis: Dict[str, Callable[[DataArray], Any]], window_size: float, compositor: Callable[[Dataset], ndarray], xr_transform: Callable[[Dataset], Dataset] | None = None, res: float | None = None, prefetch: int | None = 5, cache_size: int | None = 20, **kwargs)
Bases:
BaseLoaderA loader to prepare locally accessible data
- Parameters:
fc (list) – A feature collection. Can be Points, Polygons or a mix of the two. Must contain a property that can be used as a unique key
key (str) – Name of the feature collection property to be used as unique identifier
crs (CRS) – A coordinate reference object, from fiona, rasterio, pyproj, etc representing projection of both
fcanddatasetsdatasets (xr.Dataset or list) – (list of) xarray Datasets containing the multispectral spatio-temporal data. They must all be in the same CRS as
fc. They can lazy loaded using dask (seechunksargument inopen_dataset.vis (dict) – Dictionary of callables to compute vegetation indices see
nrt.validate.indicesmodule for examples and already implemented indicescompositor (callable) – Callable to transform a temporal slice of the provided Dataset into a 3D numpy array. See
nrt.validate.compositesmodule for exampleswindow_size (float) – Size of the bounding box used for cropping (created around the centroid of
geom). In CRS unit.xr_transform (callable) – Callable that takes an xarray Dataset as input and returns another xarray Dataset. This operation is applied to the spatial subset of the cube used for generating chips and VI time-series. Generally used for pre-processing steps such as removal of “empty” slices, or data scaling.
**kwargs – Additional arguments passed to
nrt.validate.utils.get_chips
- Returns:
- A tuple of 6 elements:
The unique key of the sample
Array of numpy.datetime64
List of ipywidgets.Image (the image chips)
Dictionary of values for multiple vegetation indices
The sample geometry
The CRS object
- Return type:
tuple
Examples
>>> import xarray as xr >>> import numpy as np >>> from shapely.geometry import Point, mapping >>> import rioxarray
>>> from nrt.validate.loaders import FileLoader >>> from nrt.validate import utils >>> from nrt.validate.indices import * >>> from nrt.validate.composites import * >>> from nrt.validate.xr_transforms import *
>>> cube = xr.open_dataset('/home/loic/Downloads/czechia_nrt_test.nc', chunks=-1) >>> cube = cube.rename({'B02_20':'B02', 'B03_20': 'B03', 'B04_20': 'B04'})
>>> geom = {'type': 'Point', 'coordinates': [4813210, 2935950]} >>> fc = [{'geometry': mapping(Point(4813210, 2935950)), ... 'properties': {'pid': 1}}, ... {'geometry': mapping(Point(4813350, 2934998)), ... 'properties': {'pid': 2}}]
>>> loader = FileLoader(fc=fc, ... key='pid', ... crs=cube.rio.crs, ... datasets=cube, ... vis={'NDVI': utils.combine_transforms(S2CloudMasking(), CR_SWIR()), ... 'CR-SWIR': utils.combine_transforms(S2CloudMasking(), NDVI())}, ... window_size=300, ... compositor=SimpleComposite(), ... res=None) >>> print(len(loader[0])) 6
- class nrt.validate.loaders.STACLoader(fc: List[Dict[str, Any]], key: str, crs: Any, client: Client, collection_id: str, bands: List[str], datetime: List[datetime | str], resampling: str | Dict[str, str] | None, vis: Dict[str, Callable[[DataArray], Any]], window_size: float, compositor: Callable[[Dataset], ndarray], query: Dict | None, xr_transform: Callable[[Dataset], Dataset] | None = None, res: float | None = None, prefetch: int | None = 5, cache_size: int | None = 20, **kwargs)
Bases:
BaseLoaderLoader to prepare data indexed into a STAC Catalogue
- Parameters:
fc (list) – A feature collection. Can be Points, Polygons or a mix of the two. Must contain a property that can be used as a unique key
key (str) – Name of the feature collection property to be used as unique identifier
crs (CRS) – A coordinate reference object, from fiona, rasterio, pyproj, etc representing projection of both
fcanddatasetsclient (Client) – The STAC API client.
collection_id (str) – The STAC collection ID to query.
bands (list) – List of bands to load from the STAC collection.
datetime (list) – List of datetime objects or strings defining the time range to query.
resampling (str or dict, optional) – Resampling method(s) for the bands.
vis (dict) – Dictionary of callables to compute vegetation indices see
nrt.validate.indicesmodule for examples and already implemented indices.window_size (float) – Size of the bounding box used for cropping (created around the centroid of
geom). In CRS unit.compositor (callable) – Callable to transform a temporal slice of the provided Dataset into a 3D numpy array. See
nrt.validate.compositesmodule for examples.query (dict, optional) – Additional query parameters for the STAC API.
res (float, optional) – Spatial resolution for the output data.
prefetch (int, optional) – Number of items to prefetch and cache.
cache_size (int, optional) – Maximum size of the cache.
xr_transform (callable) – Callable that takes an xarray Dataset as input and returns another xarray Dataset. This operation is applied to the spatial subset of the cube used for generating chips and VI time-series. Generally used for pre-processing steps such as removal of “empty” slices, or data scaling.
kwargs (dict, optional) – Additional arguments passed to
nrt.validate.utils.get_chips.
- Returns:
- A tuple of 6 elements:
The unique key of the sample
Array of numpy.datetime64
List of ipywidgets.Image (the image chips)
Dictionary of values for multiple vegetation indices
The sample geometry
The CRS object
- Return type:
tuple
Examples
>>> import datetime >>> from nrt.validate.loaders import STACLoader >>> from pystac_client import Client >>> import planetary_computer as pc >>> from pyproj import CRS >>> from nrt.validate import utils >>> from nrt.validate.indices import * >>> from nrt.validate.composites import * >>> from nrt.validate.xr_transforms import *
>>> fc = [{'geometry': {'type': 'Point', 'coordinates': (4033880, 3217980)}, ... 'properties': {'idx': 1}}, ... {'geometry': {'type': 'Point', 'coordinates': (4395490, 3038090)}, ... 'properties': {'idx': 2}}, ... {'geometry': {'type': 'Point', 'coordinates': (4713260, 2931020)}, ... 'properties': {'idx': 3}}] >>> key = 'idx' >>> crs = CRS.from_epsg(3035) >>> catalog = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1', ... modifier=pc.sign_inplace) >>> collection_id = 'sentinel-2-l2a' >>> bands = ['B02', 'B03', 'B04', 'B08', 'B11', 'B12', 'SCL'] >>> resampling = {band: 'nearest' if band == 'SCL' else 'cubic' for band in bands} >>> dt = [datetime.datetime(2019, 1, 1), datetime.datetime(2021,12,31)] >>> vis = {'NDVI': utils.combine_transforms(S2CloudMasking(), CR_SWIR(nir='B08')), ... 'CR-SWIR': utils.combine_transforms(S2CloudMasking(), NDVI(red='B04', nir='B08'))} >>> window_size = 300 >>> compositor = SimpleComposite(r='B04', g='B03', b='B02') >>> query = {"eo:cloud_cover": {"lt": 10}} >>> res = 10 >>> prefetch = 5 >>> loader = STACLoader(fc=fc, ... key=key, ... crs=crs, ... client=catalog, ... collection_id=collection_id, ... bands=bands, ... resampling=resampling, ... datetime=dt, ... vis=vis, ... window_size=window_size, ... compositor=compositor, ... query=query, ... res=res, ... prefetch=prefetch) >>> print(loader[0])
nrt.validate.segments module
Module with data structures to handle temporal segmentation and interface with sqlite database
- class nrt.validate.segments.Segment(begin: datetime64, end: datetime64, label=None)
Bases:
objectRepresents a temporal segment with a beginning and an end, optionally labeled.
- Parameters:
begin (numpy.datetime64) – The beginning of the segment.
end (numpy.datetime64) – The end of the segment.
label (str) – An optional label for the segment
Examples
>>> import numpy as np >>> import sqlite3 >>> s = Segment(np.datetime64('2020-01-01'), ... np.datetime64('2020-01-02'), ... 'forest dieback') >>> print(s) Temporal segment begin: 2020-01-01 end: 2020-01-02 label: forest dieback
>>> s.breakpoints [numpy.datetime64('2020-01-01'), numpy.datetime64('2020-01-02')]
>>> conn = sqlite3.connect(':memory:') >>> s.to_db(conn, 6) >>> cur = conn.cursor() >>> _ = cur.execute("SELECT id, feature_id, begin, end, label FROM segments WHERE id = ?", (1,)) >>> row = cur.fetchone() >>> print(row) (1, 6, 18262, 18263, 'forest dieback')
- property breakpoints
- classmethod from_db(idx, conn)
Create a Segment instance from the database using the segment ID.
- Parameters:
idx (int) – The ID of the segment in the database.
conn – sqlite database connection
- Returns:
An instance of the Segment class.
- Return type:
- to_db(conn, feature_id)
Save the Segment instance to the database.
- Parameters:
db_path (str) – Path to the SQLite database.
feature_id (int) – The feature ID to associate with the segment.
- widget(labels=['forest', 'dieback', 'non-forest'])
Create a widget with a label and dropdown for segment label selection.
- class nrt.validate.segments.Segmentation(**kwargs: Any)
Bases:
HasTraitsContainer for segmentation with observable traits
- Parameters:
breakpoints (list) – A list of numpy.datetime64 corresponding to breakpoints around temporal segments.
segments (list) – A list of ``Segment``s. The corresponding attribute is dynamically computed and updated from the breakpoints attribute
Examples
>>> import sqlite3 >>> import numpy as np
>>> # Generate 50 random dates between 2005 and 2008 >>> start_date = np.datetime64('2005-01-01') >>> end_date = np.datetime64('2008-12-31') >>> num_days = (end_date - start_date).astype(int) >>> random_days = np.sort(np.random.randint(0, num_days, 50)) >>> random_dates = start_date + random_days >>> random_dates = np.append(random_dates, end_date) >>> # Open a sqlite3 connection >>> conn = sqlite3.connect(':memory:')
>>> seg = Segmentation.from_datelist(random_dates, conn, ... labels=['a', 'b']) >>> print(seg) Temporal segmentation with 2 breakpoints and 1 segments >>> seg.add_breakpoint(np.datetime64('2006-11-21')) >>> print(seg) Temporal segmentation with 3 breakpoints and 2 segments >>> seg.remove_breakpoint(np.datetime64('2006-11-21')) >>> print(seg) Temporal segmentation with 2 breakpoints and 1 segments >>> # Write results to a sqlite database >>> seg.add_breakpoint(np.datetime64('2006-11-21')) >>> seg.to_db(12) >>> cur = conn.cursor() >>> _ = cur.execute('SELECT * FROM segments WHERE feature_id = 12') >>> rows = cur.fetchall() >>> print(rows) [(1, 12, 12788, 13473, None), (2, 12, 13473, 14244, None)]
- add_breakpoint(date)
Add a breakpoint date to the segmentation.
- Parameters:
date (np.datetime64) – The date to add as a breakpoint.
- add_or_remove_breakpoint(date)
If the date provided is already a breakpoint, remove it, otherwise add it
- breakpoints: List[datetime64]
An instance of a Python list.
- static compute_breakpoints(segments)
Compute breakpoints given a list of segments.
- Parameters:
segments (list of Segment) – List of segments.
- Returns:
Sorted list of unique breakpoints.
- Return type:
list of np.datetime64
- conn: Connection
- display_widgets()
Display the widgets for segment management.
- static exists(feature_id, conn)
Check if a feature ID exists in the segments table.
- Parameters:
feature_id (int) – The feature ID.
db_path (str) – Path to the SQLite database.
- Returns:
True if the feature ID exists, False otherwise.
- Return type:
bool
- classmethod from_datelist(dates, conn, labels)
Create a Segmentation instance from a list of dates.
Assigns a single temporal segment spanning the entire time-series
- Parameters:
dates (list of np.datetime64) – List of dates.
db_path (str) – Path to the SQLite database.
- Returns:
An instance of the Segmentation class.
- Return type:
- classmethod from_db(feature_id, conn, labels)
Create a Segmentation instance from the database using the feature ID.
- Parameters:
feature_id (int) – The feature ID.
db_path (str) – Path to the SQLite database.
- Returns:
An instance of the Segmentation class.
- Return type:
- classmethod from_db_or_datelist(feature_id, conn, dates, labels)
Create a Segmentation instance either from the database or from a list of dates.
- Parameters:
feature_id (int) – The feature ID.
conn (sqlite3.Connection) – Connection to a sqlite database
dates (list of np.datetime64) – List of dates.
- Returns:
An instance of the Segmentation class.
- Return type:
- static get_db_idx(feature_id, conn)
Retrieve the IDs of segments with a given feature ID.
- Parameters:
feature_id (int) – The feature ID.
conn (sqlite3.Connection) – Database connection
- Returns:
List of segment IDs.
- Return type:
list of int
- static get_fids_db(conn)
Get a list of unique feature_ids present in the database
- labels: List[str]
- remove_breakpoint(date)
Remove a breakpoint date from the segmentation.
- Parameters:
date (np.datetime64) – The date to remove from breakpoints.
- Raises:
ValueError – If the date is not a valid breakpoint.
- to_db(feature_id)
Save the Segmentation instance to the database.
- Parameters:
feature_id (int) – The feature ID.
- nrt.validate.segments.disable_trait_notifications(self)
Temporatilly disable trait notifications.
nrt.validate.webmaps module
- class nrt.validate.webmaps.EsriWaybackBasemap
Bases:
objectA class to create and display an Esri Wayback basemap with time navigation functionality using ipyleaflet.
- map
The ipyleaflet map instance.
- Type:
ipyleaflet.Map
- DATE_TIMEID_MAPPING
A list of tuples containing date and ID mappings.
- Type:
list
Example
>>> from nrt.validate.webmaps import EsriWaybackBasemap >>> esri_wayback_map = EsriWaybackBasemap() >>> display(esri_wayback_map.map)
- class nrt.validate.webmaps.GoogleBasemap
Bases:
objectA class to create and display a Google basemap using ipyleaflet.
- map
The ipyleaflet map instance.
- Type:
ipyleaflet.Map
Example
>>> from nrt.validate.webmaps import GoogleBasemap >>> google_map = GoogleBasemap() >>> display(google_map.map)
- class nrt.validate.webmaps.PlanetBasemap(frequency='quarterly', begin=datetime.datetime(2017, 1, 1, 0, 0), end=datetime.datetime(2026, 2, 20, 18, 39, 21, 584490), api_key='')
Bases:
objectA class to create and display Planet basemaps with time navigation functionality using ipyleaflet.
- Parameters:
frequency (str) – The frequency of the basemap updates. Either ‘monthly’ or ‘quarterly’.
begin (datetime.datetime) – The start date for the basemap time range.
end (datetime.datetime) – The end date for the basemap time range.
api_key (str) – The API key for accessing Planet basemaps.
- frequency
The frequency of the basemap updates. Either ‘monthly’ or ‘quarterly’.
- Type:
str
- begin
The start date for the basemap time range.
- Type:
datetime.datetime
- end
The end date for the basemap time range.
- Type:
datetime.datetime
- api_key
The API key for accessing Planet basemaps.
- Type:
str
- map
The ipyleaflet map instance.
- Type:
ipyleaflet.Map
Example
>>> import datetime >>> from nrt.validate.webmaps import PlanetBasemap >>> planet = PlanetBasemap(frequency='monthly', begin=datetime.datetime(2017, 1, 1), end=datetime.datetime.now(), api_key='your_api_key') >>> display(planet.map)
nrt.validate.xr_transforms module
Callables to apply a transformation to a xarray Dataset Usually returns another xarray Dataset
- class nrt.validate.xr_transforms.BaseS2Transform(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12', scl: str = 'SCL')
Bases:
ABCAbstract base class for Sentinel2 based indices
- blue: str = 'B02'
- green: str = 'B03'
- nir: str = 'B8A'
- re1: str = 'B05'
- re2: str = 'B06'
- re3: str = 'B07'
- red: str = 'B04'
- scl: str = 'SCL'
- swir1: str = 'B11'
- swir2: str = 'B12'
- class nrt.validate.xr_transforms.S2CloudMasking(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12', scl: str = 'SCL', valid_scl_values: list = <factory>)
Bases:
BaseS2TransformReplace pixels identified as clouds, shadows, snow or dark pixels by np.nan
- valid_scl_values: list
- class nrt.validate.xr_transforms.S2MonthlyBest(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12', scl: str = 'SCL', valid_scl_values: list = <factory>, weight_valid: float = 1.0, weight_time: float = 0.5)
Bases:
BaseS2TransformSelect the best image per month based on valid data percentage and date
The best image selection algorithm works by computing a score for each image based on the percentage of valid data and the temporal proximity to the center of the month.
- Parameters:
ds (xr.Dataset) – xarray Dataset with time dimension
scl (str) – name of the SCL variable in the dataset
valid_scl_values (list) – list of valid SCL values used to compute the valid data score
weight_valid (float) – weight for the valid data score
weight_time (float) – weight for the temporal proximity score
Example
>>> from nrt import data >>> from nrt.validate.xr_transforms import S2MonthlyBest
>>> # Load a small spatial-temporal subset of the dataset >>> ds = data.germany_zarr() >>> ds_sub = ds.isel(x=slice(100, 110), y=slice(200, 210))
>>> # Apply the transformation >>> transform = S2MonthlyBest() >>> ds_best = transform(ds_sub) >>> print(ds_best) <xarray.Dataset> Size: 261kB Dimensions: (time: 50, y: 10, x: 10) Coordinates: spatial_ref int32 4B 3035 * time (time) datetime64[ns] 400B 2018-02-22T10:40:29.028000 ... 20... * x (x) float64 80B 4.134e+06 4.134e+06 ... 4.134e+06 4.134e+06 * y (y) float64 80B 3.111e+06 3.111e+06 ... 3.111e+06 3.111e+06 Data variables: B02 (time, y, x) float64 40kB 0.0501 0.0656 0.0736 ... nan nan nan B03 (time, y, x) float64 40kB 0.0722 0.0863 0.0909 ... nan nan nan B04 (time, y, x) float64 40kB 0.0577 0.0862 0.1035 ... nan nan nan B08 (time, y, x) float64 40kB 0.3225 0.2855 0.2602 ... nan nan nan B11 (time, y, x) float64 40kB 0.2112 0.2219 0.2331 ... nan nan nan B12 (time, y, x) float64 40kB 0.1264 0.1362 0.1457 ... nan nan nan SCL (time, y, x) float32 20kB 4.0 4.0 4.0 4.0 ... 0.0 0.0 0.0 0.0
- valid_scl_values: list
- weight_time: float = 0.5
- weight_valid: float = 1.0
- class nrt.validate.xr_transforms.S2OffsetCorrection(blue: str = 'B02', green: str = 'B03', red: str = 'B04', nir: str = 'B8A', re1: str = 'B05', re2: str = 'B06', re3: str = 'B07', swir1: str = 'B11', swir2: str = 'B12', scl: str = 'SCL', offset: int = 1000)
Bases:
BaseS2TransformApply radiometric offset correction to Sentinel-2 bands.
Starting from processing baseline 04.00, Sentinel-2 data includes a radiometric offset (1000). This transform subtracts that offset from all spectral bands while preserving the SCL (Scene Classification Layer).
- Parameters:
offset (int) – The value to subtract from the bands. Default is 1000.
- offset: int = 1000