Files

9.1 KiB
Raw Permalink Blame History

本地模块与事件合约

Silver Pose 没有后端 API;本文定义 V1/V2 必须保持一致的本地配置、数据和事件合约。

配置合约

v1/config.example.json 的最小形状:

{
  "source": {
    "id": "lobby-camera-01",
    "rtsp_url_env": "SILVER_POSE_RTSP_URL",
    "mode": "stream",
    "roi_normalized": [0.0, 0.0, 1.0, 1.0]
  },
  "model": {
    "path": "models/best.pt",
    "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
    "confidence_threshold": 0.25
  },
  "event": {
    "keypoint_confidence_threshold": 0.4,
    "suspect_window_seconds": 0.5,
    "confirm_window_seconds": 1.0,
    "recovery_window_seconds": 2.0,
    "cooldown_seconds": 10.0
  },
  "artifacts": {
    "event_dir": "../artifacts/events"
  }
}
  • 来源二选一:rtsp_url_env(从同名环境变量读取真实 URL)或结构化字段 host/port(默认 554)/channel(默认 101,102 为子码流)/username/password;两者都会在内存中解析出 RTSP URL。结构化凭证只允许出现在未跟踪的 config.local.json;公开示例 config.example.json 只能用 rtsp_url_env,禁止任何 host/username/password/完整 URL(有测试守卫)。
  • 结构化模式下应用用 build_rtsp_url 拼接,并对用户名/密码做 RFC 3986 百分号编码,因此密码含 @、:、/ 也不会破坏 URL 解析。
  • source.mode 显式声明来源类型,取值 stream(默认,实时 RTSP,允许有界重连)或 replay(本地录像,EOF 不重放);由配置决定,不再按 URL 前缀猜测。
  • 抓流低延迟调优(非凭证,可进公开示例):source.transport(tcp 默认 / udp)、source.timeout_seconds(默认 5)、source.low_latency(默认 true)。应用用 build_ffmpeg_options 拼成 OPENCV_FFMPEG_CAPTURE_OPTIONS,并在打开流之前写入 os.environ(OpenCV 在打开时读取该环境变量);因此无需再靠外部脚本设置该变量。
  • 凭证(host/username/password/解析出的 URL)绝不进入 runtime_config_version、事件 JSONL、日志或截图文件名。
  • model.confidence_threshold 是模型检测置信度,可在设置草稿中调整,并在下次开始监控时经 PoseAdapter.set_confidence_threshold 真正生效。
  • 数值是待现场录像校准的默认值;每个值必须真正进入事件逻辑:keypoint_confidence_threshold 决定姿态质量门槛;suspect_window_seconds 限制快速下移到水平姿态的最大间隔;confirm_window_seconds 是水平倒地候选需持续的确认时间;recovery_window_seconds 是恢复姿态需持续的时间;cooldown_seconds 是确认事件后允许开始恢复判断前的最短等待时间。示例中的全零 SHA-256 只占位配置形状,T-103 必须以受控模型的真实哈希替换并验证后才能启动推理。
  • 灵敏度参数(默认放宽,适配低位俯视):require_rapid_drop(默认 false,持续水平即可进入疑似,不再强制先检测到快速下移);require_lower_body(默认 false,质量门控只强制肩+髋,膝踝可缺);horizontal_angle_threshold_degrees(默认 45,躯干与水平夹角≤此值算水平)。放宽后由 confirm_window_seconds 作为主要防误报闸——弯腰、捡物不会持续水平到确认窗满。三者进入 config_version,可经设置调整并追溯。
  • 缺少环境变量、模型不存在或哈希不符时,应用显示配置错误,不启动监控。

V2 Go 运行配置

v2/config.example.json 是 V2 的公开配置形状。它保留 V1 的来源、模型、事件和工件语义,但将 V2 交付依赖显式写入 model.onnx、model.ort_dll 和 tools.ffmpeg/tools.ffprobe:

  • source 只接受 id、rtsp_url_env、transport、timeout_seconds 和 low_latency。任何 url、rtsp_url、host、username 或 password 字段都会被拒绝,即使它们为空;实际流地址只从指定环境变量进入进程内存。
  • model.sha256 必须是锁定 ONNX 的 64 位十六进制 SHA-256;confidence_threshold 是 Pose 框过滤阈值。配置相对路径相对于配置文件解析,但只在启动预检时要求实际文件存在。
  • event 字段与 V1 的默认事件语义相同。V2 使用 source.id、模型 SHA、模型置信度和这些事件字段生成 cfg-<sha256>;URL、工具路径和工件路径均不进入该版本值。
  • artifacts.event_dir 只保存本地 PNG/JSONL 事件证据。V2 发布脚本生成的 runtime-manifest.json 记录 ONNX Runtime、FFmpeg、FFprobe 和 ONNX 的来源文件哈希;示例 runtime-manifest.example.json 不是交付证据。

核心数据

Keypoint = { x: float, y: float, confidence: float }
PersonPose = {
  box_xyxy: [float, float, float, float],
  box_confidence: float,
  keypoints: Keypoint[17]
}
TrackedPersonPose = {
  track_id: string,
  detected_at_monotonic: float,
  pose: PersonPose
}
PoseQuality = {
  accepted: bool,
  reason: string,
  visible_joint_count: int
}
PoseEvidence = {
  accepted: bool,
  horizontal_pose: bool,
  rapid_vertical_change: bool,
  horizontal_angle_degrees: float | null,
  hip_center_y: float | null,
  torso_length: float | null,
  reason: string
}
FallEvent = {
  event_id: string,
  track_id: string,
  config_version: string,
  suspected_at_monotonic: float,
  confirmed_at_monotonic: float,
  latency_seconds: float,
  state: "CONFIRMED"
}

FallEvent 是状态机的纯内存确认事件,只在状态首次进入 CONFIRMED 时创建一次。连续帧更新 UI 状态,但不重复创建事件。config_version 是由运行配置快照计算的非敏感版本标识;T-202 的 alerts 会在不改变事件幂等语义的前提下,为截图/JSONL 记录补充来源、UTC 时间和证据。

event_id 带每次监控运行的会话前缀(FALL-<session>-NNNNNN),跨监控重启全局唯一;因此同一天目录内的截图不会被覆盖,events.jsonl 也不会出现同 id 不同内容的记录。

V2 本地事件证据

V2 的 internal/render 把 BGR 视频帧与已经完成的 FrameResult 合成为 RGBA 图像。它画 person box、17 点骨架、ID、状态和 UTC 时间;NORMAL 为绿色、SUSPECT/RECOVERING 为琥珀色,只有任一人员为 CONFIRMED 时才绘制红色骨架和六像素红色画面边框。

internal/alert.Dispatcher 只接收 CONFIRMED 的 FallEvent 和已叠加的图像。它在写文件前用 event_id 去重,写入 artifacts.event_dir/YYYYMMDD/FALL-*.png 与同目录 events.jsonl;失败会释放该 ID 使后续帧可以重试。JSONL 的字段与下文 AlertRecord 一致,且模块从不接收、保存或输出 RTSP URL。

T-202 的 alerts 按 event_id 去重,对首次 CONFIRMED 只触发一次副作用(声音、弹窗、截图、JSONL 一行)。JSONL 记录如下,文件名与字段不含 RTSP 地址、凭证或客户姓名:

AlertRecord(JSONL) = {
  event_id: string,
  track_id: string,
  config_version: string,
  source_id: string,
  state: "CONFIRMED",
  confirmed_at_utc: string,        # ISO-8601 UTC
  suspected_at_monotonic: float,
  confirmed_at_monotonic: float,
  latency_seconds: float,
  screenshot: string               # 相对 event_dir 的 "YYYYMMDD/FALL-xxxxxx.png"
}

PersonPose 是 T-103 的纯模型输出,不带人员 ID;T-104 的跟踪模块产生 TrackedPersonPose 后,才允许事件证据按人员连续积累。

视频来源帧合约

FramePacket = {
  image: ndarray | null,
  timestamp_monotonic: float,
  status: "connected" | "retrying" | "error" | "eof" | "closed",
  error: string | null
}
  • SourceMode.REPLAY 的录像优先使用容器时间戳;首帧时间戳无效或倒退时,回退为帧序号/FPS,保证回放时间单调;到达 EOF 后保持 EOF,不重放。
  • SourceMode.STREAM 的实时流以成功读帧时的单调时钟计时;读取失败进入有界指数退避重连,不使用 CAP_PROP_POS_MSEC 作为事件时间。
  • retrying、error、eof 和 closed 都没有图像,且绝不伪造人员、姿态或摔倒事件。
  • 可重连来源以有界指数退避重新打开;断流不推进状态机的证据时间。

事件合约

事件 触发者 负载 结果
source.connected 视频源 source_id、时间 UI 显示在线。
source.error 视频源 source_id、错误码、可重试标记 UI 显示异常;不报警。
person.updated 跟踪与 Pose TrackedPersonPose、PoseQuality、PoseEvidence UI 绘制骨架与 ID。
fall.suspected 状态机 track_id、开始时间 UI 显示黄色疑似状态。
fall.confirmed 状态机 FallEvent 红色叠加、声音、弹窗、截图、JSONL。
fall.recovered 状态机 track_id、时间 UI 恢复绿色正常状态。

副作用边界

  • 仅 alerts 模块可写事件截图、播放声音、弹窗和追加 JSONL。
  • 仅 video_source 模块读 RTSP 或本地视频。
  • 仅 pose 模块加载模型;UI 不得直接调用模型。
  • V2 可以改变实现语言,但不得改变配置含义、FallEvent 字段和事件幂等语义。