开发后处理插件2
Some checks are pending
CI / host-build (push) Waiting to run
CI / rk3588-cross-build (push) Waiting to run

This commit is contained in:
sladro 2026-01-06 11:53:34 +08:00
parent 16c4e50535
commit 41c4a3de3b
2 changed files with 98 additions and 6 deletions

View File

@ -80,11 +80,13 @@
示意:
```text
[in] → [pre] → [ai] ─────→ [alarm]
└──→ [osd] → [storage]
└──→ [publish]
[in] → [pre] → [ai_yolo] → [det_post] ───→ [alarm]
──────→ [osd] → [storage]
└──→ [publish]
```
> 说明:`det_post` 是检测结果后处理节点(可选)。它会对 `frame->det` 做过滤/修正/二次验证,使 OSD 与告警读取到一致的“后处理结果”。
---
## 三、数据模型Frame & 元数据)
@ -322,6 +324,23 @@ GraphMgr 负责:
"nms": 0.5,
"class_filter": [0, 1]
},
{
"id": "pp_cam1",
"type": "det_post",
"role": "filter",
"enable": true,
"default": { "enable": false },
"per_class": [
{
"class_id": 0,
"enable": true,
"processors": [
{ "type": "conf_gate", "conf_min": 0.65 },
{ "type": "bbox_gate", "min_w": 10, "min_h": 10 }
]
}
]
},
{
"id": "osd_cam1",
"type": "osd",
@ -373,8 +392,9 @@ GraphMgr 负责:
"edges": [
["in_cam1", "pre_cam1"],
["pre_cam1", "ai_cam1"],
["ai_cam1", "alarm_cam1"],
["ai_cam1", "osd_cam1"],
["ai_cam1", "pp_cam1"],
["pp_cam1", "alarm_cam1"],
["pp_cam1", "osd_cam1"],
["osd_cam1", "storage_cam1"],
["osd_cam1", "publish_cam1"]
]
@ -383,6 +403,10 @@ GraphMgr 负责:
}
```
> 说明:如果不需要后处理:
> - **推荐**:保留 `pp_cam1` 节点(`enable:true`),并确保其不启用任何处理链(例如:`default.enable=false` 且 `per_class` 为空),此时 `det_post` 会作为轻量透传。
> - 若确实要移除该节点:需要**同时删除并重连拓扑**(例如改回 `ai_cam1 -> osd_cam1``ai_cam1 -> alarm_cam1`),仅设置 `enable=false` 会导致下游节点无输入而构图失败。
通过简单改动即可支持不同组合:
- 不报警:`alarm_cam1.enable = false` 或移除该节点/边。
@ -400,13 +424,15 @@ GraphMgr 负责:
{ "id": "in", "type": "input_rtsp", "role": "source", "url": "${url}" },
{ "id": "pre", "type": "preprocess", "role": "filter", "dst_w": 640, "dst_h": 640 },
{ "id": "ai", "type": "ai_yolo", "role": "filter", "model_path": "/models/yolov8n.rknn", "conf": 0.5 },
{ "id": "pp", "type": "det_post", "role": "filter", "enable": true, "default": { "enable": false } },
{ "id": "osd", "type": "osd", "role": "filter" },
{ "id": "pub", "type": "publish", "role": "sink", "path": "/live/${name}" }
],
"edges": [
["in", "pre"],
["pre", "ai"],
["ai", "osd"],
["ai", "pp"],
["pp", "osd"],
["osd", "pub"]
]
}
@ -485,6 +511,65 @@ GraphMgr 负责:
| `ai_pose` | 关键点检测(可选扩展) | `model_path` | NPU |
| `ai_custom` | 自定义 AI 算法 | `model_path`, `custom_param` 等 | NPU |
#### 6.2.1 det_post检测结果后处理按类别策略链
`det_post` 是一个 **Filter** 节点,位于 `ai_yolo` 之后,负责对 `frame->det->items` 做**按类别可配置**的后处理。
**设计目标:**
- 不同类别可以挂不同的处理器链Processor/Strategy Registry避免“一个类别一个插件”。
- 默认改写 `frame->det`,让 `osd` / `alarm` 读到一致结果。
**配置示例:**
```json
{
"id": "pp_cam1",
"type": "det_post",
"role": "filter",
"enable": true,
"default": { "enable": false },
"per_class": [
{
"class_id": 3,
"enable": true,
"processors": [
{ "type": "conf_gate", "conf_min": 0.65 },
{ "type": "bbox_gate", "min_w": 10, "min_h": 10 },
{ "type": "roi_gate", "roi": { "x": 0.1, "y": 0.1, "w": 0.8, "h": 0.8 }, "mode": "center" }
]
},
{
"class_id": 5,
"enable": true,
"processors": [
{ "type": "hsv_ratio", "h_min": 0, "h_max": 20, "s_min": 20, "v_min": 70, "ratio_min": 0.7,
"max_samples": 2048, "step": 0, "min_samples": 32,
"crop": { "x": 0.0, "y": 0.0, "w": 1.0, "h": 1.0 } }
]
},
{
"class_id": 7,
"enable": true,
"processors": [
{ "type": "lab_kmeans", "k": 3, "iters": 8, "l_max": 50, "ratio_min": 0.4,
"max_samples": 2048, "step": 0, "min_samples": 64,
"crop": { "x": 0.0, "y": 0.0, "w": 1.0, "h": 1.0 } }
]
}
]
}
```
**内置 processors当前实现**
- `conf_gate`:按置信度过滤(`conf_min`
- `bbox_gate`:按框尺寸过滤(`min_w`, `min_h`
- `roi_gate`:按 ROI 过滤(`roi:{x,y,w,h}` 归一化;`mode:center` 使用 bbox 中心点判断)
- `hsv_ratio`:框内采样像素转 HSV统计阈值命中占比`h_min/h_max/s_min/s_max/v_min/v_max/ratio_min`,支持 `crop/max_samples/step`
- `lab_kmeans`:框内采样像素转 LabKMeans 聚类后取最暗簇做判定(`k/iters/l_max/ratio_min`,支持 `crop/max_samples/step`
> 注意:`hsv_ratio/lab_kmeans` 需要 `Frame` 提供可读的像素数据(`frame->data` 可访问)。若上游是纯 DMA-BUF 且未映射到 CPU这两类处理器会自然退化为“不过滤”。
**ai_yolo 参数说明:**
- `model_version`: `"v5"`, `"v8"``"auto"`(自动检测)
- `num_classes`: 模型类别数(默认 80

View File

@ -772,6 +772,13 @@ public:
return NodeStatus::OK;
}
// Fast path: no enabled pipelines configured.
if (!cfg->def.enable && cfg->per_class.empty()) {
PushToDownstream(frame);
processed_.fetch_add(1);
return NodeStatus::OK;
}
if (!frame->det || frame->det->items.empty()) {
PushToDownstream(frame);
processed_.fetch_add(1);