状态:首个 CPU Demo 已验证(2026-08-14)。
当前 Demo 归为 C(产品业务能力),不是 geoai-py 内置功能:
geoai-py,不能标为 B。geoai-py 的准确角色是上游来源之一:其目标检测和地理结果导出可为跟踪系统提供观测,但 geoai-py 0.42.0 没有轨迹、目标跟踪或行为识别 API。本 Demo 运行时因此不安装或调用 geoai-py。未来若把 geoai-py 检测/导出、独立多目标跟踪器和本规则服务连成完整流水线,流水线可同时包含 A、B、C;当前已实现并验证的部分仍是 C。
首版所称“行为识别”是可解释的时空规则,不是视频动作识别模型,也不负责把逐帧检测框关联成轨迹 ID。
输入是一个 *.case.json 清单,引用三类真实业务可导出的文件:
track_id,entity_type,timestamp,longitude,latitude。LineString 带 track_id。zone_id 和 zone_type;首版识别 restricted。首版只接受带有效 CRS 的 WGS84 经纬度(EPSG:4326)。每条轨迹至少需要两个不同时间戳;同一轨迹的重复时间戳保留最后一条并在元数据中计数。
仓库没有用户实测轨迹,因此 generate_demo_inputs.py 会生成两组小型、可审计的合成代表样本:
normal:2 条连续移动且贴合参考路线的轨迹,预期无事件。difficult:3 条乱序轨迹,含 1 条重复观测,以及可人工核对的停留、偏航、禁入区和双人聚集。生成数据位于 shared/data/raw/15-trajectory-analysis/,不会提交 Git。真实验证仍需用户提供同结构的脱敏轨迹。
# Python 3.12 隔离环境
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1 -Capability 15-trajectory-analysis
$py = '.\.venvs\15-trajectory-analysis\Scripts\python.exe'
# 第一次生成验收输入
& $py .\capabilities\15-trajectory-analysis\generate_demo_inputs.py
# 分析目录内的 normal.case.json 和 difficult.case.json
& $py .\capabilities\15-trajectory-analysis\run_trajectory_analysis.py
# 只分析一个用户清单;输出仍放在 <output>/<case_id>/
& $py .\capabilities\15-trajectory-analysis\run_trajectory_analysis.py `
--input .\path\to\my.case.json `
--output .\shared\outputs\15-trajectory-analysis\my-run
脚本默认拒绝覆盖已有输入和结果。只有明确要替换此前运行时才传 --overwrite。
默认规则:
| 事件 | 条件 |
|---|---|
停留 stop |
速度不高于 0.8 m/s,持续至少 60 秒 |
偏航 route_deviation |
到参考路线距离大于 25 m,持续至少 20 秒 |
禁入区 restricted_zone |
轨迹点落入 restricted 面 |
聚集 gathering |
至少 2 条轨迹在 20 m 内,持续至少 30 秒 |
清单可用 thresholds 对象覆盖上述阈值。相邻观测超过 60 秒时事件连续段会断开,避免把长时间数据缺失误算为持续行为。
每个案例固定输出:
| 文件 | 内容 |
|---|---|
trajectory_summary.csv |
每条轨迹的时间、距离、速度、偏航比例、停留/禁入时长、聚类 ID 和行为标签 |
events.json |
固定事件字段、参与轨迹、起止时间、位置和规则细节 |
trajectories.geojson |
WGS84 轨迹线及汇总属性 |
events.geojson |
WGS84 事件点及事件属性 |
analysis.png |
轨迹、参考路线、区域和不同形状事件标记 |
run_metadata.json |
Python/依赖版本、规则/模型、阈值、CPU、输入数、耗时、清洗数和限制 |
DBSCAN 只对轨迹汇总特征做探索性分组;cluster_id=-1 表示没有足够相似轨迹形成簇,不代表异常已被确认。
运行环境:Python 3.12.10、CPU;pip check 通过。目录级运行处理 2 个案例、5 条轨迹和 78 条去重后观测,总耗时约 2.8 秒。
| 验收项 | 预期 | 实测 |
|---|---|---|
| 正常样本 | 2 条轨迹,0 个事件 | 通过:2 条轨迹,0 个事件 |
| 困难样本清洗 | 乱序可排序,删除 1 条重复时间观测 | 通过:删除 1 条 |
| 困难样本行为 | 四类事件各至少 1 个 | 通过:停留、偏航、禁入区、聚集各 1 个 |
| 失败处理 | 缺少必填 CSV 字段时退出码为 2,并指出字段 | 通过 |
| 输出完整性 | 每个案例生成 6 个非空文件 | 通过 |
| 视觉检查 | 正常/困难 PNG 非空,轨迹、区域和事件可区分 | 通过;两张图均为 1400 x 980 |
自动验收:
$py = '.\.venvs\15-trajectory-analysis\Scripts\python.exe'
& $py -m unittest discover -s .\capabilities\15-trajectory-analysis\tests -v
| 项目 | 当前记录 |
|---|---|
geoai-py 0.42.0 |
MIT;仅为可选上游,本 Demo 环境未安装 |
| pandas / GeoPandas / Shapely / scikit-learn | BSD 3-Clause 系列许可证 |
| PyProj | MIT;同时需遵守其随附 PROJ 数据/组件许可 |
| Matplotlib | Matplotlib License;随附字体等资产有各自许可证 |
| openpyxl 3.1.5 | MIT;仅用于读取用户提供的 XLSX 飞行日志 |
| Demo 数据 | 由本仓库脚本生成,无第三方数据集或模型权重 |
| 预训练模型/权重 | 无 |
以上是开发阶段记录,不等于已完成产品商用法务审查。
用户提供的原始 XLSX、DJI WPMZ KMZ 和禁飞区 GeoJSON 保持在 shared/data/raw/15-trajectory-analysis/tian-dun-demo-20260814/,不会被脚本改写。使用以下命令生成可审计的处理输入,再运行单例分析:
$py = '.\.venvs\15-trajectory-analysis\Scripts\python.exe'
& $py .\capabilities\15-trajectory-analysis\prepare_real_flight.py
& $py .\capabilities\15-trajectory-analysis\run_trajectory_analysis.py `
--input .\shared\data\processed\15-trajectory-analysis\tian-dun-flight-19578\tian-dun-flight-19578.case.json `
--output .\shared\outputs\15-trajectory-analysis\tian-dun-flight-19578
预处理器会将 Excel 的本地无时区时间按 Asia/Shanghai 解释后转换为 UTC,提取 waylines.wpml 中的 10 个 WGS84 航点,并从 2,300 个禁飞区源要素中按飞行/航线周边 5 km 筛选、合并为一个局部区域。点状区域按原始 radius 转为米制缓冲区;源数据的 no-fly 被映射为规则输入 restricted,只用于技术空间评估。适飞区 Gzip 已验证为 46,518 个闭合坐标环的 int32 / 1e7 流,田墩周边筛出 2 个适飞面;它只用于可视化,不参与禁入规则判定。
已验证的真实单例有 233 个观测点、1 条无人机轨迹,运行耗时 0.338 秒。输出报告 2 段偏航(77 秒、175 秒)和 1 个持续 464 秒的区域相交事件;没有停留或聚集事件。实飞点到计划线的最小/平均/最大距离为 0.0 / 221.0 / 540.8 m。两段偏航分别覆盖起飞接近计划线之前和自动返航/降落阶段,计划航线未表达这些飞行阶段,因此不能直接将其作为异常结论。区域相交仅代表与名为“三清山”的源区域(no-fly-40001494)发生空间相交,不是法规或运营违规认定。
处理输入位于 shared/data/processed/15-trajectory-analysis/tian-dun-flight-19578/;结果位于 shared/outputs/15-trajectory-analysis/tian-dun-flight-19578/tian-dun-flight-19578/,包括轨迹、计划航线、禁飞区、适飞区和事件 GeoJSON,以及 analysis.png。本地控制台的“田墩实飞”案例可直接查看这些结果;地图以 ArcGIS 影像为底图,并可在 apps/workbench-console/.env.local 配置 VITE_TIANDITU_TOKEN 叠加天地图影像和注记。
shared/data/raw/15-trajectory-analysis/tian-dun-demo-20260814/:禁飞区 GeoJSON、适飞区 Gzip 二进制源文件、DJI WPMZ 航线 KMZ 与实际飞行 Excel。原文件保持未改名、未转换状态,当前尚未纳入分析结果。prepare_real_flight.py 已支持此批 XLSX、KMZ、禁飞 GeoJSON 与适飞区 Gzip 的单例准备。适飞区的二进制几何已验证为闭合坐标环,但其发布日期、授权方和运营语义仍未独立核验,当前只用于可视化,不参与规则判断。当前区域规则只识别 zone_type=restricted,不能把 no_fly 标签直接等同为已验证的禁入事件。若输入来自无人机视频,还需在此能力之前引入独立的多目标跟踪器,并验证 ID 切换问题。
本地实验控制台支持直接上传用户常见的 XLSX 飞行日志、KMZ DJI WPMZ 航线、禁飞区 GeoJSON,以及可选适飞区 Gzip。服务端会在固定的轨迹虚拟环境中调用 prepare_real_flight.py 和 run_trajectory_analysis.py,把文件转换成 Demo 的 case.json、WGS84 轨迹和 GeoJSON 输出。适飞区缺省时仍可分析,地图只是不显示适飞区图层。
每次运行使用新的 trajectory-<UTC时间>-<随机串> 编号,原始输入不会被覆盖;控制台案例库会自动扫描 shared/outputs/15-trajectory-analysis,行为标签在界面显示中文释义,结构化文件继续保存英文键值,便于程序处理。