Process satellite imagery to monitor grove health Data sources: - Sentinel-2 (ESA): Free, 10m resolution, 5-day revisit - Planet Labs: Commercial, 3m resolution, daily - Landsat 8/9: Free, 30m resolution, 16-day revisit
| 29 | |
| 30 | |
| 31 | class SatelliteDataProcessor: |
| 32 | """ |
| 33 | Process satellite imagery to monitor grove health |
| 34 | |
| 35 | Data sources: |
| 36 | - Sentinel-2 (ESA): Free, 10m resolution, 5-day revisit |
| 37 | - Planet Labs: Commercial, 3m resolution, daily |
| 38 | - Landsat 8/9: Free, 30m resolution, 16-day revisit |
| 39 | """ |
| 40 | |
| 41 | def __init__(self): |
| 42 | self.baseline_ndvi = {} # Historical baseline by grove |
| 43 | self.sentinel2_bands = { |
| 44 | 'red': 4, |
| 45 | 'nir': 8, # Near-infrared |
| 46 | 'swir': 11 # Shortwave infrared |
| 47 | } |
| 48 | |
| 49 | def calculate_ndvi( |
| 50 | self, |
| 51 | red_band: np.ndarray, |
| 52 | nir_band: np.ndarray |
| 53 | ) -> np.ndarray: |
| 54 | """ |
| 55 | Calculate Normalized Difference Vegetation Index |
| 56 | |
| 57 | NDVI = (NIR - Red) / (NIR + Red) |
| 58 | |
| 59 | Values: |
| 60 | 0.8-1.0: Dense healthy vegetation |
| 61 | 0.6-0.8: Moderate vegetation |
| 62 | 0.2-0.6: Sparse vegetation / stressed |
| 63 | <0.2: Bare soil / dead vegetation |
| 64 | """ |
| 65 | |
| 66 | # Avoid division by zero |
| 67 | denominator = nir_band + red_band |
| 68 | denominator[denominator == 0] = 0.0001 |
| 69 | |
| 70 | ndvi = (nir_band - red_band) / denominator |
| 71 | |
| 72 | # Clip to valid range |
| 73 | ndvi = np.clip(ndvi, -1, 1) |
| 74 | |
| 75 | return ndvi |
| 76 | |
| 77 | def calculate_water_stress_index( |
| 78 | self, |
| 79 | nir_band: np.ndarray, |
| 80 | swir_band: np.ndarray |
| 81 | ) -> np.ndarray: |
| 82 | """ |
| 83 | Calculate Normalized Difference Water Index (NDWI) |
| 84 | |
| 85 | NDWI = (NIR - SWIR) / (NIR + SWIR) |
| 86 | |
| 87 | High values: High vegetation water content |
| 88 | Low values: Water stress |
no outgoing calls
no test coverage detected