Paddy-field map

VH phenology features β†’ SMOTE-balanced classifier β†’ multi-year consensus

🌐 English Β· Bahasa Indonesia β†’

The idea

Rice paddies have a distinctive VH backscatter trajectory β€” a deep flooding trough followed by a steep vegetative rise to a canopy peak. We turn a 7-period window of VH values into 29 engineered features (temporal values, differences, ratios, and phenology indicators) and classify each pixel as paddy / non-paddy.

Because paddy hugely outnumbers non-paddy in the training points (β‰ˆ92% vs 8%), a naive model becomes over-conservative. We fix this with SMOTE (synthetic minority over-sampling) to a balanced 50/50 set β€” the single most important step for realistic detection.

Step 1 β€” Train the model (runs from shipped data)

The repository ships pre-extracted features, so training needs no satellite data:

export CUDA_VISIBLE_DEVICES=-1
python train_paddy_vh_smote.py

What happens:

  • loads model_files_paddy_vh/training_data_*.csv (29 VH features per point),
  • applies SMOTE to balance the classes,
  • trains an MLP with 5-fold stratified cross-validation,
  • writes model_files_paddy_vh/paddy_vh_model.keras + scaler.joblib.

Expected cross-validation performance (full study):

Metric Value
Accuracy 95.4% Β± 0.2%
AUC-ROC 98.3% Β± 0.1%
Tip

A trained model already ships in model_files_paddy_vh/ β€” you can skip training and go straight to prediction.

Step 2 β€” Predict on the AOI stack

Point the predictor at the Sentinel-1 stack you fetched in Setup. Because the sample stack is a single year starting at band 1, use --year-start-band 1 and set --year-periods to the number of bands you downloaded (periods 7–24 β†’ 18 bands).

python predict_paddy_vh_multiyear.py \
    --period 15 --year 2024 \
    --year-start-band 1 --year-periods 18 \
    --vh-stack data/sample/klambu_vh_2024.tif \
    --mask data/sample/klambu_mask.tif \
    --skip-test \
    --output-dir predictions_sample/2024/period_15

Outputs (per period):

predictions_sample/2024/period_15/
β”œβ”€β”€ paddy_predictions.tif   # 0 = non-paddy, 1 = paddy
β”œβ”€β”€ confidence.tif          # 0–1 probability
β”œβ”€β”€ paddy_map.png           # quick-look
└── statistics.txt          # area + confidence summary
ImportantFeature window needs history

The 29 features use the current period plus the 6 previous periods. Predict on periods where at least 7 prior bands exist (e.g. period 13+ if your stack starts at period 7). For earlier periods, fetch a stack that starts earlier.

Batch several periods to see the season evolve:

for p in 13 15 17 19 21 23; do
  python predict_paddy_vh_multiyear.py --period $p --year 2024 \
    --year-start-band 1 --year-periods 18 \
    --vh-stack data/sample/klambu_vh_2024.tif --mask data/sample/klambu_mask.tif \
    --skip-test --output-dir predictions_sample/2024/period_$p
done

Step 3 β€” Multi-year consensus (stable paddy)

A single period includes transient false positives. The consensus keeps only pixels detected as paddy consistently β€” ideally across two full years, with confidence and detection-count thresholds. With one sample year you can still build a within-year consensus:

python create_multiyear_composite_paddy.py \
    --years 2024 \
    --periods 2024:"13 15 17 19 21 23" \
    --predictions-dir predictions_sample \
    --output consensus_sample \
    --min-years 1 --min-detections 3 \
    --min-confidence 0.7 --min-mean-confidence 0.6

The --periods flag takes one YEAR:"p1 p2 ..." argument per year and is repeatable β€” e.g. for the full two-year consensus: --periods 2024:"7 9 11" --periods 2025:"7 9 11" --min-years 2.

The consensus rules that matter:

  • --min-confidence 0.7 β€” each detection must be confident,
  • --min-detections 3 β€” must recur across β‰₯3 periods,
  • --min-years 2 (full study) β€” must appear in both years β†’ filters transient false positives.

On the full Java stack this yields the headline stable-paddy map:

Stable-paddy consensus, Java 2024∩2025 (β‰ˆ3.0 million ha) β€” the full-study product.

From β€œdetected” to β€œcultivated”: the cycle-based map

Consensus marks persistence; it does not check that a pixel truly completed a rice cycle. The recommended end-product intersects the consensus with a β‰₯1 complete floodβ†’canopy cycle test (see the Planting index chapter) β€” this rejects persistent non-rice false positives (e.g. highland plantations) and yields the active-paddy map.

Recommended cycle-based active-paddy map, MT 2024/25 (β‰ˆ2.3 million ha).

Next: turn the temporal signal into a planting index β†’ Planting index.