![[具身智能-633]:RDK X5 MIPI 摄像头 + FCOS 目标检测完整代码逐段深度解析](http://pic.xiahunao.cn/yaotu/[具身智能-633]:RDK X5 MIPI 摄像头 + FCOS 目标检测完整代码逐段深度解析)
RDK X5 MIPI 摄像头 FCOS 目标检测完整代码逐段深度解析整体工程定位这是地平线官方标准流水线MIPI Sensor(IMX415/IMX477) → hobot_vio(srcampy) ISP采集NV12裸流 → hobot_dnn_rdkx5 BPU推理FCOS → libpostprocess.so C后处理 → HDMI叠加框渲染显示和之前test_resnet18.py最大区别不再使用OpenCV VideoCapture 读取摄像头USB摄像头改用libsrcampy地平线 VIO 采集库专门适配 MIPI CSI任务从 ImageNet 分类 →FCOS Anchor-Free 目标检测COCO 80 类引入多进程并发后处理防止后处理阻塞采集流水线硬件通路摄像头数据流直通 HDMIAI 框是图形层叠加不会修改原始视频流一、模块导入部分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 dnnhobot_vio / hobot_vio_rdkx5RDK X3 / X5 的 MIPI ISP 采集 SDK专门读取板载 CSI 摄像头直接输出NV12 内存裸数据无需BGR2NV12 转换节省大量 CPU❗不要和cv2.VideoCapture混用读取 MIPIhobot_dnn系列和之前分类代码完全一致BPU 推理 APImultiprocessing BoundedSemaphore实现多进程并行后处理Python GIL 限制线程无法真正并行计算后处理重负载使用多进程二、ctypes C 结构体区域和分类代码对比重点python运行class FcosPostProcessInfo_t(ctypes.Structure): _fields_ [ (height,ctypes.c_int), # 模型输入尺寸 h512 (width,ctypes.c_int), # 模型输入尺寸 w512 (ori_height,ctypes.c_int), # 原图HDMI画面分辨率 (ori_width,ctypes.c_int), (score_threshold,ctypes.c_float), # 置信度阈值0.5 (nms_threshold,ctypes.c_float), # NMS IOU阈值0.6 (nms_top_k,ctypes.c_int), (is_pad_resize,ctypes.c_int) # 0拉伸resize ]✅ 对比分类结构体差异 分类ClassificationPostProcessInfo_t检测FcosPostProcessInfo_t注意此结构体缺少 FCOS 必须的 strides、class_num 参数参数在底层 libpostprocess 写死适配这个 512 FCOS 模型自定义训练模型需要扩展结构体python运行libpostprocess ctypes.CDLL(/usr/lib/libpostprocess.so) get_Postprocess_result libpostprocess.FcosPostProcess get_Postprocess_result.argtypes [ctypes.POINTER(FcosPostProcessInfo_t)] get_Postprocess_result.restype ctypes.c_char_p绑定 C 库 FCOS 后处理入口对应分类的ClassificationPostProcess。三、显示分辨率自动适配函数get_display_res()python运行def get_display_res(): disp srcampy.Display() resolution_list disp.get_display_res() # 优先匹配1920×1080不匹配自动选择支持的更小分辨率作用查询 HDMI 显示器支持分辨率避免 disp.display () 参数不兼容黑屏。 全局变量disp_w, disp_h HDMI 画面输出分辨率原始相机画面分辨率。四、辅助工具函数1.scale_bbox(bbox, input_w, input_h, output_w, output_h)模型输入是512×512相机原始画面disp_w × disp_h1920×1080FCOS 后处理解码出的框坐标是512 图坐标系该函数做坐标缩放映射回原图画面关键is_pad_resize0拉伸缩放如果设置 1等比例 padding坐标换算必须额外补偿 padding 偏移2.limit_display_cord()防止边框坐标超出画面边界避免 HDMI 渲染接口报错越界。3.get_classes()COCO 80 类别名称列表和 FCOS 预训练模型匹配。五、并行执行器 ParallelExector【重点设计】python运行class ParallelExector(object): def __init__(self, counter, parallel_num4): self._pool multiprocessing.Pool(processes4) self.workers BoundedSemaphore(4) def infer(self, output): self.workers.acquire() self._pool.apply_async(funcrun,args(output, ),callbackself.task_done)设计目的采集、BPU 推理是高速流水线后处理 绘制渲染耗时波动大如果主线程直接执行 run ()摄像头取帧会阻塞、丢帧。 方案 主线程只做取图 → forward 推理 把输出 tensor 扔给进程池异步执行后处理。BoundedSemaphore限制最大并发进程防止瞬间创建大量进程内存溢出。⚠️多进程坑全局变量在子进程是副本不要在 run 里修改主线程资源。HDMI 显示接口属于共享硬件并发绘制要注意冲突。六、核心后处理函数 run (outputs)python运行strides [8, 16, 32, 64, 128] # FCOS FPN五层步长 for i in range(len(strides)): libpostprocess.FcosdoProcess(output_tensors[i], output_tensors[i 5], output_tensors[i 10], ctypes.pointer(fcos_postprocess_info), i)FCOS 模型输出排布规则至关重要fcos_512x512_nv12.bin一共15 路输出 Tensor5 层 FPN (P3~P7)每层 3 个分支cls(分类)、reg(偏移ltrb)、centerness(中心度)索引排布plaintext0~4: cls 5~9: reg 10~14: centerness循环 i0~4逐层送入 C 后处理。数据流将推理 outputs 的 numpy 内存指针赋值给hbDNNTensor_t结构体C 库执行反量化 → 解码 ltrb 框 → scorecls*centerness → 阈值过滤 → NMS返回 JSON 字符串result_str[14:]截断头部前缀和分类[25:]类似库版本不同前缀长度不一样HDMI 图形叠加不是 OpenCV 绘图python运行disp.set_graph_rect() # 绘制矩形框 disp.set_graph_word() # 绘制类别置信度文字特点图层叠加OSD不修改原始 NV12 视频帧原始视频流继续直通 HDMI参数末尾 1/01刷新整个 OSD 图层0增量绘制颜色使用 ARGB 格式直接调用底层 VIO 图形驱动CPU 开销极低七、主流程 main 函数流水线骨架1. 加载 FCOS 模型python运行models dnn.load(../models/fcos_512x512_nv12.bin)模型输入尺寸固定512×512输入格式 NV12。2. 初始化 FCOS 后处理结构体python运行fcos_postprocess_info.height 512 fcos_postprocess_info.width 512 fcos_postprocess_info.ori_height disp_h fcos_postprocess_info.ori_width disp_w fcos_postprocess_info.score_threshold 0.5 fcos_postprocess_info.nms_threshold 0.6 fcos_postprocess_info.is_pad_resize 03. MIPI 摄像头、HDMI 显示初始化srcampy 核心pythonMIPI 摄像头运行cam srcampy.Camera() cam.open_cam(0, -1, -1, [w, disp_w], [h, disp_h],sensor_height,sensor_width)参数解读0camera 通道号RDK X5 CSI0 / CSI1 对应 0、1对应 /dev/video0/video1[w, disp_w]一路输出 512送入 BPU 推理一路输出 1920×1080直通 HDMI ISP 硬件双通路输出硬件同时输出两路图像 通路 A缩放 512×512 NV12 → 给 AI 推理 通路 B原始 1080P NV12 → 直接送到 HDMI 显示 ✅ 巨大优势硬件 ISP 完成缩放CPU 零消耗pythonHDMI 显示运行disp srcampy.Display() disp.display(0, disp_w, disp_h) srcampy.bind(cam, disp) # 将摄像头原始视频流绑定HDMI直出 disp.display(3, disp_w, disp_h) # 切换图层3用于绘制检测框OSDsrcampy.bind(cam, disp)摄像头原始数据流硬件通路直连 HDMI不需要 CPU 转发画面延迟极低。4. 主循环核心流水线python运行while not is_stop: img cam.get_img(2, 512, 512) # 获取512×512 NV12 buffer img np.frombuffer(img, dtypenp.uint8) outputs models[0].forward(img) # BPU推理 parallel_exe.infer(output_array) # 异步投递后处理cam.get_img(2,512,512)参数2选择 ISP 输出的 512 分辨率通路直接拿到 NV12 字节流。对比之前图片测试代码 旧代码BGR → cv2.resize → bgr2nv12_opencv ()CPU 大量运算 本代码ISP 硬件输出 NV12完全消除图像格式转换 CPU 开销。八、整套流水线时序图plaintextMIPI Sensor → ISP ├─通路11080P NV12 → 硬件bind直连HDMI原始画面 └─通路2硬件缩放512×512 NV12 → cam.get_img读取 → np.frombuffer → dnn.forward(BPU推理) → 扔进多进程池异步run() ↳ ctypes调用libpostprocess FCOS后处理 ↳ 解析框坐标、缩放映射原图 ↳ disp OSD叠加矩形与文字九、高频踩坑清单工程实操重点1. 摄像头通道cam.open_cam(0,...)→ CSI0改为 1 读取 CSI1实现双摄。 ⚠️不要同时使用 srcampy cv2.VideoCapture 读取同一个 MIPI 通道会抢占驱动2. 模型与分辨率绑定fcos_512x512_nv12.bin固定输入 512不要强行送入其他尺寸 NV12。3. is_pad_resize 坐标大坑0拉伸 resize当前代码1等比例缩放 上下 / 左右填充黑边 如果修改为 1scale_bbox必须增加 padding 补偿逻辑否则框位置偏移4. JSON 字符串切片python运行data json.loads(result_str[14:])libpostprocess 版本不同前缀长度变化切片数字报错就会 json 解析失败。5. 多进程隐患进程池频繁创建销毁会有内存泄漏长时间 7×24 运行产品需要增加进程重启逻辑。6. 输出 tensor 顺序不能乱FCOS 输出必须严格cls [0-4], reg [5-9], centerness [10-14]onnx 导出顺序一旦颠倒后处理直接失效。7. HDMI OSD 图层冲突多个进程同时调用set_graph_rect会出现框闪烁尽量把所有绘制收敛到同一个进程。十、和之前代码横向对比总结表格项目test_resnet18.py图片分类本 MIPI-FCOS 检测代码图像来源本地图片 cv2.imreadMIPI CSI hobot_vio ISP 硬件采集格式转换CPU 执行 BGR→NV12ISP 直接输出 NV12无 CPU 转换任务ImageNet1k 分类FCOS COCO 80 类目标检测模型输出单一路 logits15 路 tensorcls/reg/centerness 五层 FPN后处理执行主线程同步阻塞多进程异步并发防丢帧画面显示无显示硬件 HDMI 直出 OSD 叠加检测框采集方式离线图片实时视频流循环采集十一、改造拓展方向支持双摄 CSI0CSI1 两路 FCOS 并行检测把 FCOS 模型更换骨干VarGConvNet/MobileNetV1 轻量化版本去掉 libpostprocess.soPython 实现 FCOS 后处理方便自定义数据集增加保存检测截图、RTSP 推流增加 ROI 感兴趣区域过滤只识别画面指定区域目标。