Spaces:
Runtime error
Runtime error
| """ | |
| CRS-aware GeoTIFF metadata extraction. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Dict, Optional | |
| from pyproj import Geod, Transformer | |
| from app.utils.geo_utils import close_ring | |
| def _estimate_gsd_meters(src) -> Optional[float]: | |
| """Estimate average meters-per-pixel using geodesic edge lengths.""" | |
| try: | |
| transformer = Transformer.from_crs(src.crs, "EPSG:4326", always_xy=True) | |
| geod = Geod(ellps="WGS84") | |
| top_left = src.transform * (0, 0) | |
| top_right = src.transform * (1, 0) | |
| bottom_left = src.transform * (0, 1) | |
| lon1, lat1 = transformer.transform(*top_left) | |
| lon2, lat2 = transformer.transform(*top_right) | |
| lon3, lat3 = transformer.transform(*bottom_left) | |
| width_m = geod.line_length([lon1, lon2], [lat1, lat2]) | |
| height_m = geod.line_length([lon1, lon3], [lat1, lat3]) | |
| if width_m <= 0 or height_m <= 0: | |
| return None | |
| return round((width_m + height_m) / 2, 4) | |
| except Exception: | |
| return None | |
| def extract_geo_reference(image_path: str) -> Optional[Dict[str, Any]]: | |
| """ | |
| Extract a full CRS-aware georeference description from a raster file. | |
| Returns WGS84-facing metadata suitable for API responses and geometry projection. | |
| """ | |
| try: | |
| import rasterio | |
| with rasterio.open(image_path) as src: | |
| if src.crs is None: | |
| return None | |
| transformer = Transformer.from_crs(src.crs, "EPSG:4326", always_xy=True) | |
| bounds = src.bounds | |
| bounds_corners = close_ring([ | |
| [bounds.left, bounds.top], | |
| [bounds.right, bounds.top], | |
| [bounds.right, bounds.bottom], | |
| [bounds.left, bounds.bottom], | |
| ]) | |
| bounds_wgs84_ring = [[*transformer.transform(x, y)] for x, y in bounds_corners] | |
| lon_values = [point[0] for point in bounds_wgs84_ring] | |
| lat_values = [point[1] for point in bounds_wgs84_ring] | |
| return { | |
| "source_crs": src.crs.to_string(), | |
| "epsg": src.crs.to_epsg(), | |
| "transform": list(src.transform)[:6], | |
| "width": src.width, | |
| "height": src.height, | |
| "bounds_source": [bounds.left, bounds.bottom, bounds.right, bounds.top], | |
| "bounds_wgs84": [min(lon_values), min(lat_values), max(lon_values), max(lat_values)], | |
| "bounds_wgs84_ring": bounds_wgs84_ring, | |
| "source_resolution": [float(src.res[0]), float(src.res[1])], | |
| "approx_gsd_m": _estimate_gsd_meters(src), | |
| } | |
| except Exception: | |
| return None | |
| def extract_geo_transform(image_path: str) -> Optional[Dict[str, Any]]: | |
| """ | |
| Backward-compatible alias retained for existing imports. | |
| """ | |
| return extract_geo_reference(image_path) | |