Post-processing¶
Clean up maps, classify CCDC results and derive masks.
Spatial filters¶
The filters take a map (a DataArray, a numpy array or a raster path) and give back the same kind, georeferencing, NoData and attributes kept.
apply_mmu_filter¶
Minimum mapping unit filter: connected (4-neighbour) patches of pixels holding a value, whatever the value, smaller than mmu_pixels become NoData. Removes the salt-and-pepper noise of per-pixel change maps (a LandTrendr year of loss, a magnitude). Also exported as zeit.apply_mmu_filter; CLI: zeit mmu-filter.
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
DataArray, ndarray or path |
required | A single map, e.g. a year-of-loss map. |
mmu_pixels |
int |
11 |
Smallest patch to keep, in pixels (11 Landsat pixels ≈ 1 ha). |
nodata |
"auto" or float |
"auto" |
The value of "no feature": the map's NoData, else 0 (NaN for floats with NaN). |
loss = zeit.extract_events(lt, min_magnitude=1500)
yod = zeit.apply_mmu_filter(loss.yod, mmu_pixels=11)
zeit.save_raster(yod, "results/loss_year_mmu.tif")
apply_majority_filter¶
Replaces each pixel of a class map with the most common class in its neighbourhood. Also exported as zeit.apply_majority_filter.
| Parameter | Type | Default | Description |
|---|---|---|---|
image |
DataArray, ndarray or path |
required | 2-D class map. |
size |
int |
3 |
Window size (3 = 3 × 3). |
apply_bayesian_filter¶
Smooths per-class probabilities spatially, then takes the most likely class. Unlike the majority filter, confident pixels resist being overruled by their neighbours. Import from zeit.spatial.
| Parameter | Type | Default | Description |
|---|---|---|---|
probs |
DataArray or ndarray |
required | (class, y, x) probabilities or scores, e.g. zeit.classify(..., probability=True).probability. |
window_size |
int |
3 |
Averaging window. |
Returns the winning class per pixel (y, x): its index for a numpy array, the class itself for a DataArray whose first dim has coordinates.
Classification¶
train_classifier¶
Trains a classifier on the features of data at sample points. The features of a pixel are what it holds off y/x: the bands of a map, every date (and band) of a cube, the maps of a Dataset (phenology or LandTrendr metrics…), or, for a zeit.ccdc result with date, the model of the segment covering that date: each band's coefficients (the intercept moved to the date, a0 + c1 t, as CCDC classifications use it) and RMSE. Loaded on first use (scikit-learn).
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
DataArray, Dataset or path |
required | What to classify (see above). |
samples |
GeoDataFrame or path |
required | Points with their class. Points in another CRS are reprojected; points outside the data or on a pixel with a missing feature are left out. |
label |
str |
"class" |
The column holding the class (names or numbers). |
model |
classifier | None |
Any scikit-learn classifier; default a random forest of 100 trees (random_state=42). |
date |
date | None |
CCDC segments: the date whose models are the features. |
Returns the fitted model, with the feature names in zeit_features_.
classify¶
Classifies every pixel with a trained model. The features are taken as in train_classifier, and reordered by name to the model's zeit_features_. A lazy cube stays lazy. Loaded on first use (scikit-learn).
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
DataArray, Dataset or path |
required | The features (see train_classifier). |
model |
classifier | required | A fitted classifier, e.g. from train_classifier. |
date |
date | None |
CCDC segments: the date whose models are the features. |
probability |
bool |
False |
Also return each class's probability (predict_proba). |
Returns an xarray.Dataset: label (y, x), 1 for the first class of model.classes_, 2 for the second… (0: a missing feature), with the names in its flag_meanings (the legend of zeit.plot); probability (class, y, x) with probability=True; the class coordinate holds the classes.
segments = zeit.ccdc(cube, qa="fmask")
rf = zeit.train_classifier(segments, "samples.gpkg", label="class", date="2020-07-01")
land_cover = zeit.classify(segments, rf, date="2020-07-01", probability=True)
land_cover.label.zeit.plot() # legend: the class names
zeit.save_raster(land_cover, "results/land_cover") # label.tif, probability.tif
stack = zeit.load_raster("s2_2022.tif") # any cube: each date and band a feature
classes = zeit.classify(stack, zeit.train_classifier(stack, points))
Masks¶
extract_water_mask¶
Persistent water from CCDC models: water reflects a little in green and almost nothing in SWIR, so a pixel is water when its green level is above its SWIR level and the SWIR level is below threshold. The levels are those of each pixel's first segment at its middle (a0 + c1 t). Also exported as zeit.extract_water_mask.
| Parameter | Type | Default | Description |
|---|---|---|---|
segments |
Dataset |
required | A zeit.ccdc result. A numpy stack in the layout of older versions ((segments, parameters, rows, cols)) is still accepted, with integer band positions. |
green |
str or int |
"green" |
The green band. |
swir |
str or int |
"swir1" |
The SWIR band (SWIR1 or SWIR2). |
threshold |
float |
500.0 |
Highest SWIR level of water (reflectance × 10000). |
Returns a uint8 (y, x) map, 1 = water, georeferenced for a Dataset.
Validation¶
Accuracy assessment and area estimation, and labelling reference points by eye, have a page of their own: Validation.