edit | blame | history | raw

轨迹分析与行为识别

状态:首个 CPU Demo 已验证(2026-08-14)。

能力边界

当前 Demo 归为 C(产品业务能力),不是 geoai-py 内置功能:

  • 产品实现用 GeoPandas、Shapely、PyProj 和 scikit-learn 完成轨迹度量、空间关系计算、DBSCAN 分组和规则判断。仅使用这些生态库、但没有实际调用 geoai-py,不能标为 B。
  • geoai-py 的准确角色是上游来源之一:其目标检测和地理结果导出可为跟踪系统提供观测,但 geoai-py 0.42.0 没有轨迹、目标跟踪或行为识别 API。本 Demo 运行时因此不安装或调用 geoai-py

未来若把 geoai-py 检测/导出、独立多目标跟踪器和本规则服务连成完整流水线,流水线可同时包含 A、B、C;当前已实现并验证的部分仍是 C。

首版所称“行为识别”是可解释的时空规则,不是视频动作识别模型,也不负责把逐帧检测框关联成轨迹 ID。

Demo 契约

输入是一个 *.case.json 清单,引用三类真实业务可导出的文件:

  1. 轨迹点 CSV:固定字段 track_id,entity_type,timestamp,longitude,latitude
  2. 参考路线 GeoJSON:每条 LineStringtrack_id
  3. 区域 GeoJSON:每个面带 zone_idzone_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 数据 由本仓库脚本生成,无第三方数据集或模型权重
预训练模型/权重

以上是开发阶段记录,不等于已完成产品商用法务审查。

真实单例:田墩飞行任务 19578

用户提供的原始 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 叠加天地图影像和注记。

已知限制与下一步

  • 2026-08-14 已归档一组用户提供的田墩真实原始资料至 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 标签直接等同为已验证的禁入事件。
  • 合成样本只能验证程序逻辑,不能证明真实场景准确率;目前没有可报告的真实误报率和漏报率。
  • 聚集要求时间戳对齐,GPS 漂移、采样频率和轨迹断点会直接影响结果。
  • 偏航依赖可信参考路线;禁入区依赖有效区域数据;不同人员、车辆、船舶和无人机需要分别标定阈值。
  • 下一步应先选 1 个正常、1 个困难的脱敏实测轨迹,人工标注事件,再评估误报、漏报和阈值,而不是直接跑大目录。
  • 若输入来自无人机视频,还需在此能力之前引入独立的多目标跟踪器,并验证 ID 切换问题。

    控制台输入转换

本地实验控制台支持直接上传用户常见的 XLSX 飞行日志、KMZ DJI WPMZ 航线、禁飞区 GeoJSON,以及可选适飞区 Gzip。服务端会在固定的轨迹虚拟环境中调用 prepare_real_flight.pyrun_trajectory_analysis.py,把文件转换成 Demo 的 case.json、WGS84 轨迹和 GeoJSON 输出。适飞区缺省时仍可分析,地图只是不显示适飞区图层。

每次运行使用新的 trajectory-<UTC时间>-<随机串> 编号,原始输入不会被覆盖;控制台案例库会自动扫描 shared/outputs/15-trajectory-analysis,行为标签在界面显示中文释义,结构化文件继续保存英文键值,便于程序处理。