feat: stabilize cold display runtime deployment

This commit is contained in:
Yoilun
2026-05-29 14:48:01 +08:00
parent ea5f9b1b07
commit 8b5bbff364
32 changed files with 5050 additions and 241 deletions

View File

@@ -1,19 +1,22 @@
# 冷藏展示柜食品批次计时报警
这是一个独立项目,用于单摄像头监控冷藏展示柜和同画面垃圾桶,记录每个展示区域内食品批次的放置时长,并发现 3 小时到期后的违规行为。
这是一个独立项目,用于单摄像头监控冷藏展示柜和同画面垃圾桶,记录每个展示区域内食品批次的放置时长,并发现超过自定义报警时间后的异常处理行为。
## 已确认业务规则
- 摄像头同时看到展示柜和垃圾桶。
- 展示柜初始布局为横向 4 列、竖向 2 行
- 布局后期可以通过配置调整。
- 展示柜食品区域支持 1 到 10 个自定义区域
- 食品区域使用阿拉伯数字标注:`1``2``3` ...
- 垃圾桶 ROI 独立标定,不占用食品区域编号。
- 每个区域可以放多份食品,但这些食品按同一批次计时。
- 同一区域不允许混批,必须清空后才能放入新批次。
- 食品放入区域时记录开始时间。
- 区域清空时记录结束时间。
-满 3 小时清空视为正常消耗。
- 超过 3 小时清空后必须在确认窗口内看到垃圾桶投放动作
- 超过 3 小时的食品拿出后又放回展示柜,触发报警
-达到报警阈值前清空视为正常消耗。
- 食品在区域内达到 `max_dwell_seconds` 时先产生 `time_alarm`
- 已报警食品从区域移出后,必须在确认窗口内看到垃圾桶投放动作
- 如果已报警食品移出后没有丢到垃圾桶里,报警事件升级为 `warning_escalated` 警告事件。
- 已报警食品拿出后又放回展示柜,触发违规事件。
## 当前实现范围
@@ -23,8 +26,8 @@
{
"ts": "2026-04-27T10:00:00+08:00",
"zone_counts": {
"r1c1": 3,
"r1c2": 0
"1": 1,
"2": 0
},
"trash_deposit": false
}
@@ -33,12 +36,13 @@
程序会输出 JSONL 事件,例如:
- `batch_started`
- `time_alarm`
- `batch_consumed`
- `batch_pending_disposal`
- `batch_discarded`
- `warning_escalated`
- `mixed_batch_violation`
- `overdue_return_violation`
- `missing_disposal_violation`
## 配置
@@ -46,9 +50,25 @@
默认阈值:
- 最大放置时间:`10800` 秒,也就是 3 小时
- 时间报警阈值`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`
@@ -73,10 +93,10 @@ http://127.0.0.1:23000
- 配置 RTSP 地址和阈值
- 从 RTSP 拉取一帧截图
- 标定 `r1c1``r2c4` 的 8 个格口
- 标定垃圾桶区域
- 设置 1 到 10 个食品区域
- 标定数字食品区域和垃圾桶 ROI
- 直接保存标定结果到项目配置文件
- 查看事件汇总和最近 JSONL 事件
- 查看事件汇总、区域序号、停留时间、报警和警告事件
项目仍保留 `tools/calibrator` 作为轻量单页标定工具,但正式使用建议走 `23000` 管理页。
@@ -131,11 +151,22 @@ frame_width = 640
frame_height = 360
capture_timeout_seconds = 12.0
baseline_frames = 3
sample_stride_pixels = 8
occupancy_mean_delta = 24.0
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
trash_motion_delta = 18.0
trash_motion_cooldown_seconds = 8
trash_sustained_motion_delta = 8.0
trash_sustained_motion_frames = 2
trash_motion_cooldown_seconds = 3
diagnostics_path = "logs/runtime_diagnostics.jsonl"
```
@@ -144,3 +175,10 @@ diagnostics_path = "logs/runtime_diagnostics.jsonl"
```bash
PYTHONPATH=src python3 -m unittest discover -s tests -v
```
前端测试和构建:
```bash
node --test web/test/zone-state.test.js
cd web && pnpm build
```