| """ | |
| Minimal vegetation index extraction (NDVI, ARI, GNDVI only). | |
| """ | |
| import numpy as np | |
| from typing import Dict, Any | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| class VegetationIndexExtractor: | |
| """Minimal vegetation index extraction.""" | |
| def __init__(self, epsilon: float = 1e-10, soil_factor: float = 0.5): | |
| """Initialize with defaults.""" | |
| self.epsilon = epsilon | |
| self.soil_factor = soil_factor | |
| self.index_formulas = { | |
| "NDVI": lambda nir, red: (nir - red) / (nir + red + self.epsilon), | |
| "GNDVI": lambda nir, green: (nir - green) / (nir + green + self.epsilon), | |
| "SAVI": lambda nir, red: ((nir - red) / (nir + red + self.soil_factor)) * (1.0 + self.soil_factor), | |
| } | |
| self.index_bands = { | |
| "NDVI": ["nir", "red"], | |
| "GNDVI": ["nir", "green"], | |
| "SAVI": ["nir", "red"], | |
| } | |
| def compute_vegetation_indices(self, spectral_stack: Dict[str, np.ndarray], | |
| mask: np.ndarray) -> Dict[str, Dict[str, Any]]: | |
| """Compute NDVI, ARI, and GNDVI.""" | |
| indices = {} | |
| for index_name, formula in self.index_formulas.items(): | |
| try: | |
| required_bands = self.index_bands[index_name] | |
| if not all(band in spectral_stack for band in required_bands): | |
| continue | |
| band_data = [] | |
| for band in required_bands: | |
| arr = spectral_stack[band] | |
| if isinstance(arr, np.ndarray): | |
| arr = arr.squeeze(-1) | |
| band_data.append(np.asarray(arr, dtype=np.float64)) | |
| index_values = formula(*band_data).astype(np.float64) | |
| binary_mask = (np.asarray(mask).astype(np.int32) > 0) | |
| masked_values = np.where(binary_mask, index_values, np.nan) | |
| valid_values = masked_values[~np.isnan(masked_values)] | |
| if len(valid_values) > 0: | |
| stats = { | |
| 'mean': float(np.mean(valid_values)), | |
| 'std': float(np.std(valid_values)), | |
| } | |
| else: | |
| stats = {'mean': 0.0, 'std': 0.0} | |
| indices[index_name] = { | |
| 'values': masked_values, | |
| 'statistics': stats | |
| } | |
| except Exception as e: | |
| logger.error(f"Failed to compute {index_name}: {e}") | |
| return indices |