RDK S100使用USB摄像头推理YOLO26的模型帧数过低

这是我使用的推理脚本:

usb_camera_yolov26_detect.txt (15.8 KB)

这是运行脚本后的输出:

root@ubuntu:~# cd /mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/runtime/python/
root@ubuntu:/mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/runtime/python# python usb_camera_yolov26_detect.py
[UCP]: log level = 3
[UCP]: UCP version = 3.7.3
[VP]: log level = 3
[DNN]: log level = 3
[HPL]: log level = 3
[UCPT]: log level = 6
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (2075) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module source reported: Could not read from resource.
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (1053) open OpenCV | GStreamer warning: unable to start pipeline
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (616) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (2075) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module source reported: Could not read from resource.
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (1053) open OpenCV | GStreamer warning: unable to start pipeline
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (616) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
Opening video device: /dev/video0
Trying 640x480 with fourcc=1196444237…
Success! Camera now at 640x480 @ 30.00 FPS
Final camera: 640x480 @ 30.00 FPS
[BPU][[BPU_MONITOR]][281473461326464][INFO]BPULib verison(2, 2, 15)[f21ee84]!
[DNN] HBTL_EXT_DNN log level:6
[DNN]: 3.7.3_(4.2.11 HBRT)
Model loaded.
Loaded 5 classes: [‘obstacle’, ‘line’, ‘code’, ‘sign’, ‘p’]
Press ‘q’ to quit.
Read:3.6ms Infer:5.9ms Draw:0.1ms Show:0.3ms FPS:10.0
Read:3.6ms Infer:4.8ms Draw:0.3ms Show:0.2ms FPS:9.5
Read:3.7ms Infer:5.5ms Draw:0.3ms Show:0.2ms FPS:10.2
Read:3.6ms Infer:4.5ms Draw:0.2ms Show:0.3ms FPS:10.2
Read:3.6ms Infer:4.2ms Draw:0.1ms Show:0.3ms FPS:10.3
Read:3.8ms Infer:5.0ms Draw:0.3ms Show:0.3ms FPS:10.3
Read:3.8ms Infer:4.6ms Draw:0.2ms Show:0.2ms FPS:10.2
Read:3.6ms Infer:4.9ms Draw:0.2ms Show:0.3ms FPS:10.2
Read:3.6ms Infer:4.7ms Draw:0.2ms Show:0.3ms FPS:10.4
Read:3.6ms Infer:5.0ms Draw:0.2ms Show:0.2ms FPS:10.4
Read:3.6ms Infer:4.6ms Draw:0.2ms Show:0.3ms FPS:10.2
Read:3.5ms Infer:4.6ms Draw:0.2ms Show:0.3ms FPS:10.3

这是截屏:

存在的问题:按理说S100应该能跑满USB摄像头,30帧左右,但不知道为什么实际只有10帧左右

希望:希望能够提高帧数到30帧左右

我来帮你分析这个问题。先搜索一下社区是否有类似的 USB 摄像头帧数问题。

根据你的日志和输出,问题定位很清晰:瓶颈不在推理,而在摄像头数据读取。

核心结论

你的推理耗时仅 4-6ms(约160-250 FPS能力),但整体FPS只有10帧,原因是:

  • Read: 3.6ms - 摄像头读取耗时过长
  • GStreamer 警告表明摄像头初始化有问题
  • USB带宽或摄像头配置限制了实际帧率

排查步骤

1. 检查摄像头实际输出帧率

先确认摄像头本身是否能输出30fps:

# 使用 v4l2-ctl 测试摄像头原生帧率
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=640,height=480,pixelformat=YUYV --stream-mmap --stream-count=300 --stream-to=/dev/null

# 查看实际帧率统计
cat /dev/video0 | head -c 0  # 或者直接运行上面的命令看输出

2. 检查USB带宽和连接

# 查看USB设备详情
lsusb -t
lsusb -v -d <your_camera_vendor_id>:<product_id>

# 查看当前摄像头配置
v4l2-ctl --device=/dev/video0 --all | grep -E "Width|Height|Pixel|FPS"

3. 优化摄像头配置

根据社区经验,尝试以下配置:

# 方案1:强制使用 MJPEG 格式(带宽更低)
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=640,height=480,pixelformat=MJPG

# 方案2:调整 uvcvideo 驱动参数
sudo modprobe -r uvcvideo
sudo modprobe uvcvideo quirks=128

# 方案3:降低分辨率测试是否能到30fps
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=320,height=240,pixelformat=YUYV

4. 修改推理脚本

在你的 usb_camera_yolov26_detect.py 中优化摄像头打开方式:

# 原代码可能使用 GStreamer 后端,改为 V4L2 后端
cap = cv2.VideoCapture(0, cv2.CAP_V4L2)  # 强制使用 V4L2

# 设置摄像头参数
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))  # 或 'Y', 'U', 'Y', 'V'
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv2.CAP_PROP_FPS, 30)

# 验证设置
actual_fps = cap.get(cv2.CAP_PROP_FPS)
print(f"Actual camera FPS: {actual_fps}")

5. 使用预取缓冲

在推理循环前预读取几帧,避免第一帧延迟:

# 预读取 5 帧
for _ in range(5):
    ret, frame = cap.read()

# 然后在主循环中
while True:
    ret, frame = cap.read()
    if not ret:
        continue
    # ... 推理逻辑

可能的问题原因

根据社区类似案例:

  1. USB带宽不足:即使是USB 2.0,640x480@30fps的YUYV格式也需要约180Mbps,接近上限
  2. 摄像头锁定低帧率:某些摄像头在低分辨率下仍锁定30fps,但实际输出不稳定
  3. GStreamer 后端问题:OpenCV 默认使用 GStreamer,可能有兼容性问题
  4. USB口供电不足:尝试更换USB口或使用带供电的USB Hub

建议的测试顺序

  1. 先用 v4l2-ctl 确认摄像头原生能否达到30fps
  2. 尝试 MJPEG 格式降低带宽需求
  3. 修改脚本使用 CAP_V4L2 后端
  4. 检查是否使用了USB 3.0接口(S100有USB 3.0)

如果以上方法都无效,可能需要:

  • 更换支持更高帧率的摄像头
  • 使用官方推荐的摄像头型号
  • 检查是否有其他USB设备占用带宽

你可以先执行步骤1和2,把结果贴出来,我们再进一步分析。

直接把代码贴出来给AI分析,问题不是推理

也可以使用TROS 【技术分享】使用TROS 高效推理 Model Zoo 模型教程

#!/usr/bin/env python3

-- coding: utf-8 --

Copyright (c) 2025 D-Robotics Corporation

Licensed under the Apache License, Version 2.0

“”"
USB Camera real-time YOLO26 detection demo.
Supports auto-resolution probing.
“”"

import os
import sys
import cv2
import argparse
import numpy as np
import time

PROJECT_ROOT = “/mnt/ssd/rdk_model_zoo_s”
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)

from yolo26_det import YOLO26Detect, YOLO26Config
import utils.py_utils.file_io as file_io

def is_usb_camera(device):
try:
cap = cv2.VideoCapture(device)
if not cap.isOpened():
return False
cap.release()
return True
except:
return False

def find_first_usb_camera():
video_devices = [os.path.join(‘/dev’, dev) for dev in os.listdir(‘/dev’) if dev.startswith(‘video’)]
for dev in video_devices:
if is_usb_camera(dev):
return dev
return None

def draw_detection_results(img, boxes, cls_ids, scores, class_names, colors, draw_labels=True):
if len(boxes) == 0:
return img

for box, cls_id, score in zip(boxes, cls_ids, scores):
    x1, y1, x2, y2 = map(int, box)
    cls_id = int(cls_id)
    color = colors[cls_id % len(colors)]
    color_bgr = (color[2], color[1], color[0])

    cv2.rectangle(img, (x1, y1), (x2, y2), color_bgr, 2)

    if draw_labels:
        label = f"{class_names[cls_id] if class_names else cls_id}: {score:.2f}"
        (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)
        cv2.rectangle(img, (x1, y1 - th - 5), (x1 + tw, y1), color_bgr, -1)
        cv2.putText(img, label, (x1, y1 - 3), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)

return img

def try_camera_settings(cap, width, height, fps, fourcc=None):
“”“Try to set camera parameters and return actual values.”“”
if fourcc is not None:
cap.set(cv2.CAP_PROP_FOURCC, fourcc)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
cap.set(cv2.CAP_PROP_FPS, fps)
# read one frame to apply settings
ret, _ = cap.read()
if not ret:
return False, (0, 0, 0)
actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_fps = cap.get(cv2.CAP_PROP_FPS)
return True, (actual_w, actual_h, actual_fps)

def main():
parser = argparse.ArgumentParser()
parser.add_argument(‘–model-path’, default=“/mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/conversion/five/yolo26_det_bpu_nashe_640x640_nv12.hbm”)
parser.add_argument(‘–label-file’, default=“/mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/conversion/five/five.names”)
parser.add_argument(‘–priority’, type=int, default=0)
parser.add_argument(‘–bpu-cores’, nargs=‘+’, type=int, default=[0])
parser.add_argument(‘–score-thres’, type=float, default=0.25)
parser.add_argument(‘–nms-thres’, type=float, default=0.45)
parser.add_argument(‘–no-labels’, action=‘store_true’, help=‘Skip drawing labels for speed’)
opt = parser.parse_args()

# Find camera
video_device = find_first_usb_camera()
if video_device is None:
    print("No USB camera found.")
    sys.exit(-1)

print(f"Opening video device: {video_device}")
cap = cv2.VideoCapture(video_device, cv2.CAP_V4L2)
if not cap.isOpened():
    print("Failed to open camera")
    sys.exit(-1)

# Try multiple resolution and fourcc combinations
resolutions = [(640, 480), (320, 240), (640, 360), (424, 240)]
fourcc_candidates = [
    cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'),
    cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V'),
    None
]

success = False
for fourcc in fourcc_candidates:
    for w, h in resolutions:
        print(f"Trying {w}x{h} with fourcc={fourcc}...")
        ok, (aw, ah, afps) = try_camera_settings(cap, w, h, 30, fourcc)
        if ok and aw == w and ah == h:
            print(f"Success! Camera now at {aw}x{ah} @ {afps:.2f} FPS")
            success = True
            break
        else:
            print(f"Got {aw}x{ah} @ {afps:.2f} FPS (not as requested)")
    if success:
        break

if not success:
    print("Warning: Could not force desired resolution. Using current settings.")
    actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"Current camera: {actual_w}x{actual_h} @ {actual_fps:.2f} FPS")
else:
    actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"Final camera: {actual_w}x{actual_h} @ {actual_fps:.2f} FPS")

if actual_fps < 10:
    print("Frame rate is still low, trying to set FPS to 30 again...")
    cap.set(cv2.CAP_PROP_FPS, 30)
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"New FPS: {actual_fps:.2f}")

# Load model
if not os.path.exists(opt.model_path):
    print(f"Model not found: {opt.model_path}")
    cap.release()
    sys.exit(-1)

config = YOLO26Config(
    model_path=opt.model_path,
    score_thres=opt.score_thres,
    nms_thres=opt.nms_thres,
    classes_num=5,
    resize_type=1
)
model = YOLO26Detect(config)
model.set_scheduling_params(priority=opt.priority, bpu_cores=opt.bpu_cores)
print("Model loaded.")

# Load labels
class_names = []
if os.path.exists(opt.label_file):
    class_names = file_io.load_class_names(opt.label_file)
    print(f"Loaded {len(class_names)} classes: {class_names}")
else:
    class_names = [str(i) for i in range(80)]

colors = [
    (255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255),
    (0,255,255),(128,0,0),(0,128,0),(0,0,128),(128,128,0),
    (128,0,128),(0,128,128),(64,0,0),(0,64,0),(0,0,64),
    (64,64,0),(64,0,64),(0,64,64),(192,0,0),(0,192,0)
]

window_name = "YOLO26 Detection"
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
cv2.resizeWindow(window_name, 640, 480)

print("Press 'q' to quit.")
frame_count = 0
start_time = time.time()
fps_display = 0

while True:
    t0 = time.time()

    ret, frame = cap.read()
    if not ret:
        cap.release()
        cap = cv2.VideoCapture(video_device, cv2.CAP_V4L2)
        if not cap.isOpened():
            print("Cannot reconnect to camera, exiting.")
            break
        continue
    t_read = time.time()

    boxes, scores, cls_ids = model.predict(frame)
    t_infer = time.time()

    vis = draw_detection_results(
        frame.copy(),
        boxes,
        cls_ids,
        scores,
        class_names,
        colors,
        draw_labels=not opt.no_labels
    )
    t_draw = time.time()

    cv2.imshow(window_name, vis)
    t_show = time.time()

    frame_count += 1
    if frame_count % 10 == 0:
        end = time.time()
        fps_display = 10 / (end - start_time)
        start_time = end
        print(f"Read:{1000*(t_read-t0):.1f}ms  Infer:{1000*(t_infer-t_read):.1f}ms  "
              f"Draw:{1000*(t_draw-t_infer):.1f}ms  Show:{1000*(t_show-t_draw):.1f}ms  FPS:{fps_display:.1f}")

    if fps_display > 0:
        cv2.putText(vis, f"FPS: {fps_display:.1f}", (10,30),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

if name == “main”:
main()#!/usr/bin/env python3

-- coding: utf-8 --

Copyright (c) 2025 D-Robotics Corporation

Licensed under the Apache License, Version 2.0

“”"
USB Camera real-time YOLO26 detection demo.
Supports auto-resolution probing.
“”"

import os
import sys
import cv2
import argparse
import numpy as np
import time

PROJECT_ROOT = “/mnt/ssd/rdk_model_zoo_s”
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)

from yolo26_det import YOLO26Detect, YOLO26Config
import utils.py_utils.file_io as file_io

def is_usb_camera(device):
try:
cap = cv2.VideoCapture(device)
if not cap.isOpened():
return False
cap.release()
return True
except:
return False

def find_first_usb_camera():
video_devices = [os.path.join(‘/dev’, dev) for dev in os.listdir(‘/dev’) if dev.startswith(‘video’)]
for dev in video_devices:
if is_usb_camera(dev):
return dev
return None

def draw_detection_results(img, boxes, cls_ids, scores, class_names, colors, draw_labels=True):
if len(boxes) == 0:
return img

for box, cls_id, score in zip(boxes, cls_ids, scores):
    x1, y1, x2, y2 = map(int, box)
    cls_id = int(cls_id)
    color = colors[cls_id % len(colors)]
    color_bgr = (color[2], color[1], color[0])

    cv2.rectangle(img, (x1, y1), (x2, y2), color_bgr, 2)

    if draw_labels:
        label = f"{class_names[cls_id] if class_names else cls_id}: {score:.2f}"
        (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)
        cv2.rectangle(img, (x1, y1 - th - 5), (x1 + tw, y1), color_bgr, -1)
        cv2.putText(img, label, (x1, y1 - 3), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)

return img

def try_camera_settings(cap, width, height, fps, fourcc=None):
“”“Try to set camera parameters and return actual values.”“”
if fourcc is not None:
cap.set(cv2.CAP_PROP_FOURCC, fourcc)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
cap.set(cv2.CAP_PROP_FPS, fps)
# read one frame to apply settings
ret, _ = cap.read()
if not ret:
return False, (0, 0, 0)
actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_fps = cap.get(cv2.CAP_PROP_FPS)
return True, (actual_w, actual_h, actual_fps)

def main():
parser = argparse.ArgumentParser()
parser.add_argument(‘–model-path’, default=“/mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/conversion/five/yolo26_det_bpu_nashe_640x640_nv12.hbm”)
parser.add_argument(‘–label-file’, default=“/mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/conversion/five/five.names”)
parser.add_argument(‘–priority’, type=int, default=0)
parser.add_argument(‘–bpu-cores’, nargs=‘+’, type=int, default=[0])
parser.add_argument(‘–score-thres’, type=float, default=0.25)
parser.add_argument(‘–nms-thres’, type=float, default=0.45)
parser.add_argument(‘–no-labels’, action=‘store_true’, help=‘Skip drawing labels for speed’)
opt = parser.parse_args()

# Find camera
video_device = find_first_usb_camera()
if video_device is None:
    print("No USB camera found.")
    sys.exit(-1)

print(f"Opening video device: {video_device}")
cap = cv2.VideoCapture(video_device, cv2.CAP_V4L2)
if not cap.isOpened():
    print("Failed to open camera")
    sys.exit(-1)

# Try multiple resolution and fourcc combinations
resolutions = [(640, 480), (320, 240), (640, 360), (424, 240)]
fourcc_candidates = [
    cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'),
    cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V'),
    None
]

success = False
for fourcc in fourcc_candidates:
    for w, h in resolutions:
        print(f"Trying {w}x{h} with fourcc={fourcc}...")
        ok, (aw, ah, afps) = try_camera_settings(cap, w, h, 30, fourcc)
        if ok and aw == w and ah == h:
            print(f"Success! Camera now at {aw}x{ah} @ {afps:.2f} FPS")
            success = True
            break
        else:
            print(f"Got {aw}x{ah} @ {afps:.2f} FPS (not as requested)")
    if success:
        break

if not success:
    print("Warning: Could not force desired resolution. Using current settings.")
    actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"Current camera: {actual_w}x{actual_h} @ {actual_fps:.2f} FPS")
else:
    actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"Final camera: {actual_w}x{actual_h} @ {actual_fps:.2f} FPS")

if actual_fps < 10:
    print("Frame rate is still low, trying to set FPS to 30 again...")
    cap.set(cv2.CAP_PROP_FPS, 30)
    actual_fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"New FPS: {actual_fps:.2f}")

# Load model
if not os.path.exists(opt.model_path):
    print(f"Model not found: {opt.model_path}")
    cap.release()
    sys.exit(-1)

config = YOLO26Config(
    model_path=opt.model_path,
    score_thres=opt.score_thres,
    nms_thres=opt.nms_thres,
    classes_num=5,
    resize_type=1
)
model = YOLO26Detect(config)
model.set_scheduling_params(priority=opt.priority, bpu_cores=opt.bpu_cores)
print("Model loaded.")

# Load labels
class_names = []
if os.path.exists(opt.label_file):
    class_names = file_io.load_class_names(opt.label_file)
    print(f"Loaded {len(class_names)} classes: {class_names}")
else:
    class_names = [str(i) for i in range(80)]

colors = [
    (255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255),
    (0,255,255),(128,0,0),(0,128,0),(0,0,128),(128,128,0),
    (128,0,128),(0,128,128),(64,0,0),(0,64,0),(0,0,64),
    (64,64,0),(64,0,64),(0,64,64),(192,0,0),(0,192,0)
]

window_name = "YOLO26 Detection"
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
cv2.resizeWindow(window_name, 640, 480)

print("Press 'q' to quit.")
frame_count = 0
start_time = time.time()
fps_display = 0

while True:
    t0 = time.time()

    ret, frame = cap.read()
    if not ret:
        cap.release()
        cap = cv2.VideoCapture(video_device, cv2.CAP_V4L2)
        if not cap.isOpened():
            print("Cannot reconnect to camera, exiting.")
            break
        continue
    t_read = time.time()

    boxes, scores, cls_ids = model.predict(frame)
    t_infer = time.time()

    vis = draw_detection_results(
        frame.copy(),
        boxes,
        cls_ids,
        scores,
        class_names,
        colors,
        draw_labels=not opt.no_labels
    )
    t_draw = time.time()

    cv2.imshow(window_name, vis)
    t_show = time.time()

    frame_count += 1
    if frame_count % 10 == 0:
        end = time.time()
        fps_display = 10 / (end - start_time)
        start_time = end
        print(f"Read:{1000*(t_read-t0):.1f}ms  Infer:{1000*(t_infer-t_read):.1f}ms  "
              f"Draw:{1000*(t_draw-t_infer):.1f}ms  Show:{1000*(t_show-t_draw):.1f}ms  FPS:{fps_display:.1f}")

    if fps_display > 0:
        cv2.putText(vis, f"FPS: {fps_display:.1f}", (10,30),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

if name == “main”:
main()

@地瓜小助手_bot

问题定位确认

从你的日志看,推理不是瓶颈:

  • Infer: 4-6ms → 推理能力约 160-250 FPS :white_check_mark:
  • Read: 3.6ms 但整体 FPS 只有 10 → 摄像头读取是瓶颈

快速排查步骤

:one: 先确认摄像头原生能力

# 测试摄像头原生帧率(不运行推理,只读流)
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=640,height=480,pixelformat=YUYV --stream-mmap --stream-count=300 --stream-to=/dev/null 2>&1 | tail -5

# 查看摄像头支持的所有格式和帧率
v4l2-ctl --device=/dev/video0 --list-formats-ext

关键看输出:摄像头在 640x480 下是否真的支持 30fps?有些摄像头标称 30fps 但实际只有 10-15fps。


:two: 检查 USB 带宽和连接

# 查看 USB 拓扑和带宽分配
lsusb -t

# 查看摄像头当前配置
v4l2-ctl --device=/dev/video0 --all | grep -E "Width|Height|Pixel|FPS|Bandwidth"

# 检查是否插在 USB 3.0 口(S100 有 USB 3.0)
lsusb -v -d $(lsusb | grep Camera | awk '{print $6}') | grep -i "usb.*3\.0"

:three: 优化方案(按优先级尝试)

方案 A:使用 MJPG 格式(带宽降低约 70%)

# 先测试 MJPG 格式能否到 30fps
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=640,height=480,pixelformat=MJPG --stream-mmap --stream-count=300 --stream-to=/dev/null

如果上面测试能到 30fps,修改代码中的 fourcc 优先级:

# 把 MJPG 放在第一位尝试
fourcc_candidates = [
    cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'),  # 优先 MJPG
    cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V'),
    None
]

方案 B:调整 uvcvideo 驱动参数

# 卸载并重新加载驱动
sudo modprobe -r uvcvideo
sudo modprobe uvcvideo quirks=128

# 或者尝试其他 quirks 值
sudo modprobe uvcvideo quirks=0x80

方案 C:降低分辨率测试

# 测试 320x240 能否到 30fps
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=320,height=240,pixelformat=YUYV --stream-mmap --stream-count=300 --stream-to=/dev/null

如果低分辨率能到 30fps,说明是USB 带宽不足。


:four: 代码层面的优化

管理员提供的代码已经做了很好的优化,但还可以进一步:

# 添加摄像头预读取缓冲
for _ in range(5):
    cap.read()  # 丢弃前 5 帧

# 使用非阻塞读取
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)  # 只保留 1 帧缓冲

# 如果不需要显示,去掉 cv2.imshow 和 cv2.waitKey
# 显示操作也会消耗时间

社区相关案例参考

案例 问题 解决方案
s100p 三路 usb 相机提示带宽不够 USB 带宽不足 降低分辨率/帧率,使用 MJPG 格式
USB 摄像头帧率过低 X3 派 USB 摄像头 12fps 使用 TROS 的 usb camera pkg
摄像头问题 切换摄像头后帧率下降 摄像头硬件差异,更换支持高帧率的型号

建议的测试顺序

1. v4l2-ctl 测试原生帧率 → 确认摄像头硬件能力
2. 尝试 MJPG 格式 → 降低带宽需求
3. 检查 USB 口是否为 3.0 → 排除接口问题
4. 调整 uvcvideo quirks → 驱动层优化
5. 更换摄像头型号 → 硬件限制时无解

请提供以下信息方便进一步分析

# 执行后把输出贴出来
v4l2-ctl --device=/dev/video0 --list-formats-ext | head -50
lsusb -t
cat /sys/kernel/debug/usb/devices | grep -A 5 "Your Camera Name"

如果摄像头本身硬件只支持 10fps,那软件优化空间有限,建议更换支持 30fps 的摄像头型号(社区推荐:Logitech C270/C310 或官方推荐型号)。

我这几天也是在叫AI修这个问题RDK X5上部署YOLO26 以前最高可以到39帧数 后面重装系统就不行了只有10几帧 BPU使用率低了一半

@okc964593517 你的问题和楼上 S100 的情况类似,核心都是 BPU 利用率下降导致帧数暴跌。从 39 帧掉到 10 几帧、BPU 使用率减半,这通常是系统配置或软件环境问题,而非硬件故障。

核心结论

重装系统后性能下降的常见原因:

  1. BPU 驱动/固件版本不匹配
  2. CPU 频率被限制(节能模式)
  3. 模型量化配置错误
  4. Python 环境依赖缺失或版本不对

快速排查步骤

:one: 检查 BPU 驱动和固件状态

# 查看 BPU 驱动版本
hb_tool --version

# 查看 BPU 设备状态
cat /sys/class/hb_bpu/device/status

# 查看 BPU 频率是否正常
cat /sys/class/hb_bpu/device/frequency

# 检查是否有 BPU 错误日志
dmesg | grep -i bpu | tail -20

正常情况:BPU 频率应该在满频状态(X5 约 1GHz+),无 error 日志。


:two: 检查 CPU 频率和功耗模式

# 查看 CPU 频率
cat /proc/cpuinfo | grep "cpu MHz"

# 查看 CPU 调度策略
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# 如果是 powersave,改为 performance
sudo bash -c "echo performance > /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"

# 验证是否生效
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

关键:重装系统后可能默认是 powersave 模式,会严重限制性能。


:three: 验证模型和推理库版本

# 查看当前安装的 BPU 推理库版本
pip show bpu_infer_lib_x5

# 或者检查系统包
dpkg -l | grep horizon

# 查看模型文件信息
file /path/to/your/model.bin

对比:和你之前 39 帧时的版本对比,看是否有差异。


:four: 检查 Python 环境和依赖

# 查看 Python 版本
python3 --version

# 查看 OpenCV 版本
python3 -c "import cv2; print(cv2.__version__)"

# 查看 numpy 版本
python3 -c "import numpy; print(numpy.__version__)"

# 重新安装关键依赖(如果需要)
pip3 install --upgrade opencv-python numpy

:five: 使用官方 benchmark 工具测试

# 使用 hrt_model_exec 测试纯推理性能(不含摄像头读取)
hrt_model_exec perf --model_path /path/to/your/model.bin --thread_num 8

# 或者使用官方 benchmark 脚本
cd /mnt/ssd/rdk_model_zoo_s/samples/Vision/ultralytics_yolo26/
bash 03_benchmark.sh

对比数据:如果 benchmark 结果正常(~40 FPS),说明是摄像头读取或数据预处理的问题;如果 benchmark 也低,说明是BPU 或系统配置问题。


针对性解决方案

方案 A:恢复 CPU 性能模式(最常见)

# 创建开机自启脚本
sudo bash -c "cat > /etc/rc.local << 'EOF'
#!/bin/bash
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor
exit 0
EOF"

sudo chmod +x /etc/rc.local

方案 B:重新安装 BPU 驱动和工具链

# 卸载旧版本
pip3 uninstall bpu_infer_lib_x5

# 清理缓存
pip3 cache purge

# 重新安装(使用官方源)
pip3 install bpu_infer_lib_x5 -i http://sdk.d-robotics.cc:8080/simple/ --trusted-host sdk.d-robotics.cc

# 或者使用 apt 安装系统包
sudo apt update
sudo apt install --reinstall horizon-bpu-tools

方案 C:检查模型量化配置

如果你是自己量化的模型,检查:

  • 校准数据集是否和之前一致
  • 量化参数(如输入尺寸、格式)是否正确
  • ONNX 模型是否和之前版本一致
# 使用官方工具检查模型信息
hb_mapper checker --model /path/to/your/model.bin

社区相关案例

案例 问题 解决方案
X5 BPU 负载测试 BPU 利用率仅 11-12% 检查数据预处理瓶颈
我训练的模型无法正确百分比使用 bpu BPU 占用低 移除 CPU 算子,优化模型结构
X3 与 X5 性能测试的疑问 性能不达标 CPU 频率限制问题

请提供以下信息方便进一步诊断

# 执行后把输出贴出来
hb_tool --version
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
pip3 show bpu_infer_lib_x5 | grep Version
hrt_model_exec perf --model_path /path/to/your/model.bin --thread_num 8 | grep FPS

如果以上都正常,建议:

  1. 对比重装系统前后的 /etc/version 版本号
  2. 检查是否有其他后台进程占用资源(htop)
  3. 尝试使用官方提供的预训练模型测试,排除模型问题

大多数情况下,CPU 节能模式是罪魁祸首,优先检查这个!