Python Raspberry Pi 3上的OpenCV多USB摄像头

Python Raspberry Pi 3上的OpenCV多USB摄像头,python,opencv,raspberry-pi,raspbian,Python,Opencv,Raspberry Pi,Raspbian,我已经看了很多以前的问题与此相关,没有一个有帮助 我的设置: 其中之一 它们显示为/dev/video0和/dev/video1 图像为640x480 树莓皮3 拉斯宾·杰西 OpenCV 3.1.0 Python 2.7 对于其中任何一个相机,我都可以捕获图像并以相当不错的速度显示它们,并且延迟最小(偶尔会出现瑕疵) 然而,当我尝试同时使用这两种方法时,我得到的帧速率可能是帧速率的十分之一(尽管帧之间的延迟似乎随着每一帧的变化而变化很大),有各种令人讨厌的图像伪影(例如,见下文)和无法

我已经看了很多以前的问题与此相关,没有一个有帮助

我的设置:

  • 其中之一
    • 它们显示为
      /dev/video0
      /dev/video1
    • 图像为640x480
  • 树莓皮3
  • 拉斯宾·杰西
  • OpenCV 3.1.0
  • Python 2.7
对于其中任何一个相机,我都可以捕获图像并以相当不错的速度显示它们,并且延迟最小(偶尔会出现瑕疵)

然而,当我尝试同时使用这两种方法时,我得到的帧速率可能是帧速率的十分之一(尽管帧之间的延迟似乎随着每一帧的变化而变化很大),有各种令人讨厌的图像伪影(例如,见下文)和无法忍受的延迟量

问题不在于相机本身或设备上的USB带宽:当我将相机连接到Windows PC时,我能够以30 FPS的速度捕获和显示,没有任何视觉伪影,并且几乎没有延迟

据我所知,问题一定出在Pi硬件、驱动程序或OpenCV上。我不认为是Pi硬件的问题。。如果我能用两台相机达到一台相机帧速率的一半(我不明白为什么这不可能),并且没有难看的瑕疵,我会很高兴

有人有什么建议吗?我最终只是尝试将两台摄像机的视频从Pi传输到桌面。如果有不涉及OpenCV的建议,我洗耳恭听;我并没有试图在Pi上进行任何渲染或操作,但openCV是我发现的唯一一种可以相当快地捕捉图像的东西(当然,只有一个摄像头)

仅供参考,我使用的简单python脚本如下:

import cv2
import numpy as np
import socket
import ctypes
import struct

cap = []
cap.append(cv2.VideoCapture(0))
cap.append(cv2.VideoCapture(1))

#grab a single frame from one camera
def grab(num):
    res, im = cap[num].read()
    return (res,im)

#grab a frame from each camera and stitch them
#side by side
def grabSBS():
    res, imLeft  = grab(1)
    #next line is for pretending I have 2 cameras
    #imRight = imLeft.copy()
    res, imRight = grab(0)
    imSBS = np.concatenate((imLeft, imRight), axis=1)
    return res,imSBS

###For displaying locally instead of streaming
#while(False):
#    res, imLeft = grab(0)
#    imRight = imLeft.copy()
#    imSBS = np.concatenate((imLeft, imRight), axis=1)
#    cv2.imshow("win", imSBS)
#    cv2.waitKey(20)

header_data = ctypes.create_string_buffer(12)

while(True):
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sck.bind(("10.0.0.XXX", 12321))

    sck.listen(1)

    while(True):
        (client, address) = sck.accept()
        print "Client connected:", address
        try:
            while(True):
            res,im = grabSBS()
            if(res):
                success, coded = cv2.imencode('.jpg', im)
                if (success):
                    height, width, channels = im.shape
                    size = len(coded)
                    struct.pack_into(">i", header_data , 0, width)
                    struct.pack_into(">i", header_data , 4, height)
                    struct.pack_into(">i", header_data , 8, size)
                    client.sendall(header_data .raw)
                    client.sendall(coded.tobytes())
        except Exception as ex:
            print "ERROR:", ex
            client.close()
            sck.close()
            exit()
更新:我在初始化VideoCapture对象后添加了以下几行代码,使其工作得更好:

cap[0].set(cv2.CAP_PROP_FPS, 15)
cap[1].set(cv2.CAP_PROP_FPS, 15)

这既降低了所需的带宽,也降低了openCV的工作负载。我仍然每隔几帧就收到这些可怕的伪影,所以如果有人对此提出建议,我很高兴听到这些建议。

好吧,在花了大约5个小时与之斗争之后,我似乎找到了解决办法

首先,很明显,OpenCV试图以每秒30帧的速度拍摄,尽管我无法以每秒30帧的速度拍摄帧。我将视频捕获帧速率改为15 FPS,视频变得越来越平滑,越来越快

cap[0].set(cv2.CAP_PROP_FPS, 15.0)
cap[1].set(cv2.CAP_PROP_FPS, 15.0)

不过,这并没有消除这些文物。我最终发现,如果在通过网络发送图像后执行
del(im)
,伪影就会完全消失。

相机图像是否已编码??如果使用
####进行本地显示而不是流式显示,会发生什么情况?我不知道当OpenCV从驱动程序检索图像时,它们采取什么形式。VideoCapture.read()以Numpy ndarray格式返回图像,这是一种原始格式。然后我使用JPEG编码来缩小尺寸并通过网络发送。至于“####用于本地显示”位,当我使用它时,它会在Pi的显示器上显示视频。不过,该代码并没有同时使用两个摄像头,只是使用了一个摄像头,然后它复制图像,假装它有两个摄像头。当我使用它时,视频非常流畅。一些想法。。。我相信只有一个USB控制器,摄像头和网络接口必须共享,这可能是一个瓶颈。另外,你可以使用多线程,因为Pi有4个内核,可以让一个线程进行JPEG编码,或者让两个线程进行交替帧编码?只是一个想法。我的意思是从摄像机编码,以便pi必须解码它们,这可能是一个瓶颈。pc可能更快。你能尝试合并图像(例如,将两个图像合并到一个大图像)并仅对单个图像进行编码+流式处理吗?和/或在编码/流式传输之前尝试调整图像大小(更小),以便更好地了解瓶颈可能在哪里?这看起来像是通过网络异步发送,并且您在发送或复制图像时正在更改位?但这意味着在图像完全发送之前删除它,所以这可能不是原因,或者你只是幸运的一个有趣的想法。。我没有考虑到它可能是异步进行的。我显然认为
sendall()
是一个阻塞调用。无论哪种方式,我都体验到了这些伪影,即使我只是在本地显示图像——根本不使用网络。当不使用网络时,python代码没有一个是异步的,因此两个线程同时在同一个缓冲区上运行应该不会有任何问题,除非OpenCV做了一些不正常的事情,并在它交给我之后继续写入Numpy ndarray。相机可能会连续写入缓冲区,但通常情况下,这不应该是您访问的缓冲区。