# Birkastan field archive

A local reference collection for **Rörstrandsgatan and nearby streets, up Norrbackagatan to Hagastaden**. Open `Open collection.command` or `site/index.html` to browse the downloaded photos on a map. It works offline after collection.

The browser filters photos by source, year, street text and corridor. Click the map for nearby images; click a photo for the local file, capture date and attribution. The gap layer shows where photo locations are missing. A nearby photo does not necessarily show a particular facade.

The **Look around open 360° panoramas** link opens the downloaded equirectangular images in a local viewer. Its code is vendored, so it makes no external image requests. Double-click **Open collection.command** to open or start the local collection server. The main gallery also works directly from disk. To start the server manually:

```sh
uv run python -m http.server 8765 --bind 127.0.0.1
```

Then open `http://127.0.0.1:8765/site/index.html`.

## What is here

| Location | Contents |
|---|---|
| `references/google-streetview/` | Separate proprietary Google route screenshots, viewing links and capture log |
| `data/images/` | Downloaded photographs, grouped by source and stable source ID |
| `data/raw/` | Original API responses, request provenance, city archive and OSM extract |
| `data/catalog/catalog.sqlite` | Resumable inventory, file hashes, download status and source metadata |
| `data/derived/thumbnails/` | Small browsing images; source downloads remain separate |
| `exports/catalog.csv` and `.json` | Portable photograph catalog |
| `exports/attribution.csv` | Per-image credits, licenses and source links |
| `exports/geodata/` | Buildings, streets, street objects, image locations and coverage as GeoJSON |
| `exports/geodata/stockholm_lod1_native/` | Clipped city MultiPatch shapes in their original coordinate system |
| `exports/models/` | City building surfaces converted to OBJ, for the priority corridor and wider context |
| `exports/capture-priorities.csv` | Buildings with few nearby references, ready for field review |
| `exports/capture-waypoints.gpx` | 35 m planning samples along the two named streets; not a routed walk |
| `capture/inbox/` | Put your own photos here before importing |
| `reconstruction/` | Source-tracked subsets for modeling experiments |
| `logs/` | Discovery, model conversion and integrity reports |

`exports/manifest.json` is the source of truth for the current counts, size, years and outstanding downloads. Images marked failed or pending are not counted as downloaded. Spatial and category searches include context and some unlocated historical references; these are distinct from the priority corridor. Automated discovery does not guarantee that every reference depicts architecture.

## Collect and refresh

This project uses Python and [uv](https://docs.astral.sh/uv/). Run these from the project folder:

```sh
uv sync
uv run python collect.py all
```

Individual steps are resumable:

```sh
uv run python collect.py commons
uv run python collect.py kartaview
uv run python collect.py panoramax
uv run python collect.py download --provider panoramax --workers 3
uv run python collect.py download --provider commons --workers 1
uv run python collect.py download --provider kartaview --workers 4
uv run python collect.py build
uv run python collect.py verify
```

Metadata requests are cached. Use `--refresh` with a source command to ask for a fresh inventory. Repeating the download command skips completed files and retries failed files. Run one download process at a time when relying on the project disk budget. The default budget is 8 GB of downloaded photographs; change `download_max_gb` in `config.json` or use `--max-gb`. A provider rate limit stops a download pass; wait before retrying. The catalog retains the reason for each failure.

Wikimedia downloads use the API's standard 1920-pixel-wide rendition where available, following its image-delivery guidance. For small originals, the next smaller standard rendition avoids unscaled-original delivery. Original URLs and source dimensions are retained. KartaView downloads use its processed public images, falling back to the public large thumbnail when the full processed file is missing. Actual downloaded dimensions and available rendition information are recorded separately from source dimensions. `commons_download_width` can be set to a supported size such as 3840 before fetching metadata again; existing downloads are preserved.

Panoramax discovery uses the public federated catalog and downloads public HD assets. Each photo retains its own license, photographer, capture date, heading, accuracy and available camera metadata. These are processed public images, not raw camera originals.

The **Street View route** link opens a separate screenshot contact sheet with the original Google viewing links. Those images carry Google’s visible credits and are not open-licensed assets. They are excluded from the open-image catalog and modeling subset tool. See `references/google-streetview/README.md`.

Change the bounding box, street names or corridor width in `config.json` to extend the survey. After changing the area, refresh OSM and rerun discovery and build. The city conversion currently selects the Norrmalm source district, which covers this Stockholm corridor; extending into other districts or Solna requires another geometry source or selector.

## Add your own photographs

Copy images into `capture/inbox`, then run:

```sh
uv run python collect.py import-local --folder capture/inbox
uv run python collect.py build
```

The importer copies files, reads available GPS and date metadata, and deduplicates identical local captures by content hash. It does not publish or upload them. Declare ownership/usage rights before redistributing your own additions.

## Use the geometry and references

Start with `exports/models/stockholm_lod1_priority.obj`. It contains the city’s source building surfaces, including courtyard openings, triangulated for import. **Units are metres; X is east, Y is north, Z is up.** XY is relative to the recorded origin in `exports/georeference.json`; source Z elevations are retained. The OBJ is untextured. No terrain or detailed roof model has been collected.

These are generalized LOD1 blocks, not detailed facades or a complete present-day model. The city metadata describes median roof elevations and a 2023 production generation using 2022 laser data. Per-object source dates are retained. Hagastaden has changed since then. Use current OSM footprints and recent photos to identify buildings missing from or changed since the city dataset.

Build a reference subset, for example:

```sh
uv run python stage.py rorstrand-reference --street Rörstrandsgatan
uv run python stage.py sequence-study --provider kartaview --sequence 11399929
```

The staged set links to the local images and includes its provenance. Add `--copy` for a self-contained copy. For photogrammetry, select a coherent capture sequence and session; mixed dates, panorama projections, moving objects and inconsistent camera calibration need review before solving cameras. These references are useful for manual modeling, but their existence alone does not establish a usable photogrammetry or Gaussian splatting dataset.

## Extend the sources

The Mapillary adapter is prepared but requires your own developer access token. It has not been exercised against authenticated live coverage in this collection. Set `MAPILLARY_ACCESS_TOKEN` in your local shell, then run `collect.py mapillary`, `collect.py download --provider mapillary`, and `collect.py build`. Tokens are read from the environment and excluded from saved request metadata. Use provider terms when selecting a downstream use.

See `docs/sources.md` for source provenance and `docs/capture-plan.md` for the field pass. No paid data has been ordered.

## Verification

```sh
uv run python -m unittest test_pipeline.py
uv run python collect.py verify
```

The geometry checks cover metre-scale coordinates, local axes, courtyard holes, vertical surfaces, outward surface orientation, corridor selection and capture-date parsing. OBJ surface winding is corrected for outward-facing normals without moving the source geometry. File verification decodes every downloaded image and checks its SHA-256 hash. A damaged file is marked failed so a subsequent download can repair it.
