diff --git a/lidar_pipeline/visualizations.py b/lidar_pipeline/visualizations.py index 9ebb913..13e5390 100644 --- a/lidar_pipeline/visualizations.py +++ b/lidar_pipeline/visualizations.py @@ -214,22 +214,19 @@ def _fill_nans(arr): """Fill NaN values using nearest-neighbor interpolation. Returns (filled_array, nan_mask) so the caller can restore NaN after filtering. + + Via transformée de distance (O(n), vectorisé) : les indices du plus proche + voisin valides sortent en une passe. NearestNDInterpolator construisait un + cKDTree sur TOUS les points valides (25 M à 0,2 m) — plusieurs secondes + par dalle trouée, payées au premier accès de SharedDEM.filled. """ - from scipy.interpolate import NearestNDInterpolator nan_mask = np.isnan(arr) if not np.any(nan_mask): return arr, nan_mask - valid = ~nan_mask - y_coords, x_coords = np.where(valid) - if len(y_coords) == 0: - return np.zeros_like(arr), nan_mask - z_values = arr[valid] - interp = NearestNDInterpolator( - np.column_stack((y_coords, x_coords)), z_values - ) - y_missing, x_missing = np.where(nan_mask) + from scipy.ndimage import distance_transform_edt + _, (iy, ix) = distance_transform_edt(nan_mask, return_indices=True) filled = arr.copy() - filled[y_missing, x_missing] = interp(y_missing, x_missing) + filled[nan_mask] = arr[iy[nan_mask], ix[nan_mask]] return filled, nan_mask