You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Orin NX平台OpenCV无法同时运行4台1080p 30fps相机求助

相机多开与设备节点问题排查

问题背景

在Jetson Orin NX(配备4个USB3.0接口)上运行测试代码时,遇到两个核心问题:

  1. 4台相机均可通过openCamera()正常开启(未返回-1),但最多仅2台能输出图像;且所有相机在1080p分辨率下帧率极低,手动设置的30fps完全无效。
  2. 仅连接4台相机,执行ls /dev/video*却显示8个设备节点,因此代码中用for i in range(0,8,2)遍历相机,需明确原因。

已尝试操作:

  • 注释分辨率设置代码后,4台相机可输出640*480 30fps图像,但不符合需求;
  • 单独开启每台相机均可实现1080p 30fps输出;
  • 已排除供电与USB带宽问题。

最终需求:在多线程C++程序中实现4台相机同时以1080p 30fps运行。

测试代码

#!/usr/bin/env python
# coding=utf8

import cv2
import time
def openCamera(cam_index = 0):
    cap = cv2.VideoCapture(cam_index)

    if cap.isOpened():
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) #1
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) #2
        cap.set(cv2.CAP_PROP_FPS, 30) #3
        cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
        return cap
    else:
        print(str(cam_index) + "launch failed")
        return -1
        
cam_set = []

for i in range(0,8,2): #4
    temp = openCamera(i)
    if temp != -1:
        cam_set.append(temp) 
print("have ", len(cam_set),"cams running")

while(cam_set):
    window_cnt = 0
    for k in cam_set:
        
        cap = k
        ret, frame = cap.read()
        if ret:
            cv2.imshow(str(window_cnt+1), frame)
            window_cnt += 1
            cv2.waitKey(1)
else:
    print("camera launched failed")

for j in cam_set:
    j.release()
cv2.destroyAllWindows()

问题解答

一、为什么4台相机对应8个/dev/video节点?

Linux下的USB相机通常会生成多个设备节点:

  • 主节点(偶数编号,如video0、video2):负责视频流捕获;
  • 辅助节点(奇数编号,如video1、video3):用于设备控制、静态图像捕获或音频同步等辅助功能。
    每台相机对应2个节点是正常现象,你可以通过v4l2-ctl --list-devices命令查看每个节点对应的具体功能,确认哪些是用于视频捕获的主节点。

二、实现4台相机同时1080p 30fps运行的方案

1. 先验证相机的实际支持参数

用v4l2-ctl -d /dev/videoX --list-formats-ext命令(X为相机节点号)查看相机明确支持的分辨率、帧率和编码格式,确认1080p 30fps的MJPG格式是相机原生支持的(部分相机仅在特定格式下提供高帧率)。

2. 调整OpenCV参数设置顺序

OpenCV中参数设置顺序会影响生效结果,必须先设置编码格式,再设置分辨率和帧率,否则可能导致设置无效。修改openCamera函数:

def openCamera(cam_index = 0):
    cap = cv2.VideoCapture(cam_index)

    if cap.isOpened():
        # 先设置编码格式
        cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
        # 再设置分辨率和帧率
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
        cap.set(cv2.CAP_PROP_FPS, 30)
        # 验证实际生效参数
        print(f"Camera {cam_index}:")
        print(f"  实际分辨率: {cap.get(cv2.CAP_PROP_FRAME_WIDTH)}x{cap.get(cv2.CAP_PROP_FRAME_HEIGHT)}")
        print(f"  实际帧率: {cap.get(cv2.CAP_PROP_FPS)}")
        return cap
    else:
        print(f"{cam_index} launch failed")
        return -1

3. 改用多线程捕获帧

当前单线程循环读取所有相机帧的方式会导致相机间互相阻塞,高分辨率下无法及时处理所有帧,进而引发帧率下降或部分相机无输出。为每个相机创建独立线程负责捕获:

import cv2
import threading
import time

class CameraThread(threading.Thread):
    def __init__(self, cam_index):
        super().__init__()
        self.cam_index = cam_index
        self.cap = None
        self.running = False

    def run(self):
        self.cap = cv2.VideoCapture(self.cam_index)
        if not self.cap.isOpened():
            print(f"Camera {self.cam_index} 启动失败")
            return
        # 按正确顺序设置参数
        self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
        self.cap.set(cv2.CAP_PROP_FPS, 30)
        self.running = True
        while self.running:
            ret, frame = self.cap.read()
            if ret:
                cv2.imshow(f"Camera {self.cam_index}", frame)
                cv2.waitKey(1)
            else:
                time.sleep(0.01)

    def stop(self):
        self.running = False
        if self.cap:
            self.cap.release()

# 启动所有相机线程
threads = []
for i in range(0,8,2):
    thread = CameraThread(i)
    thread.start()
    threads.append(thread)

# 等待退出
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    for thread in threads:
        thread.stop()
    cv2.destroyAllWindows()

C++版本可参考相同逻辑,用std::thread为每个相机创建独立捕获线程。

4. 利用Jetson硬件加速捕获

Jetson平台上,使用GStreamer管道替代原生OpenCV捕获,可利用硬件解码能力提升性能,减少CPU占用:

# 替换cv2.VideoCapture的初始化方式
cap = cv2.VideoCapture(
    "v4l2src device=/dev/videoX ! image/jpeg,width=1920,height=1080,framerate=30/1 ! jpegdec ! videoconvert ! appsink", 
    cv2.CAP_GSTREAMER
)

5. 确认USB总线状态

用lsusb -t命令查看USB总线带宽使用情况,确认4台相机同时运行时无隐性带宽瓶颈(1080p 30fps MJPG单相机带宽约22Mbps,4台总带宽远低于USB3.0上限,此步骤仅作验证)。

内容的提问来源于stack exchange,提问作者Daniel Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:26:17