Python 一次从 OpenCV 中的两个摄像头捕获视频

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29664399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:51:51  来源:igfitidea点击:

Capturing video from two cameras in OpenCV at once

pythonopencvcamera

提问by Cerin

How do you capture video from two or more cameras at once (or nearly) with OpenCV, using the Python API?

您如何使用 Python API 使用 OpenCV 一次(或几乎)从两个或多个摄像头捕获视频?

I have three webcams, all capable of video streaming, located at /dev/video0, /dev/video1, and /dev/video2.

我有三个网络摄像头,都能够进行视频流传输,位于 /dev/video0、/dev/video1 和 /dev/video2。

Using the tutorialas an example, capturing images from a single camera is simply:

以本教程为例,从单个相机捕​​获图像很简单:

import cv2
cap0 = cv2.VideoCapture(0)
ret0, frame0 = cap0.read()
cv2.imshow('frame', frame0)
cv2.waitKey()

And this works fine.

这工作正常。

However, if I try to initialize a second camera, attempting to read()from it returns None:

但是,如果我尝试初始化第二个摄像头,尝试read()从它返回 None:

import cv2
cap0 = cv2.VideoCapture(0)
cap1 = cv2.VideoCapture(1)
ret0, frame0 = cap0.read()
assert ret0 # succeeds
ret1, frame1 = cap1.read()
assert ret1 # fails?!

Just to ensure I wasn't accidentally giving OpenCV a bad camera index, I tested each camera index individually and they all work by themselves. e.g.

只是为了确保我不会不小心给 OpenCV 一个糟糕的相机索引,我单独测试了每个相机索引,它们都自己工作。例如

import cv2
#cap0 = cv2.VideoCapture(0)
cap1 = cv2.VideoCapture(1)
#ret0, frame0 = cap0.read()
#assert ret0
ret1, frame1 = cap1.read()
assert ret1 # now it works?!

What am I doing wrong?

我究竟做错了什么?

Edit: My hardware is a Macbook Pro running Ubuntu. Researching the issue specifically on Macbooks, I've found others that have run into this problem too, both on OSX and with different types of cameras. If I access the iSight, both calls in my code fail.

编辑:我的硬件是运行 Ubuntu 的 Macbook Pro。专门在 Macbook 上研究这个问题,我发现其他人也遇到了这个问题,无论是在 OSX 上还是在不同类型的相机上。如果我访问 iSight,我的代码中的两个调用都会失败。

采纳答案by Velimir Mlaker

Yes you're definitely limited by the USB bandwidth. Attempting to read from both devices at full-rez you probably got error:

是的,您肯定会受到 USB 带宽的限制。尝试以 full-rez 从两个设备中读取您可能会遇到错误:

libv4l2: error turning on stream: No space left on device
VIDIOC_STREAMON: No space left on device
Traceback (most recent call last):
  File "p.py", line 7, in <module>
    assert ret1 # fails?!
AssertionError

And then when you reduce the res to 160x120:

然后当您将分辨率降低到 160x120 时:

import cv2
cap0 = cv2.VideoCapture(0)
cap0.set(3,160)
cap0.set(4,120)
cap1 = cv2.VideoCapture(1)
cap1.set(3,160)
cap1.set(4,120)
ret0, frame0 = cap0.read()
assert ret0 # succeeds
ret1, frame1 = cap1.read()
assert ret1 # fails?!

now it seems to work! I bet you have both cams connected on the same USB card. You can run lsusbcommand to make sure, and it should indicate something like:

现在它似乎工作!我敢打赌,您的两个摄像头都连接在同一张 USB 卡上。您可以运行lsusb命令来确定,它应该显示如下内容:

Bus 001 Device 006: ID 046d:081b Logitech, Inc. Webcam C310
Bus 001 Device 004: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 007: ID 046d:0990 Logitech, Inc. QuickCam Pro 9000
Bus 001 Device 005: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 003: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 002: ID 1058:0401 Western Digital Technologies, Inc. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

(Note both cameras on same bus.) If possible, you can add another USB card to your machine to gain more bandwidth. I've done this before in order to run multiple cams at full resolution on a single machine. Albeit that was a tower workstation with available motherboard slots, and unfortunately you may not have that option on a MacBook laptop.

(注意同一总线上的两个摄像头。)如果可能,您可以向您的机器添加另一个 USB 卡以获得更多带宽。我以前这样做是为了在一台机器上以全分辨率运行多个凸轮。尽管那是一个带有可用主板插槽的塔式工作站,但不幸的是,您在 MacBook 笔记本电脑上可能没有该选项。

回答by ?????? ?????

I have use "imutils" and read webcam show on the image.

我使用了“imutils”并阅读了图像上的网络摄像头显示。

import imutils

capture vedio frames

捕捉视频帧

#--- WebCam1
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH,300)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT,300)
#--- WebCam2
cap1 = cv2.VideoCapture(1)
cap1.set(cv2.CAP_PROP_FRAME_WIDTH,300)
cap1.set(cv2.CAP_PROP_FRAME_HEIGHT,300)
#--- WebCam3
cap2 = cv2.VideoCapture(2)
cap2.set(cv2.CAP_PROP_FRAME_WIDTH,300)
cap2.set(cv2.CAP_PROP_FRAME_HEIGHT,300)
#--- WebCame4
cap3 = cv2.VideoCapture(3)
cap3.set(cv2.CAP_PROP_FRAME_WIDTH,300)
cap3.set(cv2.CAP_PROP_FRAME_HEIGHT,300)

i create function read_framesend parameter about Image.fromarray and display

我创建函数read_frame发送关于 Image.fromarray 的参数并显示

def read_frame():
    webCameShow(cap.read(),display1)
    webCameShow(cap1.read(),display2)
    webCameShow(cap2.read(),display6)
    webCameShow(cap3.read(),display7)   
    window.after(10, read_frame)

and final function show video on the "imageFrame"

和最终功能在“imageFrame”上显示视频

def webCameShow(N,Display): 
    _, frameXX = N
    cv2imageXX = cv2.cvtColor(frameXX, cv2.COLOR_BGR2RGBA)
    imgXX = Image.fromarray(cv2imageXX)
    #imgtkXX = ImageTk.PhotoImage(image=imgXX)
    Display.imgtk = imgtkXX 
    Display.configure(image=imgtkXX)

example. 4-webcam

例子。 4-网络摄像头

Youtube: Youtube

优酷:优

回答by TheoreticallyNick

Using OPENCV and two standard USB cameras, I was able to do this using multithreading. Essentially, define one function which opens an opencv window and VideoCapture element. Then, create two threads with the camera ID and window name as inputs.

使用 OPENCV 和两个标准 USB 摄像头,我能够使用多线程来做到这一点。本质上,定义一个函数来打开一个 opencv 窗口和 VideoCapture 元素。然后,使用相机 ID 和窗口名称作为输入创建两个线程。

import cv2
import threading

class camThread(threading.Thread):
    def __init__(self, previewName, camID):
        threading.Thread.__init__(self)
        self.previewName = previewName
        self.camID = camID
    def run(self):
        print "Starting " + self.previewName
        camPreview(self.previewName, self.camID)

def camPreview(previewName, camID):
    cv2.namedWindow(previewName)
    cam = cv2.VideoCapture(camID)
    if cam.isOpened():  # try to get the first frame
        rval, frame = cam.read()
    else:
        rval = False

    while rval:
        cv2.imshow(previewName, frame)
        rval, frame = cam.read()
        key = cv2.waitKey(20)
        if key == 27:  # exit on ESC
            break
    cv2.destroyWindow(previewName)

# Create two threads as follows
thread1 = camThread("Camera 1", 1)
thread2 = camThread("Camera 2", 2)
thread1.start()
thread2.start()

Great resource for learning how to thread in python: https://www.tutorialspoint.com/python/python_multithreading.htm

学习如何在 python 中线程的好资源:https: //www.tutorialspoint.com/python/python_multithreading.htm

回答by SimLeek

This has been a pain for me for a long time, so I made a library on top of OpenCV to handle multiple cameras and viewports. I ran into a bunch of problems like videos not compressing by default, or windows only displaying in the main thread. I'm able to display two 720p webcams in real time on Windows so far.

这对我来说一直很痛苦,所以我在 OpenCV 之上做了一个库来处理多个相机和视口。我遇到了一堆问题,比如视频默认不压缩,或者窗口只显示在主线程中。到目前为止,我能够在 Windows 上实时显示两个 720p 网络摄像头。

Try:

尝试:

pip install CVPubSubs

Then, in python:

然后,在python中:

import cvpubsubs.webcam_pub as w
from cvpubsubs.window_sub import SubscriberWindows

t1 = w.VideoHandlerThread(0)
t2 = w.VideoHandlerThread(1)

t1.start()
t2.start()

SubscriberWindows(window_names=['cammy', 'cammy2'],
              video_sources=[0,1]
              ).loop()

t1.join()
t1.join()

It's relatively new though, so tell me about any bugs or unoptimized code.

不过它相对较新,所以告诉我任何错误或未优化的代码。

回答by Sajil Vohra

try to use this code... it worked as expected... this is for two cams,if you want more cams, just create the "VideoCapture()" objects...for example 3rd cam will have : cv2.VideoCapture(3) and corresponding code in the while loop

尝试使用此代码...它按预期工作...这是两个摄像头,如果您想要更多摄像头,只需创建“VideoCapture()”对象...例如,第三个摄像头将具有: cv2.VideoCapture( 3)以及while循环中对应的代码

import cv2

frame0 = cv2.VideoCapture(1)
frame1 = cv2.VideoCapture(2)
while 1:

   ret0, img0 = frame0.read()
   ret1, img00 = frame1.read()
   img1 = cv2.resize(img0,(360,240))
   img2 = cv2.resize(img00,(360,240))
   if (frame0):
       cv2.imshow('img1',img1)
   if (frame1):
       cv2.imshow('img2',img2)

   k = cv2.waitKey(30) & 0xff
   if k == 27:
      break

frame0.release()
frame1.release()
cv2.destroyAllWindows()

ALL THE BEST !

祝一切顺利 !

回答by Gio Lac Cagliari

frame0 = cv2.VideoCapture(1)
frame1 = cv2.VideoCapture(2)

must be:

必须是:

frame0 = cv2.VideoCapture(0)  # index 0
frame1 = cv2.VideoCapture(1)  # index 1

So it runs

所以它运行

回答by Jacob W. Dallas

Adding a little to what @TheoreticallyNick posted earlier:

在@TheoreticalNick 之前发布的内容中添加一点:

import cv2
import threading

class camThread(threading.Thread):
    def __init__(self, previewName, camID):
        threading.Thread.__init__(self)
        self.previewName = previewName
        self.camID = camID
    def run(self):
        print("Starting " + self.previewName)
        camPreview(self.previewName, self.camID)

def camPreview(previewName, camID):
    cv2.namedWindow(previewName)
    cam = cv2.VideoCapture(camID)
    if cam.isOpened():
        rval, frame = cam.read()
    else:
        rval = False

    while rval:
        cv2.imshow(previewName, frame)
        rval, frame = cam.read()
        key = cv2.waitKey(20)
        if key == 27:  # exit on ESC
            break
    cv2.destroyWindow(previewName)

# Create threads as follows
thread1 = camThread("Camera 1", 0)
thread2 = camThread("Camera 2", 1)
thread3 = camThread("Camera 3", 2)

thread1.start()
thread2.start()
thread3.start()
print()
print("Active threads", threading.activeCount())

This will open up a new thread for each webcam you have. In my case, I wanted to open up three different feeds. Tested on Python 3.6. Let me know if you have any issues, also thanks to TheoreticallyNick for the readable/functioning code!

这将为您拥有的每个网络摄像头打开一个新线程。就我而言,我想打开三个不同的提要。在 Python 3.6 上测试。如果您有任何问题,请告诉我,还要感谢 TheoreticallyNick 提供可读/可运行的代码!