【问题标题】:Capturing multiple webcams (uvcvideo) with OpenCV on Linux在 Linux 上使用 OpenCV 捕获多个网络摄像头 (uvcvideo)
【发布时间】:2012-04-04 14:57:15
【问题描述】:

我正在尝试在 Ubuntu 11.10 上使用 OpenCV 2.1 同时从 3 个 Logitech Webcam Pro 900 设备流式传输图像。为这些加载了 uvcvideo 驱动程序。

捕获两个设备工作正常,但是三个我遇到第三个空间不足错误:

libv4l2: error turning on stream: No space left on device

我似乎遇到了这个问题: http://renoirsrants.blogspot.com.au/2011/07/multiple-webcams-on-zoneminder.html 并且我尝试使用 quirks=128 (或几乎任何其他二次幂值)技巧,但无济于事。我还尝试在另一台带有两个 USB 2.0 集线器的机器上将两个摄像头连接到一个,将第三个摄像头连接到第二个,这导致了同样的问题。我大致如下初始化(使用 N 个摄像头,因此结果实际上是放入 STL 向量中):

cv::VideoCapture cap0(0); //(0,1,2..)

并尝试以循环方式捕获所有摄像机

cap0.retrieve(frame0);

这适用于 N=2 摄像机。当我设置 N=3 时,第三个窗口打开但没有图像出现,并且控制台充满了 V4L2 错误。同样,当我设置 N=2 并尝试在 say Cheese(简单的网络摄像头捕获应用程序)中打开第三个摄像头时,这也不起作用。

现在来了大但是:通过启动三个实例尝试 guvcview 后,我能够一次查看三个摄像头(在帧速率或相关方面没有问题),所以它似乎不是硬件问题。我认为我应该设置一些属性,但我不确定那是什么。我已经研究了 MJPEG(这些相机似乎支持),但没有成功设置此属性,或者如果我从 OpenCV 启动它们,则无法检测它们在哪种模式下运行(yuyv?)。

想法?

【问题讨论】:

    标签: opencv webcam v4l2


    【解决方案1】:

    我也遇到了这个问题,并且有一个解决方案可以让我使用 mjpeg 压缩捕捉 2 个 640x480 的摄像机。我正在使用 Creative “Live Cam Sync HD VF0770”,它错误地报告了它的带宽要求。 quirks=128 修复适用于 320x240 未压缩视频。但是对于压缩 (mjpg) 格式,quirks=128 不起作用(它对压缩格式没有任何作用)。

    为了解决这个问题,我修改了 uvc 驱动程序如下:

    下载内核源代码

    mkdir -p ~/Software/kernel-git
    cd ~/Software/kernel-git
    git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    git checkout v3.2
    # NOTE: `uname -r`  shows me my current kernel is 3.2.0-60-generic
    # For a different kernel use a different tag
    

    复制 uvc 目录:

    mkdir -p ~/Software/uvcvideo_driver
    cd ~/Software/uvcvideo_driver
    #cp -a ~/Software/kernel-git/linux/drivers/media/usb/uvc .
    cp ~/Software/kernel-git/linux/drivers/media/video/uvc .
    

    修改 Makefile

    cd ~/Software/uvcvideo_driver/uvc
    vi Makefile
    
            obj-m += aauvcvideo.o
            aauvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
                  uvc_status.o uvc_isight.o
            all:
              make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    
            clean:
              make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
    

    压缩时强制带宽为 0x400。

    cd ~/Software/uvcvideo_driver/uvc
    vw uvc_video.c
    Find the uvc_fixup_video_ctrl() function.  At the end of the function add:
          if (format->flags & UVC_FMT_FLAG_COMPRESSED) {
            ctrl->dwMaxPayloadTransferSize = 0x400;
          }
    

    构建 aauvcvideo 模块:

    make
    

    删除旧模块并插入新模块:

    sudo rmmod uvcvideo
    sudo insmod ./aauvcvideo.ko quirks=128
    

    在 2 个不同的窗口中使用压缩运行 gucview 两次以进行测试

    guvcview --device=/dev/video1 --format=mjpg --size=640x480
    guvcview --device=/dev/video2 --format=mjpg --size=640x480
    

    祝你好运! -橡子

    【讨论】:

    • 解决相机问题的内核黑客值得一票。 :) 我read 认为 FIX_BANDWIDTH 怪癖只影响未压缩的格式,与您的答案相匹配。有趣的是,worked for me 的怪癖尽管 v4l2-ctl -d 0 -V 声称像素格式为“MJPG”,而我使用基于 OpenCV 的代码从多个摄像头捕获。
    • 弄清楚为什么这个怪癖对我有用,请在此处查看我的答案。简而言之,尽管v4l2-ctl -d 0 -V 声称,OpenCV 正在捕获未压缩的数据。
    • 谢谢你。要添加更多信息,这正是我在基于 debian 的设备上执行此操作的方法: # apt-get source linux-image # tar xf # cd linux-image # cp /lib/modules//build/Module.symvers 。 # make oldconfig # make prepare # make scripts # [EDIT AS ABOVE in drivers/media/usb/uvc] # make SUBDIRS=drivers/media/usb/uvc/ modules
    【解决方案2】:

    我遇到了这个确切的问题,使用三台罗技 quickcam pro 9000 相机(使用 ubuntu)。我可以读两个,但不是三个。就我而言,我没有使用 opencv,而是使用内存映射 IO 直接通过 V4L2 访问摄像机。简单来说就是没有足够的 USB 带宽来分配三个缓冲区。

    但是,我正在阅读未压缩的帧。一旦我将格式切换为 MJPEG,数据就足够小了,我可以从三个摄像头读取数据。我使用 libjpeg 来解码 MJPEG 流。

    我还没有研究如何使用 OpenCV 更改图像格式,但我知道它需要 MJPEG 才能适应所有数据。

    在切换到 MJPEG 之前,我花了很多时间尝试一次访问每个摄像头,在切换到下一个之前流式传输单个帧。不推荐!

    【讨论】:

    • 对于 OpenCV,v4l 构建支持 MJPEG,而 libv4l 构建仅支持未压缩格式,请在此处查看我的答案。
    【解决方案3】:

    视频捕获设备的驱动程序很可能报告了 USB 带宽争用。检查像素格式是否为YUYV,恰好是未压缩的。相反,如果像素格式为MJPG(压缩),则可能有多个设备在同一个USB通道上。

    v4l2-ctl -d /dev/video0 --list-formats
    

    输出将如下所示:

    ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : 16bpp YUY2, 4:2:2, packed
    

    以下是可能的解决方案:

    1. 使用不同制造商的捕获设备,以使加载的驱动程序不同。通常,处理多个设备的同一个驱动程序需要有效地处理带宽。
    2. 如果可用,请使用 PCI USB 扩展卡来连接第二个 USB 视频捕获设备。当我尝试连接加载驱动程序 cx231xx 的 AVerMedia DVD EZMaker 7 时,此解决方法对我非常有效。

    【讨论】:

    • EZMaker 7 是否可以在 windows 上使用 openCV VideoCapture 对象?
    【解决方案4】:

    OpenCV 可以构建为使用 v4llibv4l,并且只有 v4l 版本支持压缩格式,而 libv4l 版本仅支持 OpenCV 2.4 的一种未压缩格式。 11. (对于 v4l,请参见 autosetup_capture_mode_v4l2(),对于 libv4l,请参见 line 692 之后的代码。)OpenCV 3.0.0 在这里并没有比 2.4.11 改进太多;它仍然只支持 libv4l 的未压缩格式。

    由于您的错误提到了libv4l2,因此您的情况似乎是 libv4l 版本和 OpenCV 未压缩。要构建 v4l 版本的 OpenCV,您的 cmake 命令应包含

    -D WITH_LIBV4L=OFF
    

    WITH_LIBV4L 默认为我启用。)

    关于带宽和 USB 的说明。 USB 2.0(几乎所有网络摄像头都使用)的带宽为 480 Mbit/s。 30 fps 和 24 位/像素未压缩的 640x480 约为 221 Mbit/s,因此使用未压缩的网络摄像头可以快速耗尽 USB 2.0 带宽。每个 USB 主机控制器 可获得 480 Mbit/s,请参阅answer 了解如何列出它们。 (USB 集线器不添加主机控制器,主板上的多个 USB 端口通常连接到同一个主机控制器。连接到主机控制器的所有设备和集线器共享带宽。)

    对于预留更多 USB 带宽的网络摄像头,例如,UVC driver page 上带有 footnote [13] 的网络摄像头,FIX_BANDWIDTH quirk 可以提供帮助。但是这个怪癖仅适用于未压缩的格式(除非您在 Acorn 的答案中进行内核破解)。在我的情况下(Ubuntu 14.04,许多 Microsoft LifeCam Cinemas at 320x240),当我使用 OpenCV 的 libv4l 版本(ASMedia USB 主机控制器上的四个 LifeCam 运行良好)但对于 v4l 版本时,这个怪癖起作用了——我确认使用MJPEG——当我尝试从第二个 LifeCam 捕获时,我收到了 VIDIOC_STREAMON: No space left on device 错误! (对于同一台机器,Intel 和 VIA 主机控制器表现更好,并且每个都与两个 LifeCam for v4l 配合使用;LifeCam 保留了 48% 的 USB 2.0 带宽。)

    【讨论】:

    • 由于 libv4l 的部分目的似乎是“从任何(已知)像素格式转换为 BGR24”,libv4l 原则上可以从网络摄像头接收压缩格式,然后将 BGR24 传递给 OpenCV。我检查并发现 libv4l not 从网络摄像头接收压缩格式(适用于 v4l-utils 1.10.0),与我在上面的观察结果一致,即该怪癖适用于 libv4l。
    【解决方案5】:

    这对我很有魅力

    sudo rmmod uvcvideo

    sudo modprobe uvcvideo quirks=128

    这将在每次重新启动时重置。如果可行,请创建以下文件: 须藤 vi /etc/modprobe.d/uvcvideo.conf 包含以下行: options uvcvideo quirks=128

    检查此链接 http://renoirsrants.blogspot.in/2011/07/multiple-webcams-on-zoneminder.html

    【讨论】:

      【解决方案6】:

      使用 Ubuntu 18.04 上的内核 4.15.0-34-generic 和使用 gstreamer/v4l 支持编译的 OpenCV 3.4,我能够使用带电源的集线器在单个 USB 端口上流式传输 3x720p,并在 python 中使用带有 gstreamer 的 MJPG 压缩(使用 2xC922 和1xC920 相机 - 不需要 10fps 的帧率来工作):

      def open_cam_usb(dev, width, height):
          gst_str = (
              "v4l2src device=/dev/video{} ! "
              "image/jpeg,widh=(int){},height=(int){},framerate=10/1,"
              "format=(string)RGB ! "
              "jpegdec ! videoconvert ! appsink"
          ).format(dev, width, height)
          return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
      

      【讨论】:

        【解决方案7】:

        我发现的最有用的事情之一是,如果您在捕获初始化之间放置一个 Sleep(ms) 调用。这让我可以毫无问题地同时检索两个网络摄像头捕获。

        【讨论】:

          猜你喜欢
          • 2015-08-18
          • 1970-01-01
          • 1970-01-01
          • 2010-11-18
          • 1970-01-01
          • 1970-01-01
          • 2015-01-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多