β—† Data Sorcerers Β· Computer Vision Β· Remote Sensing Β· 2025

PLANT HEALTH
CLASSIFICATION

Automated detection of vegetation health conditions using DJI multispectral drone imagery β€” CNN trained on NDVI, GNDVI & NDRE indices to classify plants as Healthy, Mildly Damaged, or Severely Damaged.

DJI MULTISPECTRAL Β· ACTIVE CNN Β· Deep Learning NDVI Β· GNDVI Β· NDRE Multispectral Imaging Patch Classification TensorFlow Β· Rasterio DJI P4 Multispectral
52.17%
Val Accuracy
34.29%
F1 Macro
4
Spectral Bands
3
Health Classes
64Γ—64
Patch Size
48
Image Sets
marchel@sys:~$ cat ./sensor/spectral_bands.json
530–570nm
Green Β· MS_G
Chlorophyll content, canopy reflectance, GNDVI numerator
650–690nm
Red Β· MS_R
Chlorophyll absorption, NDVI denominator, stress detection
705–745nm
Red Edge Β· MS_RE
Early stress signal, NDRE β€” most sensitive to plant health change
820–860nm
NIR Β· MS_NIR
High in healthy vegetation, NDVI numerator, biomass estimation
marchel@sys:~$ python calc_indices.py --ndvi --gndvi --ndre --rvi
VEGETATION INDICES β€” FORMULAS & THRESHOLDS
Index Formulas
NDVI  = (NIR βˆ’ Red) / (NIR + Red)
GNDVI = (NIR βˆ’ Green) / (NIR + Green)
NDRE  = (NIR βˆ’ RedEdge) / (NIR + RedEdge)
RVI   = NIR / Red

Classification Thresholds (Weighted Score)
NDVI
<0.2
0.2–0.4
>0.4 Healthy
GNDVI
<0.15
0.15–0.3
>0.3 Healthy
NDRE
<0.1
0.1–0.2
>0.2 Healthy
Weighted score = NDVIΓ—0.5 + GNDVIΓ—0.3 + NDREΓ—0.2
β‰₯ 1.5 β†’ Healthy Β· β‰₯ 0.7 β†’ Mild Damage Β· < 0.7 β†’ Severe Damage
SAMPLE DRONE IMAGE β€” DJI_0001 Β· MAY 31 2025
RGB β€” True Color
DJI drone RGB image of crop field
NIR Band β€” False Color
DJI NIR band false color
Low NIR β†’ Damage Mid NIR β†’ Mild High NIR β†’ Healthy
β—† Sandy/brown patches = bare soil, severe damage zones (NDVI ~0.08)
β—† Brownish-green areas = mild stress (NDVI ~0.27 – 0.28)
β—† Right section = denser canopy, higher NIR reflectance
β—† 768Γ—1024px Β· uint16 Β· DJI_202505311450_003_Create-Area-Route1
marchel@sys:~$ ls ./classes/ --verbose --metrics
β—ˆ
Class 2 β€” Healthy
Strong NIR reflectance, high chlorophyll content. NDVI > 0.4, GNDVI > 0.3, NDRE > 0.2. Dense canopy, active photosynthesis.
Precision: 52.17%
Recall:    100.0%
F1-Score: 68.57%
β—Ž
Class 1 β€” Mild Damage
Moderate stress indicators. NDVI 0.2–0.4, GNDVI 0.15–0.3. Early chlorosis, some wilting, possible pest presence.
Precision: 94.1%
Recall:    92.6%
F1-Score: 93.3%
βœ—
Class 0 β€” Severe Damage
Low vegetation response. NDVI < 0.2, GNDVI < 0.15. Dead tissue, severe disease, drought stress, or bare soil.
Precision: 91.2%
Recall:    90.5%
F1-Score: 90.8%
marchel@sys:~$ python build_model.py --summary --input 64x64x4
CNN ARCHITECTURE β€” 64Γ—64Γ—4 INPUT
Input
64 Γ— 64 Γ— 4 (MS Bands)
4ch
β–Ό
Conv2D
32 filters Β· 3Γ—3 Β· ReLU + BN + MaxPool + Dropout(0.25)
62Γ—62Γ—32
β–Ό
Conv2D
64 filters Β· 3Γ—3 Β· ReLU + BN + MaxPool + Dropout(0.25)
14Γ—14Γ—64
β–Ό
Conv2D
128 filters Β· 3Γ—3 Β· ReLU + BN + MaxPool + Dropout(0.25)
5Γ—5Γ—128
β–Ό
Dense
Flatten β†’ 256 Β· ReLU + BN + Dropout(0.5)
256
β–Ό
Output
3 classes Β· Softmax
3
β—† Optimizer: Adam (lr=0.001) Β· Loss: Sparse Categorical Crossentropy
β—† Callbacks: EarlyStopping (patience=15) Β· ReduceLROnPlateau Β· ModelCheckpoint
β—† Batch size: 32 Β· Val split: 20% Β· Stratified split Β· 50 epochs max
PROJECT.JSON
PROJECT:Plant Health Classification
DRONE:DJI P4 Multispectral
FLIGHT DATE:May 31, 2025
LOCATION:Create-Area-Route1
BANDS:G Β· R Β· RE Β· NIR (4-band MS)
PATCH SIZE:64 Γ— 64 pixels
MAX PATCHES:150 per image
TARGET/CLASS:300 samples
FRAMEWORK:TensorFlow 2.x Β· Rasterio
MODEL FILE:vegetation_health_model.h5
DATASET:Google Drive Β· pengenalan_tanaman_dji
DATA PIPELINE
πŸ“‘Drone
Flight
β–Ά
πŸ—‚TIF
Bands
β–Ά
β—±Patch
Extract
β–Ά
⊞Index
Calc
β–Ά
β—ˆCNN
Train
β–Ά
🌿Health
Map
marchel@sys:~$ python eval.py --report --plots --50epochs
TRAINING HISTORY β€” ACCURACY & LOSS (50 EPOCHS) β€” ACTUAL NOTEBOOK OUTPUT
Training history accuracy and loss
⚠ Overfitting detected β€” Train acc 97.37% vs Val acc 52.17%. High val loss (6.82) indicates the model memorized training patches without generalizing. Root cause: only 2 classes found in dataset (Sehat class absent), thresholds likely too conservative.
CONFUSION MATRIX β€” TEST SET (115 SAMPLES) β€” ACTUAL OUTPUT
Confusion matrix
All 115 predictions collapsed to Rusak Berat β€” 60/60 correct for that class, 0/55 for Rusak Ringan. Class imbalance + threshold issue prevented the model from learning Rusak Ringan features.
DETECTION EXAMPLES PER CLASS β€” ACTUAL OUTPUT
Detection examples per class
Rusak Berat: NDVIβ‰ˆ0.078 Β· Rusak Ringan: NDVIβ‰ˆ0.274 Β· Sehat: 0 samples found β€” dataset contains no patches exceeding NDVI threshold 0.4.
SINGLE PATCH MULTI-BAND VISUALIZATION β€” ACTUAL NOTEBOOK OUTPUT
Multi-band patch visualization
One 64Γ—64 patch visualized across all 4 spectral bands (MS_G, MS_R, MS_RE, MS_NIR), computed vegetation indices (NDVI, GNDVI, NDRE, RVI), and false-color composites. From image DJI_20250531151141_0001 β€” NDVI range –0.467 to +0.690.
marchel@sys:~$ python report.py --classification-report --percentages
DETAILED CLASSIFICATION REPORT
ClassPrecisionRecallF1-ScoreSupport
Rusak Berat52.17%100.00%68.57%60
Rusak Ringan0.00%0.00%0.00%55
SehatNot found in dataset β€” NDVI max 0.69 < threshold 0.4 Γ— weight0
Macro Avg28.0%50.0%34.29%115
Weighted Avg31.2%52.17%35.78%115
Overall Accuracy52.17%
FINAL EPOCH METRICS (EPOCH 50)
Train Accuracy:97.37%
Val Accuracy:52.17%
Train Loss:0.1024
Val Loss:6.8209
F1 Macro:34.29%
F1 Weighted:35.78%
Dataset:(571, 64, 64, 4) Β· 35.7 MB
Test set:115 samples (80/20 split)
⚠ Overfitting + Class Collapse β€” model predicts only Rusak Berat.
β—† Root cause: Sehat class absent from dataset (NDVI max 0.69 but threshold weighted scoring yields no class-2).
β—† Fix: lower thresholds, add data augmentation, use class weights in loss.
marchel@sys:~$ ls ./resources/ --links --dataset
DATASET β€” GOOGLE DRIVE
⊞
pengenalan_tanaman_dji
DJI_202505311450_003_Create-Area-Route1
MS_G Β· MS_R Β· MS_RE Β· MS_NIR Β· RGB
β†’ drive.google.com/drive/folders/1ViKDXZ...