{
  "name": "std_workshop_face_recognition_shoe_alarm",
  "description": "1080p 车间全功能识别流程，包含人脸检测与识别、人员跟踪、劳保鞋检测、画面叠加、视频发布、告警上报以及抓拍存证。",
  "source": "configs/full_pipeline_1080p_test_alarm.json",
  "slots": {
    "inputs": [
      {"name": "video_input_main", "type": "video_source", "required": true, "description": "主视频输入"}
    ],
    "services": [
      {"name": "object_storage_main", "type": "object_storage", "required": false, "description": "抓拍与片段上传"},
      {"name": "token_service_main", "type": "token_service", "required": false, "description": "认证服务"},
      {"name": "alarm_service_main", "type": "alarm_service", "required": false, "description": "告警服务"}
    ],
    "outputs": [
      {"name": "stream_output_main", "type": "stream_publish", "required": true, "description": "主视频输出"}
    ]
  },
  "template": {
    "executor": {
      "batch_size": 2,
      "run_budget": 8
    },
    "nodes": [
      {
        "id": "input_rtsp_main",
        "type": "input_rtsp",
        "role": "source",
        "enable": true,
        "url": "${slot:video_input_main.url}",
        "fps": 30,
        "width": 1920,
        "height": 1080,
        "use_ffmpeg": true,
        "use_mpp": false,
        "force_tcp": true,
        "reconnect_sec": 5,
        "reconnect_backoff_max_sec": 30
      },
      {
        "id": "preprocess_rgb",
        "type": "preprocess",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          2
        ],
        "dst_w": 1920,
        "dst_h": 1080,
        "dst_format": "rgb",
        "dst_packed": true,
        "resize_mode": "stretch",
        "keep_ratio": false,
        "rga_gate": "main_pipeline_rga",
        "use_rga": true
      },
      {
        "id": "detect_face",
        "type": "ai_scrfd_sliding",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          4
        ],
        "infer_fps": 3,
        "model_path": "./models/face_det_scrfd_500m_640_rk3588.rknn",
        "model_w": 640,
        "model_h": 640,
        "windows": [
          {
            "x": 0,
            "y": 0,
            "w": 960,
            "h": 1080
          },
          {
            "x": 960,
            "y": 0,
            "w": 960,
            "h": 1080
          }
        ],
        "conf_thresh": 0.5,
        "nms_thresh": 0.4,
        "max_faces": 50,
        "debug": {
          "stats": false,
          "stats_interval": 30
        }
      },
      {
        "id": "recognize_face",
        "type": "ai_face_recog",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          4
        ],
        "infer_fps": 2,
        "infer_phase_ms": 120,
        "model_path": "./models/face_recog_mobilefacenet_arcface_112_rk3588.rknn",
        "align": true,
        "emit_embedding": false,
        "max_faces": 50,
        "person_class_id": 0,
        "track_state_max_age_ms": 1000,
        "input_format": "rgb",
        "input_dtype": "uint8",
        "threshold": {
          "accept": 0.45,
          "margin": 0.05
        },
        "gallery": {
          "backend": "sqlite",
          "path": "./models/face_gallery.db",
          "load_on_start": true,
          "dtype": "auto"
        },
        "debug": {
          "enabled": false,
          "log_matches": false,
          "min_log_interval_ms": 0
        }
      },
      {
        "id": "detect_person",
        "type": "ai_yolo",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          5
        ],
        "use_rga": true,
        "rga_gate": "main_pipeline_rga",
        "rga_max_inflight": 4,
        "dst_packed": true,
        "use_dma_input": true,
        "infer_fps": 2,
        "infer_phase_ms": 0,
        "model_path": "./models/object_det_yolov8n_coco_640_rk3588.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
        },
        "debug": {
          "stats": false,
          "stats_interval": 30,
          "detections": false
        }
      },
      {
        "id": "track_person",
        "type": "tracker",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          5
        ],
        "mode": "bytetrack_lite",
        "per_class": true,
        "track_classes": [
          0
        ],
        "ignore_classes": [],
        "high_th": 0.55,
        "low_th": 0.1,
        "iou_th": 0.3,
        "max_age_ms": 900,
        "min_hits": 1,
        "max_tracks": 128
      },
      {
        "id": "detect_shoe",
        "type": "ai_shoe_det",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          6
        ],
        "use_rga": true,
        "rga_gate": "main_pipeline_rga",
        "rga_max_inflight": 4,
        "dst_packed": true,
        "use_dma_input": false,
        "infer_fps": 2,
        "infer_phase_ms": 150,
        "model_path": "./models/shoe_det_yolov8s_workshoe_640_rk3588.rknn",
        "model_w": 640,
        "model_h": 640,
        "conf": 0.22,
        "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,
          "max_box_area_ratio": 0.6,
          "y_offset": 0.7,
          "width_scale": 1.6,
          "height_scale": 0.4
        }
      },
      {
        "id": "rule_shoe_association",
        "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.3,
          "min_shoe_score": 0.22,
          "foot_region": {
            "y_offset": 0.7,
            "width_scale": 1.6,
            "height_scale": 0.4
          },
          "min_shoe_height_ratio": 0.08,
          "min_shoe_area_ratio": 0.012,
          "max_shoe_height_ratio": 0.14,
          "max_shoe_width_ratio": 0.38,
          "max_shoe_area_ratio": 0.05,
          "max_shoe_roi_width_ratio": 0.45,
          "max_shoe_roi_height_ratio": 0.35,
          "max_shoe_roi_area_ratio": 0.1
        }
      },
      {
        "id": "rule_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
        }
      },
      {
        "id": "prepare_publish",
        "type": "preprocess",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          7
        ],
        "dst_w": 1920,
        "dst_h": 1080,
        "dst_format": "nv12",
        "resize_mode": "stretch",
        "rga_gate": "main_pipeline_rga",
        "use_rga": true
      },
      {
        "id": "render_osd",
        "type": "osd",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          7
        ],
        "draw_bbox": true,
        "draw_text": true,
        "draw_face_det": true,
        "draw_face_recog": true,
        "draw_face_bbox": true,
        "line_width": 2.0,
        "font_scale": 1.0,
        "use_rga_bbox": false,
        "labels": [
          "person",
          "shoe",
          "non_black_shoe"
        ]
      },
      {
        "id": "publish_stream",
        "type": "publish",
        "role": "filter",
        "enable": true,
        "cpu_affinity": [
          3
        ],
        "queue": {
          "size": 2,
          "policy": "drop_oldest"
        },
        "codec": "h264",
        "fps": 30,
        "gop": 60,
        "bitrate_kbps": 4000,
        "mpp_output_timeout_ms": 50,
        "mpp_packet_wait_ms": 10,
        "use_mpp": true,
        "use_ffmpeg_mux": true,
        "outputs": [
          {
            "proto": "hls",
            "path": "${slot:stream_output_main.publish_hls_path}",
            "segment_sec": 2
          },
          {
            "proto": "rtsp_server",
            "port": "${slot:stream_output_main.publish_rtsp_port}",
            "path": "${slot:stream_output_main.publish_rtsp_path}"
          }
        ]
      },
      {
        "id": "alarm_violation",
        "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.3,
            "min_box_area_ratio": 0.0,
            "require_track_id": false,
            "min_duration_ms": 800,
            "min_hits": 2,
            "hit_window_ms": 2000,
            "cooldown_ms": 15000,
            "per_track_cooldown_ms": 0
          }
        ],
        "face_track_aggregation": {
          "known": {
            "min_hits": 3,
            "hit_window_ms": 3000,
            "reentry_cooldown_ms": 300000
          },
          "unknown": {
            "min_track_age_ms": 2000,
            "min_quality_hits": 4
          }
        },
        "face_debug": {
          "log_unknown_candidates": false,
          "unknown_candidate_interval_ms": 0
        },
        "face_rules": [
          {
            "name": "unknown_face",
            "type": "unknown",
            "cooldown_ms": 7000,
            "max_known_sim": 0.35,
            "min_hits": 2,
            "hit_window_ms": 1500,
            "min_face_area_ratio": 0.001,
            "min_face_aspect": 0.6,
            "max_face_aspect": 1.6
          },
          {
            "name": "known_person",
            "type": "person",
            "cooldown_ms": 7000,
            "min_sim": 0.6,
            "min_hits": 2,
            "hit_window_ms": 1500,
            "min_face_area_ratio": 0.001,
            "min_face_aspect": 0.6,
            "max_face_aspect": 1.6
          }
        ],
        "actions": {
          "log": {
            "enable": true,
            "level": "info",
            "include_detections": true,
            "min_interval_ms": 2000
          },
          "snapshot": {
            "enable": true,
            "format": "jpg",
            "quality": 85,
            "upload": {
              "type": "minio",
              "endpoint": "${slot:object_storage_main.endpoint}",
              "bucket": "${slot:object_storage_main.bucket}",
              "region": "us-east-1",
              "access_key": "${slot:object_storage_main.access_key}",
              "secret_key": "${slot:object_storage_main.secret_key}"
            }
          },
          "clip": {
            "enable": true,
            "pre_sec": 5,
            "post_sec": 10,
            "format": "mp4",
            "fps": 30,
            "upload": {
              "type": "minio",
              "endpoint": "${slot:object_storage_main.endpoint}",
              "bucket": "${slot:object_storage_main.bucket}",
              "region": "us-east-1",
              "access_key": "${slot:object_storage_main.access_key}",
              "secret_key": "${slot:object_storage_main.secret_key}"
            }
          },
          "external_api": {
            "enable": true,
            "getTokenUrl": "${slot:token_service_main.get_token_url}",
            "putMessageUrl": "${slot:alarm_service_main.put_message_url}",
            "tenantCode": "${slot:alarm_service_main.tenant_code}",
            "channelNo": "${slot:stream_output_main.channel_no}",
            "timeout_ms": 3000,
            "include_media_url": true,
            "token_header": "X-Access-Token",
            "token_json_path": "responseBody.token",
            "token_cache_sec": 1200
          }
        }
      }
    ],
    "edges": [
      [
        "input_rtsp_main",
        "preprocess_rgb"
      ],
      [
        "preprocess_rgb",
        "detect_face"
      ],
      [
        "detect_face",
        "detect_person"
      ],
      [
        "detect_person",
        "track_person"
      ],
      [
        "track_person",
        "recognize_face"
      ],
      [
        "recognize_face",
        "detect_shoe",
        {
          "queue": {
            "size": 16,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "detect_shoe",
        "rule_shoe_association",
        {
          "queue": {
            "size": 16,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "rule_shoe_association",
        "rule_shoe_color",
        {
          "queue": {
            "size": 16,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "rule_shoe_color",
        "render_osd",
        {
          "queue": {
            "size": 16,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "render_osd",
        "prepare_publish",
        {
          "queue": {
            "size": 32,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "prepare_publish",
        "publish_stream",
        {
          "queue": {
            "size": 64,
            "strategy": "drop_oldest"
          }
        }
      ],
      [
        "publish_stream",
        "alarm_violation",
        {
          "queue": {
            "size": 64,
            "strategy": "drop_oldest"
          }
        }
      ]
    ]
  }
}
