146 lines
8.6 KiB
Markdown
146 lines
8.6 KiB
Markdown
# SandCastle
|
||
|
||
Инструмент для массового захвата Google Photorealistic 3D Tiles в формате датасета **UAV-GeoLoc**. Через Cesium снимает ортофото-кропы сцены (DB) и «дроновые» кадры (query) по сетке, формирует JSON траектории камеры и сохраняет всё в дерево папок, совместимое с UAV-GeoLoc.
|
||
|
||
## Быстрый старт
|
||
|
||
1. Установите Node.js 14+.
|
||
2. Запустите `start.bat`:
|
||
- `start.bat` — запуск на порту `3000`
|
||
- `start.bat 3001` — запуск на указанном порту
|
||
3. Откройте `http://localhost:<порт>` если браузер не открылся сам.
|
||
|
||
## Рабочий процесс
|
||
|
||
1. **Панель управления** ([index.html](index.html)) — задайте имена сцены и параметры:
|
||
- `Dataset / Country / City / Region` — 4 уровня дерева в `output/`
|
||
- `Точка 1 / Точка 2` — противоположные углы прямоугольника в формате DMS
|
||
- `Шаг сетки (метры)` — размер одного тайла
|
||
- `Прореживание` — 1 = все точки, 2 = каждая вторая
|
||
- `DB crop sizes` — ровно 11 уникальных размеров PNG-кропов (через запятую)
|
||
- `Разрешение query кадра` — размер итогового JPEG (по умолчанию 512)
|
||
- `FOV вертикальный` — параметр съёмки query-камеры
|
||
- `Pitch query` — фиксирован в `-90` (top-down)
|
||
- `Высоты (3 слота)` — чекбоксы + редактируемые значения высот
|
||
- `Абсолютная высота` — выкл = над рельефом
|
||
- `Предзагрузка тайлов` — прогрев Cesium перед съёмкой
|
||
- `Пропускать пустые зоны` — не сохранять области без 3D-контента
|
||
2. **Сохранить настройки** → `settings.json`.
|
||
3. **Создать папки** → дерево сцены и `{region}.txt` с углами прямоугольника.
|
||
4. **Запустить захват** — откроется два окна:
|
||
- **Карта зоны** ([mapview.html](mapview.html)) — чистый canvas без внешних тайлов, красный прямоугольник зоны, синие точки тайлов, жёлтая активная точка, зелёный след пройденного
|
||
- **Окно захвата** ([capture.html](capture.html)) — Cesium Viewer, прогресс и лог
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
SandCastle/
|
||
├── start.bat Запуск (проверяет Node, принимает порт, стартует сервер)
|
||
├── package.json
|
||
├── server.js Express backend + API
|
||
├── index.html Панель управления
|
||
├── ui.js UI-контроллер панели
|
||
├── style.css
|
||
├── capture.html Окно захвата (Cesium)
|
||
├── mapview.html Окно карты (canvas, без внешних тайлов)
|
||
├── settings.json Последние настройки (создаётся автоматически)
|
||
└── output/ Результаты (создаётся автоматически)
|
||
└── {dataset}/{country}/{city}/{region}/
|
||
├── {region}.txt Углы зоны: maxLat minLon / minLat maxLon
|
||
├── DB/
|
||
│ ├── merge.tif Базовый TIFF сцены (для внешней нарезки)
|
||
│ ├── db_postion.txt Строки: filename lon lat res_x res_y
|
||
│ └── img/
|
||
│ └── crop_{col}_{row}_{size}.png Ортофото по сетке (X=col, Y=row, size=px)
|
||
├── positive.json Соответствия query -> точный DB crop
|
||
├── semi_positive.json Соответствия query -> соседние DB crop
|
||
└── query/
|
||
└── height{H}_rot{R}/
|
||
├── height{H}_rot{R}.json Траектория камеры
|
||
└── footage/
|
||
└── height{H}_rot{R}_{NN}.jpeg Дроновые кадры
|
||
```
|
||
|
||
## Формат траектории (UAV-GeoLoc)
|
||
|
||
`query/height100_rot0/height100_rot0.json`:
|
||
|
||
```json
|
||
{
|
||
"name": "height100_rot0",
|
||
"width": 512,
|
||
"height": 512,
|
||
"frameRate": 30,
|
||
"numFrames": 75,
|
||
"durationSeconds": 2.5,
|
||
"cameraFrames": [
|
||
{
|
||
"position": { "x": 3843512.1, "y": 604821.7, "z": 5095123.4 },
|
||
"rotation": { "x": -60, "y": 0, "z": 0 },
|
||
"coordinate": { "latitude": 52.41, "longitude": 9.65, "altitude": 100 },
|
||
"fovVertical": 30
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
`numFrames` и `durationSeconds` вычисляются автоматически по фактическому числу сохранённых кадров.
|
||
|
||
- `position` — ECEF (Earth-Centered Earth-Fixed) в метрах, получено через `Cesium.Cartesian3.fromDegrees`
|
||
- `rotation` — `x` = pitch, `y` = heading (yaw), `z` = roll, все в градусах (pitch задаётся в UI)
|
||
- `coordinate` — геодезические координаты точки съёмки
|
||
- `fovVertical` — вертикальный FOV камеры Cesium в градусах (задаётся в UI)
|
||
|
||
## API сервера
|
||
|
||
| Метод | Путь | Назначение |
|
||
|---|---|---|
|
||
| GET | `/api/get-settings` | Текущие настройки (или дефолты) |
|
||
| POST | `/api/save-settings` | Сохранить настройки в `settings.json` |
|
||
| POST | `/api/create-folders` | Создать дерево сцены и `{region}.txt` |
|
||
| POST | `/api/start-capture` | Сохранить настройки и вернуть URL `capture.html` |
|
||
| POST | `/api/save-db-crop` | Сохранить `crop_{col}_{row}_{size}.png` + строку в `db_postion.txt` |
|
||
| POST | `/api/save-merge-tif` | Сохранить `DB/merge.tif` |
|
||
| POST | `/api/save-drone-frame`| Сохранить кадр `height{H}_rot{R}_{NN}.jpeg` |
|
||
| POST | `/api/save-trajectory` | Сохранить `height{H}_rot{R}.json` |
|
||
| POST | `/api/save-annotations` | Сохранить `positive.json` и `semi_positive.json` |
|
||
|
||
## Координаты DMS
|
||
|
||
Формат: `52°25'10.28"N 9°39'10.04"E`. Точки 1 и 2 — противоположные углы прямоугольника; их порядок не важен, сервер сам вычисляет `minLat/maxLat/minLon/maxLon`.
|
||
|
||
## Параметры съёмки (актуально)
|
||
|
||
- `DB crop sizes` — обязательный список из **11 уникальных** положительных размеров (px)
|
||
- стандартная кнопка в UI подставляет:
|
||
- `100,150,200,250,300,400,500,512,600,800,1000`
|
||
- для каждого тайла сохраняется 11 PNG-кропов:
|
||
- `crop_{col}_{row}_{size}.png`
|
||
- `Query`:
|
||
- `drone_size` — размер JPEG кадра
|
||
- `query_fov_deg` — вертикальный FOV
|
||
- `query_pitch_deg` — зафиксирован на `-90` (top-down)
|
||
- высоты query задаются тремя редактируемыми слотами (`height_100_value`, `height_125_value`, `height_150_value`) и включаются соответствующими чекбоксами
|
||
- при завершении захвата сохраняются:
|
||
- `DB/merge.tif`
|
||
- `positive.json`
|
||
- `semi_positive.json`
|
||
|
||
## Обмен окнами
|
||
|
||
`capture.html` ↔ `mapview.html` общаются через `BroadcastChannel('sandcastle-map')`. Сообщения:
|
||
- `{type: 'init', bounds, tiles}` — одноразово после генерации сетки
|
||
- `{type: 'position', index, total, lat, lon}` — перед съёмкой каждого тайла
|
||
- `{type: 'done', total}` — по завершении
|
||
- `{type: 'request-init'}` — карта запрашивает реплей при позднем открытии
|
||
|
||
## Требования
|
||
|
||
- Node.js 14+
|
||
- Cesium Ion token (Google Photorealistic 3D Tiles, asset `2275207`) — вшит в `capture.html`
|
||
- Интернет для Cesium CDN и Google 3D Tiles (карта зоны работает офлайн)
|
||
|
||
## Версия
|
||
|
||
1.0.0 — Мороз Е.С. Павленко Б. В. / ЛИСАД
|