[具身智能-566]:RDK RDK X5 mipi_camera.py(FCOS 目标检测 Demo)完整解析 RDK X5 mipi_camera.pyFCOS 目标检测 Demo完整解析运行环境RDK OS3.xX5 平台核心组件hobot_vio(相机 / 显示) hobot_dnn(BPU 推理) libpostprocess.so(C 后处理) 业务流程MIPI 相机采集 NV12 图 → BPU FCOS 推理 → C 库后处理解析检测框 → HDMI 叠加绘制目标框一、整体数据流框图plaintextMIPI Sensor(F37) → hobot_vio.Camera采集 → 裁剪缩放512×512 NV12图像 ↓ models[0].forward() BPU硬件推理 ↓ 推理输出tensor → 多进程调度调用libpostprocess.soFCOS解码 ↓ 解析JSON检测结果 → HDMI图层叠加绘制方框类别文字二、模块逐段解析1. 头文件与兼容导入python运行try: from hobot_vio import libsrcampy as srcampy except ImportError: from hobot_vio_rdkx5 import libsrcampy as srcampy try: from hobot_dnn import pyeasy_dnn as dnn except ImportError: from hobot_dnn_rdkx5 import pyeasy_dnn as dnn作用兼容新旧 SDK 包名srcampy 地平线 VIO 库Camera/Display/Binddnn BPU 推理 Python 接口⚠️ 你之前报错根源此模块预编译依赖 numpy2.02. C 类型结构体定义ctypes 桥接 C 库python运行class hbSysMem_t / hbDNNTensor_t / FcosPostProcessInfo_t ... libpostprocess ctypes.CDLL(/usr/lib/libpostprocess.so)重点Python 通过ctypes直接调用地平线提供的 C 语言后处理动态库libpostprocess.so手动对齐 C 结构体将 BPU 推理输出 tensor 内存地址传递给 C 函数FcosdoProcessget_Postprocess_result返回 JSON 字符串包含所有目标框坐标、置信度、类别 ID优势后处理在 C 中运行性能远高于纯 Python 解析避免占用 CPU3. 显示分辨率自动适配函数get_display_res()python运行disp srcampy.Display() resolution_list disp.get_display_res()逻辑优先尝试1920×1080如果 HDMI 不支持则自动选择小于等于 1080P 的最大分辨率返回disp_w/disp_h后续绘制框时用于坐标缩放4. 多进程并行后处理ParallelExectorpython运行self._pool multiprocessing.Pool(processesself.parallel_num, maxtasksperchild5) self.workers BoundedSemaphore(self.parallel_num)核心设计推理BPU 硬件与后处理CPU解耦主线程持续采集图像 调用 BPU 推理硬件异步子进程池并发运行 FCOS 解析、绘制逻辑BoundedSemaphore信号量限制最大并发数防止进程无限创建、内存暴涨maxtasksperchild5执行若干任务后重建子进程规避长期运行内存泄漏⚠️注意multiprocess 多进程在 RDK 上有坑全局变量跨进程不共享代码中image_counter使用multiprocessing.Value实现跨进程计数。5.run(outputs)单帧后处理核心函数python运行libpostprocess.FcosdoProcess(...) result_str get_Postprocess_result(...) data json.loads(result_str[14:])执行步骤将 BPU 输出 tensor 内存地址绑定到 C 结构体调用 C 库 FCOS 解码5 个 stride 层 8/16/32/64/128 特征图返回 json截取字符串[14:]跳过库内置前缀字符坐标缩放模型输入是512×512输出框坐标映射回 HDMI 显示分辨率disp_w×disp_hpython运行bbox scale_bbox(bbox, 512, 512, disp_w, disp_h)边界截断limit_display_cord防止框超出画面HDMI 叠加绘制python运行disp.set_graph_rect() # 绘制矩形框 disp.set_graph_word() # 绘制类别置信度文字box_color_ARGB转换成 HDMI 接口要求的 ARGB32 颜色格式6. 主程序初始化if __name__ __main__:6.1 加载模型python运行models dnn.load(../models/fcos_512x512_nv12.bin)*.bin地平线经过 HBIR 编译完成、适配 BPU 的模型文件输入格式NV12和相机输出格式一致无需 RGB 转换节省 CPU6.2 FCOS 后处理参数配置python运行fcos_postprocess_info.height 512 # 模型输入尺寸 fcos_postprocess_info.score_threshold 0.5 # 置信度阈值 fcos_postprocess_info.nms_threshold 0.6 # NMS阈值 fcos_postprocess_info.nms_top_k 5 # 单帧最多输出5个目标6.3 MIPI 相机打开python运行cam.open_cam(0, -1, -1, [w, disp_w], [h, disp_h],sensor_height,sensor_width)参数含义RDK 标准 API0camera 通道号[w, disp_w]两路输出分辨率一路512×512→ 送入 BPU 推理一路disp_w×disp_h→ HDMI 原始预览画面VIO 硬件完成图像缩放不需要 CPU 做 resize零拷贝优势6.4 HDMI 显示分层关键python运行disp.display(0, disp_w, disp_h) srcampy.bind(cam, disp) # 图层0原始相机画面 disp.display(3, disp_w, disp_h) # 图层3图形叠加层画框/文字地平线 HDMI 支持多图层叠加Layer0原始摄像头视频流Layer3OSD 图层绘制检测框透明叠加在视频上srcampy.bind(cam, disp)实现相机数据流直接硬件输送到 HDMI主线程不转发原始图像大幅降低 CPU 占用。7. 主循环采集链路python运行img cam.get_img(2, 512, 512) img np.frombuffer(img, dtypenp.uint8) outputs models[0].forward(img) parallel_exe.infer(output_array)cam.get_img(2,512,512)获取缩放后 512×512 NV12 图像参数2代表获取推理支路图像np.frombuffer把 C 内存块封装成 numpy 数组零拷贝不复制像素数据models[0].forward(img)提交任务到 BPU 硬件异步推理将推理输出送入进程池执行后处理主线程立刻继续取下一帧流水线运行8. FPS 统计逻辑python运行if image_counter.value 100: print(ffps: {100/(finish_time - start_time)})每累计 100 帧输出一次平均帧率multiprocessing.Value保证跨进程计数器同步。9. 信号退出处理python运行signal.signal(signal.SIGINT, signal_handler)捕获CtrlC置位is_stop标志退出 while 循环执行python运行cam.close_cam() disp.close()释放相机、HDMI 硬件资源防止硬件句柄泄漏。三、关键技术亮点地平线 RDK 平台特有NV12 原生输入MIPI 相机输出 NV12模型直接接收 NV12省去NV12→BGRCPU 颜色转换降低时延。VIO 硬件多路缩放 硬件 HDMI 图层叠加图像缩放、预览输出、OSD 绘制全部由 VPU 硬件完成CPU 仅负责调度和 AI 业务。零拷贝内存传输frombuffer、ctypes 直接传递物理内存地址像素数据不在用户态来回拷贝。BPU 推理与 CPU 后处理流水线并行多进程分离推理、解码绘制充分利用 X5 的 BPU 多核 CPU。四、结合你遇到问题的重点坑点清单numpy 版本限制hobot_dnn二进制包基于 numpy1.x 编译numpy 2.0 直接触发numpy.core.multiarray failed to import✅修复pip install numpy2.0 --force-reinstalllibpostprocess.so 路径依赖代码硬编码路径/usr/lib/libpostprocess.so升级镜像、容器环境如果缺少该库会直接崩溃。多进程 ctypes 注意事项硬件句柄cam/disp不能放到子进程操作本代码所有采集、硬件 API 全部在主线程子进程仅做解析绘制。分辨率匹配问题模型固定输入 512×512如果你更换其他尺寸模型必须同步修改FcosPostProcessInfo_t宽高参数。MIPI Sensor 适配当前默认 F37 传感器更换其他 MIPI 镜头需要修改设备树 / 相机 yaml 配置否则open_cam失败。五、常见可改造方向保存检测框图片在run()函数内增加 cv2 保存逻辑关闭 HDMI 输出改为 RTSP 网络推流替换 YOLO 系列模型需要更换对应的libpostprocess.so和后处理结构体去掉多进程简化为单线程适合低负载场景调试更简单