9.6 KiB
Cold Display Guard Project Documentation
Goal
cold-display-guard monitors refrigerated display food batches by camera region. It tracks how long each configured food region remains occupied, raises a configurable time alarm, and escalates alarmed food to a warning if it is removed without a matching trash-bin deposit.
The v1.1 优化改造 batch upgrades the product from a fixed 8-zone layout to a configurable 1-10 zone workflow with numeric region labels and editable trash ROI calibration. All v1.1 items are part of one batch; backend, API, frontend, and documentation are implementation workstreams inside that same batch.
The v1.2 轨迹识别 batch adds source-zone trajectory evidence for disposal confirmation. The first implementation uses lightweight motion tracking and keeps YOLO disabled, while preserving an evidence contract that a later trained YOLO product detector can enrich.
Architecture
- Backend package:
src/cold_display_guard/models.py: settings, observations, and batch dataclasses.engine.py: deterministic batch state machine.config.py: TOML config load/save, calibration merge, and project path resolution.manage_api.py: standard-library HTTP management API.main.py: RTSP runtime loop connecting frame capture, vision, state engine, and JSONL sinks.vision.py: heuristic ROI occupancy and trash-motion detection.- v1.2 adds trajectory evidence between vision and engine:
TrajectoryTrackeremits source-zone-to-trash evidence;BatchEngineconsumes the backend-neutraldisposal_evidencecontract.
- Frontend package:
web/- Vite + vanilla JavaScript management console.
- Default web port
23000. - API proxy target
http://127.0.0.1:19080. - Runtime home view falls back to clearly marked demo data when no real events exist, so the operational layout still shows summary cards, dwell timers, and event rows.
- Runtime data:
- Events JSONL default path
logs/events.jsonl. - Diagnostics JSONL default path
logs/runtime_diagnostics.jsonl. - v1.2 diagnostics include root-level
disposal_evidenceplusdiagnostics.trajectory.
- Events JSONL default path
- Deployment:
- Root Python Docker image for API/runtime.
web/Dockerfilefor static web console.deploy/docker-compose.ymlwires API, runtime, and web services.
Configuration
- Main config path:
config/example.toml. - Camera identity:
camera_id. - Timezone default:
Asia/Shanghai. - RTSP input:
[stream] rtsp_url. - Thresholds:
max_dwell_seconds: v1.1 time-alarm threshold. Default can remain 10800 seconds; users can set values such as 1200 seconds for 20 minutes.trash_confirmation_seconds: window after an alarmed batch is removed where a trash deposit must be observed before warning escalation.
- Food zones:
- v1.1 food zone IDs are numeric strings from
"1"through"10". - The configured zone count must be between 1 and 10.
- If both
zone_countand numericzone_idsare present, they must agree. - Each
[[zones]]polygon must have at least 3 normalized points.
- v1.1 food zone IDs are numeric strings from
- Trash ROI:
- Stored under
[trash] roi. - Does not use a food zone number.
- Stored under
- v1.2 trajectory settings:
lighting_shift_guard_enabled: freezes occupancy changes when many regions shift brightness in the same direction.lighting_shift_min_regions,lighting_shift_region_fraction,lighting_shift_mean_delta: tune the global lighting/exposure guard.trajectory_enabled: enables source-zone trajectory evidence.trajectory_window_seconds: seconds after a zone clears where movement can confirm disposal.trajectory_sample_interval_seconds: faster runtime delay while a candidate is active.trajectory_min_points: minimum sampled motion points required before evidence can emit.trajectory_segmented_enabled,trajectory_segmented_min_points: allow a source point plus trash-entry point to confirm disposal when the middle of the path is occluded.trajectory_min_confidence: minimum confidence before evidence can close pending disposal.trajectory_motion_delta: frame-difference threshold for trajectory motion points.trajectory_min_blob_area: minimum connected motion area to keep as a point.trajectory_max_blob_area_fraction: rejects overly broad frame motion as ambiguous.trajectory_trash_entry_margin: margin for treating a track point as entering the trash ROI.trajectory_backend: first valid value is"motion".yolo_enabled,yolo_model_path,yolo_min_confidence: reserved for a future trained model backend. Current v1.2 keeps YOLO disabled.
v1.2 Runtime Flow
RTSPFrameSourcecaptures a resized RGB frame.ZoneOccupancyDetectorupdates per-zone binary occupancy and generic trash-motion count from calibrated ROIs.TrajectoryTrackercaches recent source-region motion while a zone is occupied, watches zones that just cleared, follows lightweight motion points toward the trash ROI, and emits source-specificDisposalEvidencewhen confidence passes the configured threshold. If the middle of the path is occluded, a segmented source-to-trash track can still emit evidence.BatchEngineprocessesObservation(zone_counts, trash_deposit_count, disposal_evidence).- For pending disposal, matching
disposal_evidence.source_zone_idconfirmsbatch_discardedbefore generic FIFOtrash_deposit_countfallback is used. - Runtime writes events to
logs/events.jsonland diagnostics tologs/runtime_diagnostics.jsonl.
The current tracker is a motion backend only. A later trained YOLO detector should plug in as another backend that enriches or replaces the evidence producer while preserving the same disposal_evidence contract consumed by the engine.
Diagnostics
- Runtime diagnostics JSONL records one item per runtime iteration.
- Root
disposal_evidenceis the exact evidence list passed into the engine for that iteration. diagnostics.zonescontains occupancy metrics used to derivezone_counts.diagnostics.lighting_shiftreports whether global brightness drift suppressed occupancy transitions.diagnostics.trashcontains generic trash-motion metrics and cooldown state.diagnostics.trajectorycontains v1.2 candidate counts, emitted evidence count, motion point count, source-seeded and segmented-track flags, and per-candidate emitted/rejected/expired records.- Capture failures still keep the v1.2 schema with root
disposal_evidence: []anddiagnostics.trajectory.reason = "frame_capture_failed".
Event Model
batch_started: a food region changes from empty to occupied.time_alarm: an active batch reachesmax_dwell_secondswhile still in the display region.batch_count_changed: count decreases while the region remains occupied.mixed_batch_violation: count increases before the region clears.batch_consumed: a non-alarmed batch clears before the threshold.batch_pending_disposal: an alarmed batch clears and waits for trash confirmation.batch_discarded: a pending alarmed batch is matched to a trash deposit.warning_escalated: a pending alarmed batch is not matched to a trash deposit before the confirmation deadline.
Events should include zone_id, zone_index, zone_label, started_at, dwell_seconds, and relevant alarm/removal/deadline timestamps when available.
In v1.2, batch_discarded can be triggered by zone-scoped disposal_evidence before falling back to generic trash_deposit_count. Evidence must match the pending batch's source_zone_id.
Runbook
- Python tests:
PYTHONPATH=src python3 -m unittest discover -s tests -v
- Management API:
scripts/run_manage_api.sh- Health:
curl http://127.0.0.1:19080/api/manage/health
- Web console:
scripts/run_web.sh- Build:
cd web && pnpm build - Frontend logic tests:
node --test web/test/zone-state.test.js - Docker web URL:
http://127.0.0.1:23000
- Runtime monitor:
scripts/run_runtime.sh- One-frame smoke test when camera and
ffmpegare available:PYTHONPATH=src python3 -m cold_display_guard.main --config config/example.toml --once
- v1.2 operating notes:
- Keep
trajectory_backend = "motion"andyolo_enabled = falseunless a trained YOLO backend has been explicitly deployed. - Confirm
logs/runtime_diagnostics.jsonlcontains top-leveldisposal_evidenceanddiagnostics.trajectorybefore judging trajectory behavior from events alone. - When
TrajectoryTrackerhas active candidates, runtime sampling usestrajectory_sample_interval_seconds; this can temporarily be faster than the normalsample_interval_seconds. - On remote deployments, preserve the remote
config/example.tomlcalibration and stream settings when syncing code.
- Keep
Known Risks
- The current vision detector is heuristic and reports binary occupancy, not item counts.
- The lighting-shift guard suppresses multi-zone brightness/exposure jumps; if operators intentionally fill most zones at once under a large lighting change, diagnostics should be reviewed before treating that interval as clean data.
- v1.2 motion tracking improves disposal matching but can still miss movement if the hand/object path is occluded, too broad, too small, or sampled too sparsely.
- YOLO config fields are present for compatibility, but no trained YOLO model is part of the current runtime.
- If food is already present during baseline collection, those regions may be treated as empty baseline until visual changes occur.
- Changing calibration while the runtime process has active batches can create operational ambiguity; v1.1 should document or enforce a pause/restart expectation.
- Historical events must keep the zone index at the time of emission so later region reordering does not reinterpret old logs.