Spaces:
Running on Zero
Running on Zero
|
Download README.md from akashch1512/SingleViewHeigthEstimation: direct link, hf CLI and curl.
- Browser
- Download file 5.66 kB
-
https://huggingface.co/spaces/akashch1512/SingleViewHeigthEstimation/resolve/main/README.md
- Command line
-
hf download hf://spaces/akashch1512/SingleViewHeigthEstimation/README.md
-
curl -L -o README.md https://huggingface.co/spaces/akashch1512/SingleViewHeigthEstimation/resolve/main/README.md
5.66 kB
| title: SingleViewHeigthEstimation | |
| emoji: π’ | |
| colorFrom: pink | |
| colorTo: pink | |
| sdk: gradio | |
| sdk_version: 6.27.0 | |
| python_version: '3.12' | |
| app_file: app.py | |
| pinned: false | |
| license: mit | |
| # Single View Height Estimation | |
| Per-pixel above-ground height from one optical aerial or satellite image, with an | |
| interactive 3D inspector for the result. | |
| ## Using the Space | |
| Upload an image, state its ground sampling distance in metres per pixel, and run. | |
| The GSD is not cosmetic β every height, slope and distance the viewer reports is | |
| derived from it, so a wrong GSD gives a plausible-looking surface with wrong | |
| numbers. A georeferenced GeoTIFF carries its own resolution; leave the field at | |
| its default to use that, or set it to override. | |
| Optional **test-time augmentation** flip-averages the prediction. It is steadier | |
| on noisy input; all 8 views of each tile run in a single GPU batch, so it costs | |
| 8Γ the compute but far less than 8Γ the wall time on a large GPU. | |
| ## What comes back | |
| * **DSM viewer & 3D flythrough** β the same standalone viewer that ships in | |
| `viewer/`, inlined into the page. Orbit, first-person (`F`) and cinematic drone | |
| cameras; an optical / height-colormap / hillshade drape; vertical exaggeration; | |
| a movable sun with cast shadows; a 2-D map pane with optional contours; and | |
| click-to-probe, which reports a height, and on a second click a ground | |
| distance, slope and elevation profile between the two points. | |
| * **Derived rasters** β the turbo height colormap and a 315Β°/45Β° hillshade. | |
| Hillshade is the honest test of a DSM: flat ground has to read as flat. | |
| * **Height16** β the height field as an 8-bit PNG carrying 16 bits of precision | |
| across its red and green channels: | |
| `height_m = min + (RΒ·256 + G) / 65535 Β· (max β min)`. This is what the viewer | |
| decodes, because a browser down-converts a true 16-bit PNG to 8 bits β which | |
| would quantise a 0β60 m scene into 0.23 m steps before anything is drawn. | |
| * **Artefacts** β a zip plus the headline files: `ndsm_m.npy` (bit-exact | |
| float32 metres), `meta.json` (the full contract, including the encoding | |
| affine), `terrain.glb` (a self-contained binary glTF with the optical image | |
| as its base-colour texture β opens in any glTF viewer), `terrain.obj` + | |
| `.mtl` + `texture.png` for MeshLab or Blender, and the two rasters. | |
| * **Object classes** β `seg.png`, the segmentation head's class per pixel on the | |
| height grid (8-bit greyscale ids; the id β name legend is `meta.json` | |
| `classes`: other, ground, low_veg, building, water, road, tree), plus a | |
| colour preview in the gallery. | |
| * **3D objects** β `objects.json` (`infer/objects.py`): trees as | |
| `{x, y, h, r}` (crown centre, top height, crown radius), buildings as | |
| footprint polygons with a median roof height, and water outlines. Positions | |
| are pixels on the height grid; heights and radii are metres. Trees are split | |
| into crowns by a watershed on the smoothed canopy seeded at its peaks, so | |
| touching crowns come out as separate trees. The gallery's "Detected trees, | |
| buildings and water" overlay is the check: every circle should sit on a tree. | |
| A failure in this step is reported in the status and never costs the height map. | |
| Heights are metres above local ground (nDSM). An input without georeferencing | |
| yields a relative surface (`rDSM`); `meta.json` says which you got, and does not | |
| publish an affine transform for a scene the demo resampled. | |
| ## Layout | |
| | path | what it is | | |
| |---|---| | |
| | `app.py` | the Space: inference, encodings, artefacts, and the viewer iframe | | |
| | `infer/`, `dwdata/`, `models/` | the model and the preprocessing contract stored in the checkpoint | | |
| | `infer/objects.py` | class map + height map β trees / buildings / water (`objects.json`) | | |
| | `tests/` | CPU-only unit tests for the object step (`pytest -q`; no torch needed) | | |
| | `viz/` | figure primitives, the mesh writers, and the standalone validation report | | |
| | `viewer/` | the dual-pane DSM inspector β `index.html` + `app.js` + vendored three.js | | |
| | `predict_image.py` | single-image CLI, writing the older `phase0_viewer.html` | | |
| `viewer/index.html` has no build step and no network dependency: opened straight | |
| off disk it behaves exactly as it does in the Space, and takes a prediction three | |
| ways β its file picker, a `?result=<directory>` URL, or an inlined payload, which | |
| is how `app.py` hands it a result. | |
| ## Running the model | |
| The Space reads its checkpoint from `/data/best.pt`, so a Hugging Face bucket | |
| containing `best.pt` must be mounted at `/data`, and `HF_TOKEN` must be set as a | |
| Space secret for the DINOv3 encoder download. | |
| ## Area mode (GeoLibre plugin) | |
| Two API-only endpoints serve the DepthWizard GeoLibre plugin: | |
| * `/catalog` β the tile repository's footprints (GeoJSON). | |
| * `/predict_area(bbox_json, tta)` β `"[west, south, east, north]"` in WGS84. | |
| The tiles under the box are stitched onto a 0.5 m UTM grid (`tiles/mosaic.py`), | |
| run through the same model, and returned georeferenced: `ndsm_m.tif`, | |
| `height_overlay.png` (map overlay, corners in the result's `corners_wgs84`), | |
| `objects.geojson` (WGS84), `ndsm_rgb.png` + `imagery.jpg` (Terrain-RGB | |
| heights and their texture on the same corners, for the GeoLibre plugin's 3D | |
| view), plus the usual artefacts. A partly covered box is | |
| processed over its covered part (`coverage` < 1); an uncovered one returns | |
| `status: "not_available"`. | |
| The repository is a folder at `DW_TILES_DIR` (default `/data/tiles`, i.e. the | |
| mounted bucket): `catalog.geojson` + one COG per tile, built from GeoTIFFs with | |
| `python -m tiles.build_catalog <tifs> --out <dir>`. `pytest tests/test_tiles.py` | |
| covers it without torch. | |