From ec7d294605200fae525a2422c708727640075c97 Mon Sep 17 00:00:00 2001 From: Pikaliov Date: Sat, 9 May 2026 11:50:35 +0300 Subject: [PATCH] docs: rewrite README with exact dataset pipeline Align documentation with prepare_dataset.py behavior (routes, outputs, index formats, and target-size semantics). Co-authored-by: Cursor --- README.md | 257 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 156 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index f4fa4c7..c93d7f8 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,197 @@ # UAV-VisLoc Dataset Preparation -Prepare UAV-VisLoc dataset for cross-view geo-localization retrieval training. -Generates satellite crops, GPS-matched drone-crop pairs, and Index files -compatible with UAV-GeoLoc format. +Подготовка датасета **UAV-VisLoc** для задач cross-view retrieval / geo-localization. -## Pipeline +Скрипт: +- ресайзит drone-кадры +- режет спутниковые карты на кропы фиксированного размера +- считает GPS-координаты центра каждого кропа +- сопоставляет каждый drone-кадр с ближайшим кропом (**positive**) и соседями по сетке (**semi-positive**) +- генерирует индексы в формате, совместимом с **UAV-GeoLoc** (`Index/train_query.txt`, `Index/*_db.txt`) + +## Входные данные + +Ожидаемая структура сырого датасета (`--src`): ``` -UAV_VisLoc_dataset/ UAV_VisLoc_processed/ -├── 01/ ├── 01/ -│ ├── drone/*.JPG (3976x2652) ---> │ ├── drone/*.JPG (512x512) -│ ├── satellite01.tif ---> │ ├── DB/img/crop_X_Y.png (512x512) -│ └── 01.csv │ ├── DB/db_postion.txt -│ │ ├── positive.json -├── ... │ └── semi_positive.json -├── 09/ ├── ... -│ ├── satellite09_01-01.tif --+ ├── 09/ (stitched from 4 tiles) -│ ├── satellite09_01-02.tif +--> │ ├── DB/img/ (~22K crops) -│ ├── satellite09_02-01.tif | │ └── ... -│ └── satellite09_02-02.tif --+ │ -├── satellite_ coordinates_range.csv └── Index/ -├── visloc_train.csv ├── train_query.txt -└── visloc_test.csv ├── test_query.txt - ├── train_db.txt - ├── test_db.txt - └── all_db.txt +UAV_VisLoc_dataset/ +├── 01/ +│ ├── drone/*.JPG +│ ├── satellite01.tif +│ └── 01.csv +├── ... +├── 09/ +│ ├── satellite09_01-01.tif +│ ├── satellite09_01-02.tif +│ ├── satellite09_02-01.tif +│ ├── satellite09_02-02.tif +│ ├── drone/*.JPG +│ └── 09.csv +├── satellite_ coordinates_range.csv +├── visloc_train.csv +└── visloc_test.csv ``` -## Quick Start +Примечания: +- Маршрут **07** исключён (спутниковая карта 3000×170 — невозможно нарезать 512×512). +- Для маршрута **09** спутник хранится 4 тайлами и автоматически сшивается в один большой image. + +## Выходные данные + +Структура обработанного датасета (`--dst`): + +``` +UAV_VisLoc_processed/ +├── 01/ +│ ├── drone/*.JPG +│ ├── DB/ +│ │ ├── img/crop_X_Y.png +│ │ └── db_postion.txt +│ ├── positive.json +│ └── semi_positive.json +├── ... +└── Index/ + ├── train_query.txt + ├── test_query.txt + ├── train_db.txt + ├── test_db.txt + ├── all_db.txt + ├── train.txt + └── test.txt +``` + +## Установка + +Python 3.10+. + +```bash +python -m pip install -U pip +python -m pip install numpy pillow +``` + +## Запуск + +Минимальный пример: ```bash python scripts/prepare_dataset.py \ - --src /path/to/UAV_VisLoc_dataset \ - --dst /path/to/UAV_VisLoc_processed \ - --crop-size 512 --stride 256 --target-size 256 + --src "/path/to/UAV_VisLoc_dataset" \ + --dst "/path/to/UAV_VisLoc_processed" ``` -To process specific routes only: +Рекомендованные параметры (частый пресет): +- `--crop-size 512` +- `--stride 256` (50% overlap) +- `--target-size 512` (если хотите хранить 512×512 **на диске**; иначе по умолчанию будет 256×256) + ```bash -python scripts/prepare_dataset.py --src ... --dst ... --routes 01 02 03 +python scripts/prepare_dataset.py \ + --src "/path/to/UAV_VisLoc_dataset" \ + --dst "/path/to/UAV_VisLoc_processed" \ + --crop-size 512 \ + --stride 256 \ + --target-size 512 ``` -## Steps +Обработать только выбранные маршруты: -1. **Resize drone images** -> 512x512 JPEG (quality=95) -2. **Stitch satellite tiles** for route 09 (4 tiles -> 44800x33280) -3. **Crop satellite maps** -> 512x512 patches, stride 256 (50% overlap), saved as 512x512 PNG -4. **Compute GPS** for each crop center from satellite bbox + grid position -5. **Match drone -> crops** via vectorized haversine (positive = closest, semi-positive = +-1 in grid) -6. **Write metadata**: positive.json, semi_positive.json, db_postion.txt (per route) -7. **Generate Index files**: train_query.txt, test_query.txt, train_db.txt, test_db.txt, all_db.txt - -## Output Format (UAV-GeoLoc compatible) - -### Index files - -**train_query.txt / test_query.txt:** +```bash +python scripts/prepare_dataset.py \ + --src "/path/to/UAV_VisLoc_dataset" \ + --dst "/path/to/UAV_VisLoc_processed" \ + --routes 01 02 03 ``` -01/drone/01_0001.JPG 0 01/DB/img/crop_5_18.png 01/DB/img/crop_4_17.png ... -``` -Format: `query_path label positive_crop semi_positive_crops...` -**train_db.txt / test_db.txt / all_db.txt:** +## Что делает скрипт (по шагам) + +1. **Читает метаданные** + - `satellite_ coordinates_range.csv`: GPS bbox спутниковых карт по маршрутам + - `{route}/{route}.csv`: GPS drone-кадров + - `visloc_train.csv` / `visloc_test.csv`: train/test split по именам файлов +2. **Ресайзит drone изображения** в `{route}/drone/*.JPG` до `--target-size × --target-size` +3. **Загружает спутниковую карту** (`route 09` — сшивка 4 тайлов) +4. **Нарезает спутник на кропы** `--crop-size × --crop-size` со `--stride`, сохраняет в `{route}/DB/img/` как PNG, затем **ресайзит** кроп до `--target-size` +5. **Считает GPS для центра каждого кропа** (линейная интерполяция внутри bbox) +6. **Матчит drone→crop** + - `positive`: ближайший кроп по haversine distance + - `semi-positive`: соседи `±1` по grid (до 8 штук, если не на границе карты) +7. **Пишет метаданные и индексы** в стиле UAV-GeoLoc + +## Форматы файлов + +### `Index/train_query.txt` и `Index/test_query.txt` + +Одна строка = один drone query: + +``` +01/drone/01_0001.JPG 0 01/DB/img/crop_5_18.png 01/DB/img/crop_4_17.png 01/DB/img/crop_4_18.png ... +``` + +Формат: +- `query_path label pos1 pos2 ...` +- `label` в этом проекте всегда `0` (как в исходных датасетах UAV-GeoLoc; дальше лоссы обычно не используют это поле) +- первый путь после label — **positive** (ближайший), остальные — **semi-positive** (соседи в сетке) + +### `Index/*_db.txt` и `Index/all_db.txt` + +Галерея (DB) — список всех спутниковых кропов: + ``` 01/DB/img/crop_0_0.png 01/DB/img/crop_0_1.png ... ``` -Full gallery (all 74,807 crops), identical for train and test (split is by query). -### Per-route metadata +Важное: gallery одинаковая для train/test, split идёт по **queries**. + +### `{route}/positive.json` + +Ключ = frame id без префикса маршрута (`01_0001.JPG` → `"0001"`): -**positive.json:** ```json -{"0001": ["crop_5_18.png"], "0002": ["crop_5_19.png"], ...} +{ + "0001": ["crop_5_18.png"], + "0002": ["crop_5_19.png"] +} ``` -Keys are frame IDs (without route prefix). -**semi_positive.json:** +### `{route}/semi_positive.json` + +До 8 соседей в сетке вокруг positive: + ```json -{"0001": ["crop_4_17.png", "crop_4_18.png", ...], ...} +{ + "0001": ["crop_4_17.png", "crop_4_18.png"], + "0002": ["crop_4_18.png", "crop_4_19.png"] +} ``` -8 neighbors (+-1 in grid) of the positive crop. -**db_postion.txt** (tab-separated, matching UAV-GeoLoc spelling): +### `{route}/DB/db_postion.txt` + +Tab-separated, совместимо с UAV-GeoLoc (орфография `postion` сохранена намеренно): + ``` crop_0_0.png 115.97197337 29.77349180 2.68e-06 -2.68e-06 ``` -Columns: name, longitude, latitude, scale_lon (deg/px), scale_lat (deg/px). -## Dataset Statistics +Колонки: +- `name` +- `longitude` +- `latitude` +- `scale_lon` (deg/px) +- `scale_lat` (deg/px) -| Route | Drone | Crops | Region | Satellite (px) | -|-------|-------|-------|--------|----------------| -| 01 | 817 | 3,811 | Changjiang | 9774x26762 | -| 02 | 1,071 | 5,676 | Changjiang | 11482x34291 | -| 03 | 768 | 12,648 | Taizhou | 35092x24308 | -| 04 | 738 | 10,281 | Taizhou | 18093x38408 | -| 05 | 473 | 805 | Yunnan | 9394x6144 | -| 06 | 344 | 1,110 | Zhuxi | 8082x9780 | -| 07 | -- | -- | Excluded | 3000x170 (too narrow) | -| 08 | 1,033 | 10,416 | Huzhou | 43421x16294 | -| 09 | 766 | 22,446 | Huzhou | 44800x33280 (stitched) | -| 10 | 144 | 432 | Huailai | 6593x5077 | -| 11 | 590 | 7,182 | Shandan | 29592x16582 | -| **Total** | **6,744** | **74,807** | | | +## Про negatives / positives -Split: 5,060 train / 1,684 test queries. Gallery: 74,807 crops (shared). -Disk size: **25 GB**. +Отдельного списка negative нет: **negatives = все кропы gallery, которые не вошли в список positive+semi-positive** для данного query. -## Image Resolution +## Известные ограничения и качество матчингa -All images stored at **512x512** on disk: -- Drone: resized from 3976x2652 / 3000x2000 -> 512x512 -- Satellite crops: cut at 512x512 from satellite map, no downscale +- **Route 07** исключён (слишком узкая спутниковая карта). +- Встречается кейс, когда часть drone кадров может оказаться далеко от спутникового покрытия (в исходном датасете). +- `--target-size` влияет на то, какое разрешение хранится на диске; для обучения многие пайплайны всё равно делают финальный ресайз/кроп/аугментации уже в dataloader’е. -Resolution 512 chosen to support downstream tasks (segmentation, depth, normals, canopy height). -Resize to 224/256 for model input should be done in the dataloader, not on disk. +## Память -## GPS Matching Quality - -- Median distance drone -> positive crop: **25.9m** -- P99: **45.7m** -- Known issue: 6 drones in route 06 (06_0093-06_0098) are outside satellite coverage (~1,091m to nearest crop) - -## Satellite Resolution - -All maps: ~0.30 m/pixel (single Google Earth zoom level). -One crop 512x512 covers ~154x154m on the ground. - -## Requirements - -``` -numpy -Pillow -``` - -## Memory - -Peak RAM usage: ~8.7 GB (route 09 stitching: 4 tiles + merged image). -Other routes: 1-3 GB. +Маршрут 09 (сшивка тайлов) — самый тяжёлый по RAM; остальные маршруты существенно легче. +Если не хватает памяти, можно прогонять маршруты по одному через `--routes`.