From 6b5ce59592987a8cecd28625af39fc25fff545f1 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sun, 15 Mar 2026 11:23:01 +0800 Subject: [PATCH] Add workshoe color alarm pipeline --- .../person_shoe_two_stage_workshoe_alarm.json | 246 ++++++++++++++++++ docs/deployment.md | 6 + plugins/logic_gate/logic_gate_node.cpp | 35 ++- 3 files changed, 273 insertions(+), 14 deletions(-) create mode 100644 configs/person_shoe_two_stage_workshoe_alarm.json diff --git a/configs/person_shoe_two_stage_workshoe_alarm.json b/configs/person_shoe_two_stage_workshoe_alarm.json new file mode 100644 index 0000000..cda09de --- /dev/null +++ b/configs/person_shoe_two_stage_workshoe_alarm.json @@ -0,0 +1,246 @@ +{ + "queue": { + "size": 8, + "strategy": "drop_oldest" + }, + "graphs": [ + { + "name": "person_shoe_two_stage_workshoe_alarm", + "executor": { + "batch_size": 2, + "run_budget": 8 + }, + "nodes": [ + { + "id": "in", + "type": "input_rtsp", + "role": "source", + "enable": true, + "url": "rtsp://10.0.0.49:8554/cam", + "fps": 30, + "width": 1920, + "height": 1080, + "use_ffmpeg": true, + "use_mpp": false, + "force_tcp": true + }, + { + "id": "pre_rgb", + "type": "preprocess", + "role": "filter", + "enable": true, + "dst_w": 1920, + "dst_h": 1080, + "dst_format": "rgb", + "dst_packed": true, + "resize_mode": "stretch", + "rga_gate": "person_shoe_two_stage_workshoe_alarm", + "use_rga": true + }, + { + "id": "person_det", + "type": "ai_yolo", + "role": "filter", + "enable": true, + "cpu_affinity": [4], + "use_rga": true, + "rga_gate": "person_shoe_two_stage_workshoe_alarm", + "rga_max_inflight": 4, + "dst_packed": true, + "use_dma_input": true, + "infer_fps": 2, + "infer_phase_ms": 0, + "model_path": "./models/yolov8n-640.rknn", + "model_version": "v8", + "model_w": 640, + "model_h": 640, + "num_classes": 80, + "conf": 0.35, + "nms": 0.45, + "class_filter": [0], + "bbox_expand": { + "enable": true, + "class_id": 0, + "left": 0.06, + "right": 0.06, + "top": 0.04, + "bottom": 0.16 + } + }, + { + "id": "person_trk", + "type": "tracker", + "role": "filter", + "enable": true, + "cpu_affinity": [5], + "mode": "bytetrack_lite", + "per_class": true, + "track_classes": [0], + "high_th": 0.55, + "low_th": 0.10, + "iou_th": 0.3, + "max_age_ms": 900, + "min_hits": 2 + }, + { + "id": "shoe_det", + "type": "ai_shoe_det", + "role": "filter", + "enable": true, + "cpu_affinity": [6], + "use_rga": true, + "rga_gate": "person_shoe_two_stage_workshoe_alarm", + "rga_max_inflight": 4, + "dst_packed": true, + "use_dma_input": false, + "infer_fps": 2, + "infer_phase_ms": 150, + "model_path": "./models/shoe_detector_openimages_ppe_v1.rknn", + "model_w": 640, + "model_h": 640, + "conf": 0.15, + "nms": 0.45, + "v8_box_format": "cxcywh", + "append_detections": true, + "dynamic_roi": { + "enable": true, + "person_class_id": 0, + "shoe_class_id": 1, + "debug_roi_class_id": -1, + "max_rois": 3, + "min_person_height": 60, + "x_offset": -0.24, + "y_offset": 0.64, + "width_scale": 1.48, + "height_scale": 0.58 + } + }, + { + "id": "shoe_assoc", + "type": "logic_gate", + "role": "filter", + "enable": true, + "cpu_affinity": [6], + "mode": "person_shoe_check", + "debug": false, + "person_shoe_check": { + "person_class": 0, + "shoe_class": 1, + "violation_class": 2, + "min_person_score": 0.30, + "min_shoe_score": 0.15, + "require_person_track_id": true, + "attach_person_track_to_shoe": true, + "emit_missing_violation": false, + "foot_region": { + "x_offset": -0.24, + "y_offset": 0.64, + "width_scale": 1.48, + "height_scale": 0.58 + } + } + }, + { + "id": "shoe_color", + "type": "logic_gate", + "role": "filter", + "enable": true, + "cpu_affinity": [6], + "mode": "ppe_boots_check", + "anchor_class": 0, + "boots_class": 1, + "violation_class": 2, + "debug": false, + "color_check": { + "enable": true, + "method": "brightness", + "dark_threshold": 90, + "roi_expand": 1.0 + } + }, + { + "id": "osd", + "type": "osd", + "role": "filter", + "enable": true, + "cpu_affinity": [7], + "draw_bbox": true, + "draw_text": false, + "use_rga_bbox": false, + "labels": ["person", "shoe", "non_black_shoe"] + }, + { + "id": "post", + "type": "preprocess", + "role": "filter", + "enable": true, + "cpu_affinity": [7], + "dst_w": 1920, + "dst_h": 1080, + "dst_format": "nv12", + "resize_mode": "stretch", + "rga_gate": "person_shoe_two_stage_workshoe_alarm", + "use_rga": true + }, + { + "id": "pub", + "type": "publish", + "role": "filter", + "enable": true, + "cpu_affinity": [3], + "codec": "h264", + "fps": 30, + "bitrate_kbps": 2000, + "mpp_output_timeout_ms": 50, + "mpp_packet_wait_ms": 10, + "use_mpp": true, + "outputs": [ + {"proto": "rtsp_server", "port": 8555, "path": "/live/cam1"} + ] + }, + { + "id": "alarm", + "type": "alarm", + "role": "sink", + "enable": true, + "eval_fps": 2, + "labels": ["person", "shoe", "non_black_shoe"], + "rules": [ + { + "name": "non_compliant_workshoe", + "class_ids": [2], + "roi": {"x": 0.0, "y": 0.0, "w": 1.0, "h": 1.0}, + "min_score": 0.30, + "require_track_id": true, + "min_duration_ms": 800, + "min_hits": 2, + "hit_window_ms": 2000, + "cooldown_ms": 10000, + "per_track_cooldown_ms": 15000 + } + ], + "actions": { + "log": { + "enable": true, + "level": "info", + "include_detections": true, + "min_interval_ms": 2000 + } + } + } + ], + "edges": [ + ["in", "pre_rgb"], + ["pre_rgb", "person_det"], + ["person_det", "person_trk"], + ["person_trk", "shoe_det", {"queue": {"size": 16, "strategy": "drop_oldest"}}], + ["shoe_det", "shoe_assoc", {"queue": {"size": 16, "strategy": "drop_oldest"}}], + ["shoe_assoc", "shoe_color", {"queue": {"size": 16, "strategy": "drop_oldest"}}], + ["shoe_color", "osd", {"queue": {"size": 16, "strategy": "drop_oldest"}}], + ["osd", "post", {"queue": {"size": 32, "strategy": "drop_oldest"}}], + ["post", "pub", {"queue": {"size": 64, "strategy": "drop_oldest"}}], + ["pub", "alarm", {"queue": {"size": 64, "strategy": "drop_oldest"}}] + ] + } + ] +} diff --git a/docs/deployment.md b/docs/deployment.md index df37bf9..db6002b 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -165,6 +165,12 @@ sudo ./scripts/ops.sh ddr-restore ./build/media-server -c configs/person_shoe_two_stage_recommended_alarm.json ``` +如果业务目标是“只关心已检测到的鞋是否为黑色劳保鞋”,可使用: + +```bash +./build/media-server -c configs/person_shoe_two_stage_workshoe_alarm.json +``` + 说明: - 输入端:`use_ffmpeg: true`、`use_mpp: false` diff --git a/plugins/logic_gate/logic_gate_node.cpp b/plugins/logic_gate/logic_gate_node.cpp index 5cfe0cd..c5509f4 100644 --- a/plugins/logic_gate/logic_gate_node.cpp +++ b/plugins/logic_gate/logic_gate_node.cpp @@ -21,6 +21,7 @@ struct PersonShoeCheckConfig { bool require_person_track_id = false; bool use_person_bbox_for_violation = true; bool attach_person_track_to_shoe = true; + bool emit_missing_violation = true; float match_iou = 0.02f; float x_offset = -0.20f; float y_offset = 0.64f; @@ -32,6 +33,7 @@ struct LogicGateConfig { std::string mode = "ppe_boots_check"; int anchor_class = 6; int boots_class = 3; + int violation_class = 10; bool enable_color_check = true; bool pass_through = true; bool debug = false; @@ -118,6 +120,7 @@ private: config.mode = cfg.ValueOr("mode", config.mode); config.anchor_class = cfg.ValueOr("anchor_class", config.anchor_class); config.boots_class = cfg.ValueOr("boots_class", config.boots_class); + config.violation_class = cfg.ValueOr("violation_class", config.violation_class); config.violation_key = cfg.ValueOr("violation_key", config.violation_key); config.pass_through = cfg.ValueOr("pass_through", config.pass_through); config.debug = cfg.ValueOr("debug", config.debug); @@ -144,6 +147,8 @@ private: "use_person_bbox_for_violation", config.person_shoe.use_person_bbox_for_violation); config.person_shoe.attach_person_track_to_shoe = ps->ValueOr( "attach_person_track_to_shoe", config.person_shoe.attach_person_track_to_shoe); + config.person_shoe.emit_missing_violation = ps->ValueOr( + "emit_missing_violation", config.person_shoe.emit_missing_violation); config.person_shoe.match_iou = ps->ValueOr("match_iou", config.person_shoe.match_iou); if (const SimpleJson* fr = ps->Find("foot_region"); fr && fr->IsObject()) { config.person_shoe.x_offset = fr->ValueOr("x_offset", config.person_shoe.x_offset); @@ -246,19 +251,21 @@ private: continue; } - Detection no_shoe; - no_shoe.cls_id = config_.person_shoe.violation_class; - no_shoe.track_id = person.track_id; - no_shoe.score = std::max(0.5f, person.score); - no_shoe.bbox = config_.person_shoe.use_person_bbox_for_violation ? person.bbox : foot_region; - appended.push_back(no_shoe); + if (config_.person_shoe.emit_missing_violation) { + Detection no_shoe; + no_shoe.cls_id = config_.person_shoe.violation_class; + no_shoe.track_id = person.track_id; + no_shoe.score = std::max(0.5f, person.score); + no_shoe.bbox = config_.person_shoe.use_person_bbox_for_violation ? person.bbox : foot_region; + appended.push_back(no_shoe); - if (config_.debug) { - LogInfo("[logic_gate] no_shoe track_id=" + std::to_string(no_shoe.track_id) + - " bbox=(" + std::to_string(static_cast(no_shoe.bbox.x)) + "," + - std::to_string(static_cast(no_shoe.bbox.y)) + "," + - std::to_string(static_cast(no_shoe.bbox.w)) + "," + - std::to_string(static_cast(no_shoe.bbox.h)) + ")"); + if (config_.debug) { + LogInfo("[logic_gate] no_shoe track_id=" + std::to_string(no_shoe.track_id) + + " bbox=(" + std::to_string(static_cast(no_shoe.bbox.x)) + "," + + std::to_string(static_cast(no_shoe.bbox.y)) + "," + + std::to_string(static_cast(no_shoe.bbox.w)) + "," + + std::to_string(static_cast(no_shoe.bbox.h)) + ")"); + } } } @@ -282,8 +289,8 @@ private: if (color_result.is_dark) continue; Detection no_boots_det; - no_boots_det.cls_id = 10; - no_boots_det.track_id = std::max(0, boot.track_id); + no_boots_det.cls_id = config_.violation_class; + no_boots_det.track_id = boot.track_id; no_boots_det.score = std::max(0.5f, color_result.confidence); no_boots_det.bbox = boot.bbox; detections.push_back(no_boots_det);