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 <cursoragent@cursor.com>
This commit is contained in:
2026-05-09 11:50:35 +03:00
committed by pikaliov
parent cf455cd0f3
commit ec7d294605

257
README.md
View File

@@ -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`.