Files
cold_display_guard/README_zh.md
2026-06-01 11:06:42 +08:00

232 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 冷藏展示柜食品批次计时报警
这是一个独立项目,用于单摄像头监控冷藏展示柜和同画面垃圾桶,记录每个展示区域内食品批次的放置时长,并发现超过自定义报警时间后的异常处理行为。
## 已确认业务规则
- 摄像头同时看到展示柜和垃圾桶。
- 展示柜食品区域支持 1 到 10 个自定义区域。
- 食品区域使用阿拉伯数字标注:`1``2``3` ...
- 垃圾桶 ROI 独立标定,不占用食品区域编号。
- 每个区域可以放多份食品,但这些食品按同一批次计时。
- 同一区域不允许混批,必须清空后才能放入新批次。
- 食品放入区域时记录开始时间。
- 区域清空时记录结束时间。
- 未达到报警阈值前清空视为正常消耗。
- 食品在区域内达到 `max_dwell_seconds` 时先产生 `time_alarm`
- 已报警食品从区域移出后,必须在确认窗口内看到垃圾桶投放动作。
- 如果已报警食品移出后没有丢到垃圾桶里,报警事件升级为 `warning_escalated` 警告事件。
- 已报警食品拿出后又放回展示柜,触发违规事件。
## 当前实现范围
当前版本已经接入可运行的轻量视觉流程:区域占用、垃圾桶动作和 v1.2 的轻量 motion trajectory 都使用启发式图像差分实现,不使用 YOLO。后续训练好的 YOLO 食品检测模型会通过统一的 `disposal_evidence` / backend 合约接入,不改变批次计时状态机的业务输入形态。
视觉或 backend 模块需要输出标准观察数据:
```json
{
"ts": "2026-04-27T10:00:00+08:00",
"zone_counts": {
"1": 1,
"2": 0
},
"trash_deposit": false,
"disposal_evidence": [
{
"source_zone_id": "1",
"target": "trash",
"confidence": 0.9,
"method": "motion",
"track_points": [
{"x": 0.22, "y": 0.30},
{"x": 0.48, "y": 0.58},
{"x": 0.76, "y": 0.78}
],
"item_class": null,
"detector_score": null,
"observed_at": "2026-04-27T10:00:03+08:00"
}
]
}
```
程序会输出 JSONL 事件,例如:
- `batch_started`
- `time_alarm`
- `batch_consumed`
- `batch_pending_disposal`
- `batch_discarded`
- `warning_escalated`
- `mixed_batch_violation`
- `overdue_return_violation`
## 配置
示例配置在 `config/example.toml`
默认阈值:
- 时间报警阈值:`10800` 秒,也就是 3 小时;管理页按分钟输入,例如 20 分钟会保存为 `1200`
- 垃圾桶投放确认窗口:`120`
食品区域配置示例:
```toml
[layout]
zone_count = 3
zone_ids = ["1", "2", "3"]
[[zones]]
id = "1"
label = "区域 1"
polygon = [[0.1, 0.1], [0.3, 0.1], [0.3, 0.3]]
[trash]
roi = [[0.7, 0.7], [0.9, 0.7], [0.9, 0.9]]
```
## 区域标定
项目现在有正式管理页,前端默认 `23000`,后端默认 `19080`
```bash
scripts/run_manage_api.sh
```
另开一个终端:
```bash
scripts/run_web.sh
```
打开:
```text
http://127.0.0.1:23000
```
管理页支持:
- 配置 RTSP 地址和阈值
- 从 RTSP 拉取一帧截图
- 设置 1 到 10 个食品区域
- 标定数字食品区域和垃圾桶 ROI
- 直接保存标定结果到项目配置文件
- 查看事件汇总、区域序号、停留时间、报警和警告事件
项目仍保留 `tools/calibrator` 作为轻量单页标定工具,但正式使用建议走 `23000` 管理页。
## 管理 API
默认后端:
```text
http://127.0.0.1:19080
```
主要接口:
- `GET /api/manage/health`
- `GET /api/manage/config`
- `PUT /api/manage/config`
- `POST /api/manage/snapshot`
- `PUT /api/manage/calibration`
- `GET /api/manage/summary`
- `GET /api/manage/events`
## 运行识别计时进程
管理页只负责配置和查看数据。要产生数据,还需要启动运行进程:
```bash
scripts/run_runtime.sh
```
运行进程会:
1. 按配置读取 RTSP。
2.`ffmpeg` 周期抓取小尺寸 RGB 帧。
3. 按标定区域做占用变化检测。
4. 判断垃圾桶区域是否有明显投放动作。
5. 对刚清空的来源区域运行轻量 motion trajectory生成可选的 `disposal_evidence`
6. 调用批次计时状态机,优先使用匹配 `source_zone_id``disposal_evidence` 确认丢弃,再回退到通用垃圾桶动作。
7. 写入 `logs/events.jsonl`,管理页会读取这个文件。
当前视觉版本是可运行的启发式版本:
- 每个格口输出 `0/1` 占用状态,不识别单份数量。
- 启动后的前几帧用于建立空柜基线,默认 `3` 帧。
- 如果启动时格口里已经有食品,系统会把它当作基线,后续要等画面变化后才会产生计时事件。
- v1.2 轨迹识别是轻量 motion trajectory不加载 YOLO不要求模型文件。
- 训练好的 YOLO 模型后续应作为新的 backend 接入,并继续输出统一的 `disposal_evidence`
可选运行参数可以放在配置文件的 `[runtime]` 中:
```toml
[runtime]
sample_interval_seconds = 5.0
frame_width = 640
frame_height = 360
capture_timeout_seconds = 12.0
baseline_frames = 3
sample_stride_pixels = 4
occupancy_mean_delta = 55.0
occupancy_texture_delta = 18.0
occupancy_dark_luma_threshold = 80.0
occupancy_dark_fraction = 0.06
occupancy_texture_dark_fraction = 0.04
occupancy_bright_luma_threshold = 220.0
occupancy_bright_reflection_fraction = 0.18
occupancy_reflection_dark_fraction = 0.10
occupancy_reflection_bright_dark_ratio = 2.0
occupancy_confirm_frames = 2
empty_confirm_frames = 2
lighting_shift_guard_enabled = true
lighting_shift_min_regions = 3
lighting_shift_region_fraction = 0.6
lighting_shift_mean_delta = 45.0
trash_motion_delta = 18.0
trash_sustained_motion_delta = 8.0
trash_sustained_motion_frames = 2
trash_motion_cooldown_seconds = 3
trajectory_enabled = true
trajectory_window_seconds = 8
trajectory_sample_interval_seconds = 1.0
trajectory_min_points = 3
trajectory_segmented_enabled = true
trajectory_segmented_min_points = 2
trajectory_min_confidence = 0.72
trajectory_motion_delta = 20.0
trajectory_min_blob_area = 12
trajectory_max_blob_area_fraction = 0.35
trajectory_trash_entry_margin = 0.04
trajectory_backend = "motion"
yolo_enabled = false
yolo_model_path = ""
yolo_min_confidence = 0.65
diagnostics_path = "logs/runtime_diagnostics.jsonl"
```
`trajectory_backend = "motion"` 表示当前使用轻量轨迹 backend。`yolo_enabled``yolo_model_path``yolo_min_confidence` 是为后续训练模型预留的配置项;当前版本即使保留这些字段,也不会启用 YOLO 推理。
运行诊断写入 `logs/runtime_diagnostics.jsonl`。每行包含顶层 `disposal_evidence`,以及 `diagnostics.trajectory`
- 顶层 `disposal_evidence`:本帧实际输出给状态机的来源区域到垃圾桶证据。
- `diagnostics.lighting_shift`:多数区域同时同方向亮度漂移时启用,防止灯光/曝光变化被当成食品进出。
- `diagnostics.trajectory`:轻量轨迹 backend 的候选、过期、拒绝、分段轨迹和已发出证据等调试信息。
## 本地测试
```bash
PYTHONPATH=src python3 -m unittest discover -s tests -v
```
前端测试和构建:
```bash
node --test web/test/zone-state.test.js
cd web && pnpm build
```