RDK X5 MIPI摄像头推理:单独测试87FPS,但视频流只有4-5FPS

一、问题描述
在 RDK X5 上部署 YOLOv8n 道路缺陷检测模型,**单独测试推理模块可达 87 FPS**,但接入 MIPI 摄像头后,**完整视频流只有 4-5 FPS**
二、环境信息
| 项目 | 信息 |

|------|------|

| 开发板 | RDK X5 |

| BPU Platform | 1.3.6 |

| DNN Runtime | 1.24.5_(3.15.55 HBRT) |

| Model Builder | 1.24.3 |

| 模型 | YOLOv8n 自训练道路缺陷检测 (5类) |

| 输入格式 | NV12, 640x640 |

| 摄像头 | MIPI (1920x1080 采集, 640x640 推理, 1280x720 显示) |

三、模型信息

```bash

hrt_model_exec model_info --model_file yolov8n_road.bin

```

模型基本信息

| 项目 | 值 |

|------|-----|

| 模型名称 | converted_model |

| 子图数量 | **1 个 (无 CPU 回退)** |

| 加载耗时 | 178ms |

**输入 Tensor**:

| 属性 | 值 |

|------|-----|

| 名称 | images |

| 来源 | HB_DNN_INPUT_FROM_PYRAMID |

| Shape | (1, 3, 640, 640) |

| 类型 | HB_DNN_IMG_TYPE_NV12 |

| Layout | NCHW |

输出 Tensors (Split-Head 格式)

| 输出 | 名称 | Shape | 说明 |

|------|------|-------|------|

| output[0] | output0 | (1,80,80,64) | bbox stride=8 |

| output[1] | 326 | (1,40,40,64) | bbox stride=16 |

| output[2] | 334 | (1,20,20,64) | bbox stride=32 |

| output[3] | 342 | (1,80,80,5) | cls stride=8 |

| output[4] | 350 | (1,40,40,5) | cls stride=16 |

| output[5] | 358 | (1,20,20,5) | cls stride=32 |

> :white_check_mark: 模型结构正确:单 BPU 子图 + Split-Head 6 输出,无 Softmax CPU 回退问题。

四、性能测试结果

4.1 单独推理测试 (87 FPS) :white_check_mark:

```python

# 测试命令

python3 inference.py /root/new/models/yolov8n_road.bin

```

输出:

```

[YOLOv8] :white_check_mark: 模型加载成功

[YOLOv8] Anchor grids: [(6400, 2), (1600, 2), (400, 2)]

预热…

基准测试 (100 次)…

20/100: 11.08ms

40/100: 11.05ms

60/100: 11.12ms

80/100: 11.10ms

100/100: 11.26ms

平均延迟: 11.44ms

吞吐量: 87.4 FPS

```

4.2 完整视频流 (4-5 FPS) :cross_mark:

接入 MIPI 摄像头后,Web 显示只有 4-5 FPS。

五、系统架构

```

MIPI 摄像头 (1920x1080)

│

├── VPS 输出 1: 640x640 NV12 ──→ \[推理线程\] ──→ BPU 推理 (11ms)

│                                                   │

│                                               结果共享

│                                                   ↓

└── VPS 输出 2: 1280x720 NV12 ──→ \[显示线程\] ──→ NV12转BGR ──→ 绘制 ──→ JPEG编码 ──→ Web

```

两个线程独立运行,推理结果通过锁共享给显示线程。

六、关键代码

6.1 摄像头初始化 (双路输出)

```python

# camera_mipi.py

class MIPICamera:

def open(self):

    self.cam = srcampy.Camera()

    \# 双路输出: 推理用 640x640, 显示用 1280x720

    self.cam.open_cam(

        video_index=0,

        fps=-1,

        width=-1,

        width_list=\[self.infer_w, self.display_w\],

        height_list=\[self.infer_h, self.display_h\],

        sensor_height=1080,

        sensor_width=1920

    )



def get_infer_frame(self, timeout=0.1):

    return self.cam.get_img(2, self.infer_w, self.infer_h)



def get_display_frame(self, timeout=0.1):

    return self.cam.get_img(2, self.display_w, self.display_h)

```

6.2 推理模块 (高性能优化版)

```python

\ inference.py - 参考官方论坛优化方案

class YOLOv8DetectorFast:

def \__init_\_(self, model_path, conf_thresh=0.25):

    self.model = dnn.load(model_path)\[0\]

    self.\_init_anchors()  # 预计算 anchor grid

    self.conf_logit = np.log(conf_thresh / (1 - conf_thresh))  # 预计算阈值



def infer_nv12(self, nv12_data, orig_shape):

    outputs = self.model.forward(nv12_data)  # BPU 推理

    return self.\_postprocess(outputs, ...)   # 优化后处理



def \_postprocess(self, outputs, ...):

    \# 关键优化: 先筛选再计算 (logit 空间比较)

    for bbox_out, cls_out in zip(bbox_outputs, cls_outputs):

        cls_max = np.max(cls_feat, axis=1)

        valid_mask = cls_max > self.conf_logit  # 先筛选

        \# 只对有效候选框计算 DFL 解码...

```

6.3 视频流生成

```python

# main.py

def generate_stream(camera, detector):

\# 推理线程 (独立)

def infer_worker():

    while running:

        nv12 = camera.get_infer_frame()  # 640x640

        results, timings = detector.infer_nv12(nv12, orig_shape)

        with lock:

            state.results = results



threading.Thread(target=infer_worker).start()



\# 显示循环

while True:

    display_nv12 = camera.get_display_frame()  # 1280x720

    bgr = nv12_to_bgr(display_nv12)            # OpenCV 转换

    bgr = draw_results(bgr, state.results)     # 绘制检测框

    jpeg = cv2.imencode('.jpg', bgr)           # JPEG 编码

    yield jpeg

```

七、疑问

1. **推理线程和显示线程已经分离**,为什么整体帧率还是只有 4-5 FPS?

2. ****VPS 多路输出****是否有性能瓶颈?`cam.get_img()` 是否会阻塞?

3. 是否需要使用 `srcampy.bind(cam, disp)` ****零拷贝直显****才能达到高帧率?

4. Python 的 `nv12_to_bgr` (OpenCV) 和 ****JPEG 编码****是否是瓶颈?如果是,有什么替代方案?

** 八、期望帮助**

1. 分析 4-5 FPS 瓶颈具体在哪个环节

2. 推荐 RDK X5 上 MIPI 摄像头 + 推理 + Web 显示的最佳实践

我是刚学嵌入式的新手,如有不对请指点,感谢各位大佬指点!

您好,高性能推荐使用C++来进行开发

零拷贝能够大幅提升传输耗时,

为什么要nv12 to bgr nv12就是BPU期望的输入格式,你转化的时RGB的模型吗

Opencv的各种操作都会占用CPU的大量资源,每一帧的延迟的比较高

推荐 RDK X5 上 MIPI 摄像头 + 推理 + Web 显示的最佳实践 参考TROS的高效率输出即可https://developer.d-robotics.cc/rdk_doc/rdk_s/Robot_development/boxs/detection/yolo