Samukashvili/LaunchPoint
GitHub: Samukashvili/LaunchPoint
LaunchPoint 通过对多次无人机地面目击事件进行蒙特卡洛可视域交集运算,结合真实地形数据估算无人机操作员的位置并生成概率热力图。
Stars: 2 | Forks: 1
# LaunchPoint — 飞控原点查找器
[](LICENSE)

根据无人机的一次或多次地面位置目击事件,估算**无人机操作员所处的位置**。

*同一无人机的三次地面目击事件(图钉 1–3)被融合为操作员位置的概率面 —— 苏黎世示例,50% 置信区域 ≈ 12 km²。颜色越暖代表可能性越高。*
该方法基于一个简单的事实:**视线是互逆的。** 无人机能看到的所有地方,也是控制器能看到无人机的地方 —— 而且控制器必须保持(大致的)视线才能进行飞行操作。因此,LaunchPoint 在高保真度的高度表面上,对多次目击事件的*可见区域*进行交集运算,并根据真实的控制范围模型以及地形/树冠遮挡对其进行加权,最后通过 Monte Carlo 传播(巨大的)输入不确定性,从而生成操作员位置的**概率热力图**。
本仓库实现了项目路线图的 **Phase 0–6** 阶段:核心科学算法、性能优化以及首个交互式指挥中心工作台。
## 快速开始
### Windows(一键启动)
```
install_dependencies.bat
.venv\Scripts\activate
launchpoint demo --out demo_origin.tif
launchpoint ui
```
安装程序会自动寻找兼容的 Python(3.10–3.12),创建一个 `.venv`,并安装所有依赖。`demo` 完全在离线状态下基于合成场景运行,并会打印出还原出的峰值与预设控制器位置之间的距离。
### 任意平台(手动安装)
```
python -m venv .venv && . .venv/bin/activate # use a 3.10–3.12 interpreter
pip install -r requirements.txt
pip install -e .
pytest # 32 offline tests
launchpoint demo --out demo_origin.tif
```
### 基于真实目击数据运行
```
launchpoint run --sightings examples/sightings_zurich.json --out origin.tif
```
首次运行时,程序仅会获取您的区域所需的数据(Copernicus DSM,以及树冠和 OSM 建筑物),通过无密钥 HTTPS 连接进行下载,并将其缓存在 `data_cache/` 目录下,同时写入一份 GeoTIFF 概率栅格。所有数据源均无需账户或 API 密钥。
### 交互式工作台
```
launchpoint ui --host 127.0.0.1 --port 8765
```
在浏览器中打开 `http://127.0.0.1:8765`。工作台启动时会显示一张空白的操作地图。您可以直接在地图上添加目击记录,或者导入符合现有目击数据 schema 的 JSON/CSV 文件,然后运行分析,查看 2D 热力图、50% 置信区域、联动的 3D 地形视图、每次目击的贡献度、网格诊断以及导出内容。
2D 底图使用带有版权归属信息的 OpenStreetMap 公共切片。3D 地形视图会从 AWS Open Data Terrain Tiles 存储桶中解码无密钥的 Terrarium 高程 PNG 切片,并覆盖与 2D 视口和 PNG 预览相同的概率热力图调色板。GeoTIFF 导出功能由完整的后端概率栅格提供支持。

*联动的 3D 视图在无密钥的 Terrarium 高程切片上覆盖了相同的概率调色板 —— 在此示例中,高可能性的羽状区域顺着地形向湖泊方向延伸。*
## 覆盖范围规划器(逆向模式)
工作台还提供了第二种模式。**覆盖范围规划器(Coverage planner)** 不是从目击事件中*寻找*操作员,而是逆向运行几何计算:定义一个**飞行区域** —— 在无人机将要作业的空域绘制一个圆(圆心、半径、任务高度),然后 LaunchPoint 会根据每个候选地面地点在整个区域内保持控制范围视线的情况对其进行评分,从而得出**最佳起飞点**及其覆盖范围。它复用了原点查找器的 viewshed、曲率以及地形/树冠遮挡模型,只是将其应用方向反过来了:*你应该站在哪里才能覆盖这个区域?* 而不是*飞到这里来的操作员在哪里?*

## 工作原理
| 阶段 | 功能说明 |
|------|---------------|
| **0** | 核心数据结构(`Sighting`、`RasterGrid`),局部 UTM 投影规则,以及一个**合成验证套件** —— 包含完全已知的地形 + 预设的控制器 + 几何上可见的目击事件,从而为后续每个阶段提供客观的真实参考。 |
| **1** | **无密钥数据层。** 计算感兴趣的区域(目击位置 + 最大范围),然后读取 **Copernicus GLO-30 DSM** 的窗口化 Cloud-Optimized GeoTIFFs(HTTP range 请求),将其重投影/拼接为通用的 UTM 网格并进行缓存。 |
| **2** | **单观察者 viewshed。** 采用带有 **4/3 地球曲率 + 折射** 校正和**软范围模型**(平稳段 → 逻辑衰减,而非硬性限制)的径向扫描(R3)视线核心。由一个暴力破解预言机进行验证。 |
| **3** | **融合 + Monte Carlo。** 通过对每次目击事件的位置/高度不确定性进行 N 次采样,根据每个候选网格的可见性对其进行评分。默认情况下使用**严格最小值**(`combine="min"`)来合并目击事件 —— 网格的值由*最弱的*那次目击事件决定,因此如果有一架无人机无法看到某个位置,该位置的值就会降至约 0。这强制执行了单一发射点的假设:每架无人机都必须能从操作员的位置被看到。`combine="geometric_mean"` 提供了较温和的交集,而 `"arithmetic_mean"` 则是宽容的并集。 |
| **4** | **表面增强。** 将 OSM 建筑物高度和 **Meta/WRI 1 m 树冠** 数据融入画面中,并*推导出*裸地表面 `bare = DSM − canopy − building`(无需依赖 FABDEM,完全支持商业友好使用)。树冠数据还会作为软性因素降低发射可行性的权重。1 m 树冠数据**仅在 DSM 可达的覆盖区内**(见下文)获取,而非整个范围圆盘。 |
| **5** | **性能优化。** 粗粒度到细粒度:先在整个圆盘范围内进行成本较低的 30 m 粗略计算,然后**仅**在热门候选区域和每次目击点周围进行细粒度(1–2 m)的精细化计算。CUDA viewshed 核心(自动支持 CPU 回退)可加速精细计算过程。 |
### 几何约定
* 所有几何图形都会被重投影到**局部 UTM 带中**,这样 raycasting 的计算单位始终是米,绝不会是经纬度。
* **DSM 会遮挡**沿途的射线(它已经包含了树冠和屋顶)。**推导出的裸地表面**给出了*目标高度*:操作员站在裸地 + 天线高度(约 1.5 m)上,而不是树冠顶部或屋顶上。
* 观察者 = 处于其(采样)位置和高度的无人机。AGL 高度利用无人机下方的表面转换为绝对高度。
### 覆盖区门控的树冠获取
1 m 的 Meta/WRI 树冠是消耗带宽最大的层(其切片是全宽单行条带且没有概览图,因此对整个范围圆盘进行简单的窗口化读取可能会拉取约 1 GB 数据)。树冠仅在控制器实际可能站立的位置才有意义,因此 LaunchPoint 首先对每次目击事件运行低成本的**纯 DSM viewshed** 来寻找*可达覆盖区*,然后**仅在该覆盖区的边界框内**获取高分辨率的树冠数据。
至关重要的是,覆盖区的组合方式**与热力图的组合方式相同**。在默认严格的 `min` 模式下,一个可行的发射点必须能被*每一架*无人机看到,因此树冠数据仅在每次目击 viewshed 的**交集**内才需要 —— 而不是在它们的并集内。这是一个小得多的区域(即使在平坦的合成地形上也大约只有 AOI 的一半,在地形遮挡的地方则少得多),这正好符合驱动热力图的单一发射点假设。较温和的 `geometric_mean` / `arithmetic_mean` 模式会退回到使用并集,因为它们保留了仅被部分无人机到达的网格。
这种方式保持了数据无损:每个仅基于 DSM 的单次目击 viewshed 都是其真实树冠感知贡献的超集(树冠只会降低天线目标,从而缩小可见性),并且覆盖区还会将观察者的高度提升约 2σ 的海拔,并根据位置抖动进行了膨胀处理 —— 因此,在热力图可能为非零值的任何地方都会获取树冠数据,而在其不可能为非零值的地方则不会获取。
## 架构
```
src/launchpoint/
config.py # all tunables / physical constants (one place to cite)
core/ # Sighting, geo/UTM helpers, RasterGrid
viewshed/ # curvature, soft range model, R3 + oracle kernels, GPU
fusion/ # Monte-Carlo fusion, coarse-to-fine multiscale
data/ # keyless fetchers: Copernicus DSM, canopy, OSM buildings,
# derived bare earth, on-disk cache, surface stack
synthetic/ # the validation harness
pipeline.py # sightings in -> OriginEstimate out
ui/ # Phase 6 browser workspace and shared overlay renderer
cli.py # `launchpoint run` / `launchpoint demo` / `launchpoint ui`
tests/ # 32 offline tests + network-gated data tests
```
程序化使用方式:
```
from launchpoint import Sighting, find_origin
sightings = [Sighting(47.39, 8.55, altitude=110, position_sigma_m=200),
Sighting(47.38, 8.57, altitude=95, position_sigma_m=250)]
est = find_origin(sightings) # fetches keyless data for the AOI
print(est.argmax_lonlat()) # most-likely operator location
est.probability.write_geotiff("origin.tif") # full heatmap
```
## 数据源(全部免费,均无需密钥)
| 图层 | 来源 | 访问方式 | 许可证 |
|---|---|---|---|
| DSM(表面 / 遮挡) | Copernicus GLO-30 | `copernicus-dem-30m` S3 / HTTPS,匿名访问 | 开放 |
| 树冠高度(1 m) | Meta / WRI Global Canopy Height | `dataforgood-fb-data` S3 / HTTPS,匿名访问 | 免费(包含商业用途) |
| 建筑物 | OpenStreetMap (Overpass API) | 无密钥 HTTP | ODbL |
| 裸地 | **推导得出** = DSM − 树冠 − 建筑物 | 内部计算 | 继承上述来源 |
未使用任何 Google Earth Engine 路径(因其需要账户)。未获取任何 FABDEM 数据(而是直接推导裸地),这使得每一项输入都能支持商业友好。
### 获取方式:并行 + 可观察
远程 COG 切片(DSM、树冠)通过一个小型线程池进行**并发**拉取 —— 每个工作线程持有自己的 GDAL 句柄,并且切片会按其原始顺序组合回来,因此结果与串行拼接完全相同,只是速度更快。共享的、速率受限的 Overpass 建筑物 API 保持为单一的顺序请求。
每次获取操作都会通过 `launchpoint.data` 日志记录器记录到终端(`run.bat` 打开的窗口)中:包括哪个图层、逐切片的时间、可能的拉取字节数以及每个图层的总计数据 —— 这样就能清楚地看到哪个环节慢或体积大。UI 会将这些相同的事件转化为运行进度条上的实时下载百分比。在 CLI 中加上 `--verbose` 参数可获取 debug 级别的详细信息。
## 测试
```
pytest # offline: synthetic recovery, R3-vs-oracle, fusion, ...
pytest -m network # also hit the live keyless endpoints (DSM/canopy/OSM)
```
核心测试(`tests/test_recovery.py`)断言 pipeline 能够还原出预设的合成控制器,并且**能够优雅降级** —— 随着输入不确定性的增加,置信区域会变得*更大*,而不是变得*错误*。
## 局限性 / 误差预算
* **具有概率性,而非精确确定。** 热力图是一个似然面;其峰值可能会偏离几百米到几公里不等,特别是在目击记录很少或无人机高度很高的情况下(高空无人机在很大范围内都可见,因此它对操作员的约束非常有限)。
* DSM 的**基础分辨率为 30 m** —— 虽然与单次快照中几百米的位置不确定性相匹配,但这已经是粗略计算阶段细节的下限了。
* **推导出的裸地比 FABDEM 经过验证的 ML 模型更为粗糙**,特别是在复杂地形中;它只是简单直接的 `DSM − 树冠 − 建筑物` 减法。
* **软范围,软树冠。** 控制范围和起飞可行性只是一种*趋势*,而非绝对的规则 —— 操作员确实也会站在森林边缘和空地上。
* **建筑物数据依赖于 OSM 的覆盖范围**;在人烟稀少的地区,其遮挡效果会被低估(Microsoft / Google 开放建筑物数据的补缺已作为可选的扩展功能被接入)。
## 状态
Phase 0–6 已实现并经过测试。Phase 7(发布完善阶段)将随后进行。
## 许可证
代码采用 MIT 许可证(详见 `LICENSE`)。数据层保留其各自的许可证;请注意,OpenStreetMap 的 **ODbL** 相同方式共享条款适用于任何重新分发的提取内容。
标签:Python, Vectored Exception Handling, 地理信息系统, 实时处理, 无人机追踪, 无后门, 蒙特卡洛方法, 视线分析, 逆向工具