ELF-RV1126B YOLOv8官方例程目标检测部署验证
- 金融市场
- 2026-04-04
- 5015
基于官方资料包例程完成图片或摄像头目标检测、结果显示和 FPS记录。
1.实验目的
•验证 YOLOv8官方例程能在 ELF-RV1126B上正确启动并调用 NPU推理。
•验证摄像头节点、模型路径和例程关键参数配置是否正确。
•记录目标检测效果和平均 FPS,形成可归档的 AI部署验收结果。
2.前置条件与目录要求
1)板端准备以下内容:main_camera_fps_v8.py、rknnpool 目录、func 目录、rknnModel/best.rknn。(注意所有文件夹创建在/dev/mmcblk0p8分区的/userdata下,默认安装路径是在/dev/root分区的home/elf下,会导致/dev/root的空间满了)

在大分区创建缓存目录
mkdir -p /userdata/.cache/pip
创建软链接,让系统以为它还在原位,其实存在了 49G的分区里
ln -s /userdata/.cache/pip ~/.cache/pip
2)若使用摄像头,请先确认摄像头已经被系统识别:这里使用的是HIKVISION的USB摄像头。
| 无摄像头时的处理:如果暂时没有接摄像头,可以先把官方例程改为读取静态图片或视频文件,先验证“模型加载 +前后处理 +推理输出”链路;但正式验收时,仍建议补做摄像头路径测试。 |
步骤 2.1 激活 Python 环境并安装 OpenCV(接上一个实验)
| cd /userdata/rknn_test python3 -m venv venv source venv/bin/activate pip install rknn-toolkit-lite2==2.3.2 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple |
步骤 2.2 检查当前摄像头节点
| v4l2-ctl --list-devices v4l2-ctl --list-formats-ext -d /dev/video52
|
说明:请把 /dev/videoXX替换为你的实际摄像头节点,这是video52。若是 UVC摄像头,节点往往位于较靠后的 /dev/video号;若是 OV13855,则可参考官方手册中的摄像头测试章节确认节点(这里使用的是HIKVISION的USB摄像头,1080p USB)。
3. 关键目录与参数检查
| 检查项 | 建议内容 | 备注 |
|---|---|---|
| 主程序 | main_camera_fps_v8.py | 建议直接使用官方资料包版本 |
| 模型目录 | ./rknnModel/best.rknn | 模型路径要与脚本一致 |
| 依赖目录 | rknnpool / func | 保持与主程序在同一工程目录下 |
| 摄像头节点 | /dev/videoXX | 必须按实际节点修改 |
| 线程 | TPEs = 1~2初测,稳定后再提高 | 先求稳定,再追求 FPS |
步骤 3.1 官方例程中的关键参数示例(按需修改,这里用X11转发至Mobaxterm进行显示)
| import os #抑制 Qt字体警告 os.environ["QT_LOGGING_RULES"] = "qt.qpa.fonts.warning=false" import cv2 import time from rknnpool.rknnpool_ld import rknnPoolExecutor from func.func_yolov8_optimize import myFunc # ---------------性能采集工具函数 --------------- def get_npu_load(): """读取 RV1126B NPU负载百分比,返回字符串如 '45%'或 'N/A'""" paths = [ "/sys/kernel/debug/rknpu/load", "/sys/class/devfreq/ffbc0000.npu/load", ] for p in paths: try: with open(p, "r") as f: text = f.read().strip() #取第一行 first_line = text.split("n")[0].strip() #格式可能是 "NPU load: 4%"或 "45%"或 "45 / 100" if "%" in first_line: #提取百分比数字,如 "NPU load: 4%" -> "4%" import re m = re.search(r'(d+)s*%', first_line) if m: return f"{m.group(1)}%" return first_line parts = first_line.replace("/", " ").split() if len(parts) >= 2: return f"{int(int(parts[0]) * 100 / int(parts[1]))}%" return first_line except (FileNotFoundError, PermissionError, ValueError): continue return "N/A" def get_cpu_usage(prev_stat): """ 通过 /proc/stat两次采样差值计算 CPU使用率。 prev_stat:上次采样的 (idle, total)元组,首次传 None。 返回 (cpu_percent_str, current_stat) """ try: with open("/proc/stat", "r") as f: line = f.readline() #第一行 "cpu ..." parts = [int(x) for x in line.split()[1:]] idle = parts[3] total = sum(parts) if prev_stat is None: return ("--", (idle, total)) d_idle = idle - prev_stat[0] d_total = total - prev_stat[1] if d_total == 0: return ("0.0%", (idle, total)) usage = (1.0 - d_idle / d_total) * 100 return (f"{usage:.1f}%", (idle, total)) except (FileNotFoundError, PermissionError, ValueError): return ("N/A", prev_stat) def draw_osd(frame, fps_str, cpu_str, npu_str): """在帧左上角绘制半透明黑底 +性能信息""" lines = [ f"FPS : {fps_str}", f"CPU : {cpu_str}", f"NPU : {npu_str}", ] font = cv2.FONT_HERSHEY_SIMPLEX scale, thickness = 0.7, 2 y0, dy = 25, 30 #半透明背景 overlay = frame.copy() cv2.rectangle(overlay, (5, 5), (220, y0 + dy * len(lines) - 10), (0, 0, 0), -1) cv2.addWeighted(overlay, 0.5, frame, 0.5, 0, frame) for i, text in enumerate(lines): cv2.putText(frame, text, (10, y0 + i * dy), font, scale, (0, 255, 0), thickness) return frame # --------------- X11显示检测 --------------- #修复 sudo下 X11授权丢失问题: # sudo会切换到 root,但 root没有原用户的 .Xauthority令牌 sudo_user = os.environ.get("SUDO_USER") if sudo_user: #从原用户的 home目录继承 .Xauthority sudo_home = os.path.expanduser(f"~{sudo_user}") xauth_file = os.path.join(sudo_home, ".Xauthority") if os.path.exists(xauth_file) and "XAUTHORITY" not in os.environ: os.environ["XAUTHORITY"] = xauth_file print(f"已设置 XAUTHORITY={xauth_file} (来自用户 {sudo_user})") if "DISPLAY" not in os.environ: print("警告:未检测到 DISPLAY环境变量") print("请确保 MobaXterm已开启 X11转发 (ssh -X / -Y)") print("尝试设置 DISPLAY=localhost:10.0继续...") os.environ["DISPLAY"] = "localhost:10.0" # ---------------初始化 --------------- cap = cv2.VideoCapture("/dev/video52") modelPath = "./rknnModel/best.rknn" TPEs = 8 os.makedirs("output", exist_ok=True) if not cap.isOpened(): print("错误:无法打开摄像头 /dev/video52") os.system("ls -l /dev/video*") exit(-1) print(f"摄像头已打开,分辨率: {int(cap.get(3))}x{int(cap.get(4))}") pool = rknnPoolExecutor( rknnModel=modelPath, TPEs=TPEs, func=myFunc ) #预填充推理流水线 if cap.isOpened(): for i in range(TPEs + 1): ret, frame = cap.read() if not ret: print(f"错误:第 {i}帧读取失败") cap.release() pool.release() exit(-1) pool.put(frame) # --------------- X11窗口 (带降级) --------------- WINDOW_NAME = "YOLOv8 - RV1126B" use_x11 = False try: cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.resizeWindow(WINDOW_NAME, 640, 480) use_x11 = True print("X11显示窗口已创建") except cv2.error as e: print(f"警告: X11窗口创建失败 ({e})") print("将以无头模式运行 (仅保存图片到 output/)") print("提示:请尝试以下命令解决 X11问题:") print(f" 1.用普通用户运行: python3 {os.path.basename(__file__)}") print(f" (先执行: sudo chmod 666 /dev/video52)") print(f" 2.或传递 X11授权: sudo -E XAUTHORITY=$HOME/.Xauthority ./venv/bin/python3 {os.path.basename(__file__)}") print(f" 3.或允许 root访问 X11: xhost +local:root") # ---------------推理主循环 --------------- # X11转发带宽有限,跳帧显示以避免拖慢推理帧率 #每 X11_SKIP帧才做一次 imshow,其余帧只推理不显示 X11_SKIP = 10 print("开始推理循环,按 'q'或 Ctrl+C停止...") frames, loopTime, initTime = 0, time.time(), time.time() fps_display = "..." #预采样 CPU一次,使首次输出不是 "--" cpu_display, cpu_stat = get_cpu_usage(None) npu_display = get_npu_load() last_good_frame = None try: while cap.isOpened(): ret, frame = cap.read() if not ret: print(f"第 {frames + 1}帧读取失败,退出") break pool.put(frame) frame, flag = pool.get() if not flag: print(f"第 {frames + 1}帧推理失败,退出") break frames += 1 last_good_frame = frame #每30帧更新性能数据 if frames % 30 == 0: elapsed = time.time() - loopTime fps_val = 30 / elapsed if elapsed > 0 else 0 fps_display = f"{fps_val:.1f}" npu_display = get_npu_load() cpu_display, cpu_stat = get_cpu_usage(cpu_stat) loopTime = time.time() #保存图片 save_path = f"output/result_{frames}.jpg" cv2.imwrite(save_path, frame) print(f"FPS: {fps_display} CPU: {cpu_display} NPU: {npu_display} | 已保存: {save_path}") # OSD叠加 draw_osd(frame, fps_display, cpu_display, npu_display) #通过 X11显示 (跳帧以减少 X11转发开销) if use_x11 and frames % X11_SKIP == 0: cv2.imshow(WINDOW_NAME, frame) if cv2.waitKey(1) & 0xFF == ord('q'): print("按 'q'退出") break except KeyboardInterrupt: print("n手动停止") finally: if last_good_frame is not None: cv2.imwrite("output/result_latest.jpg", last_good_frame) print(f"最后一帧已保存: output/result_latest.jpg") if frames > 0: total_time = time.time() - initTime print(f"总帧数: {frames} 总平均帧率: {frames / total_time:.2f}") else: print("未处理任何帧") cap.release() pool.release() if use_x11: cv2.destroyAllWindows() |
步骤 3.2 运行 YOLOv8 官方例程
| sudo ./venv/bin/python3 main_camera_fps_v8.py 可以设置跳帧X11_SKIP =15(X11转发是瓶颈)
|
4. 预期结果与判定标准
| 检查项 | 成功标志 | 判定 |
|---|---|---|
| 程序启动 | 无 import错误、无模型路径错误 | 通过 / 不通过 |
| 摄像头打开 | 可正常读取画面或至少确认节点可用 | 通过 / 不通过 |
| 目标检测 | 画面中能看到检测框 /类别结果 | 通过 / 不通过 |
| 性能记录 | 能够记录平均 FPS或等效性能指标 | 通过 / 不通过 |
5. 常见问题与排查
•程序启动失败:先检查 main_camera_fps_v8.py、rknnpool、func 和 rknnModel 目录是否完整。
•画面不出图:优先检查 /dev/videoXX是否写对,摄像头是否被 v4l2-ctl正确识别。
•SSH下无窗口:这通常是显示环境问题,不一定是模型推理失败;建议接本地显示器,或改为保存图片/日志方式验证。
•FPS偏低:先把 TPEs调到 1~2保证稳定,再逐步提升;同时避免在高分辨率显示输出下直接判断模型性能。
•检测结果为空:检查 best.rknn是否与当前前处理 /后处理函数匹配,避免脚本模型版本不对应。







