如何从opencv中的捕获设备(相机)获取最新帧[python] [英] how to get the latest frame from capture device (camera) in opencv [python]

查看:788
本文介绍了如何从opencv中的捕获设备(相机)获取最新帧[python]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想连接到摄像机,并且仅在发生事件(例如按键)时捕获帧.我想做的一个简化版本是:

I want to connect to a camera, and only capture a frame when an event happens (e.g. keypress). A simplified version of what I'd like to do is this:

cap = cv2.VideoCapture(device_id)

while True:
    if event:
        img = cap.read()
        preprocess(img)

    process(img)
    cv.Waitkey(10)

但是,cap.read似乎仅捕获队列中的下一帧,而不捕获最新帧.我在网上做了很多搜索,对此似乎有很多疑问,但没有明确的答案.只有一些肮脏的骇客,包括在抓取之前和之后打开和关闭捕获设备(这对我不起作用,因为我的事件可能每秒触发多次);或假设固定帧率并在每个事件上读取固定n次(这对我来说不起作用,因为我的事件是不可预测的,并且可能在任何时间间隔发生).

However, cap.read seems to only capture the next frame in the queue, and not the latest. I did a lot of searching online, and there seems to be a lot of questions on this but no definitive answer. Only some dirty hacks which involve opening and closing the capture device just before and after grabbing (which won't work for me as my event might be triggered multiple times per second); or assuming a fixed framerate and reading a fixed-n times on each event (which won't work for me as my event is unpredictable and could happen at any interval).

一个不错的解决方案是:

A nice solution would be:

while True:
    if event:
        while capture_has_frames:
            img = cap.read()
        preprocess(img)

    process(img)
    cv.Waitkey(10)

但是 capture_has_frames 是什么?是否有可能获得该信息?我尝试查看 CV_CAP_PROP_POS_FRAMES ,但始终为-1.

But what is capture_has_frames? Is it possible to get that info? I tried looking into CV_CAP_PROP_POS_FRAMES but it's always -1.

目前,我有一个单独的线程,其中捕获以全fps的速度运行,并且在我发生的事件中,我正在从该线程中获取最新图像,但这似乎有些过头了.

For now I have a separate thread where the capture is running at full fps, and on my event I'm grabbing the latest image from that thread, but this seems overkill.

(我在Ubuntu 16.04 btw上,但我想应该没关系.我也在使用pyqtgraph进行显示)

(I'm on Ubuntu 16.04 btw, but I guess it shouldn't matter. I'm also using pyqtgraph for display)

推荐答案

我认为问题中提到的解决方案(即拥有一个单独的线程来清除缓冲区)是最简单的非脆弱解决方案为了这.这里的代码相当不错(我认为):

I think the solution mentioned in the question, namely having a separate thread that clears the buffer, is the easiest non-brittle solution for this. Here reasonably nice (I think) code for this:

import cv2, Queue, threading, time

# bufferless VideoCapture
class VideoCapture:

  def __init__(self, name):
    self.cap = cv2.VideoCapture(name)
    self.q = Queue.Queue()
    t = threading.Thread(target=self._reader)
    t.daemon = True
    t.start()

  # read frames as soon as they are available, keeping only most recent one
  def _reader(self):
    while True:
      ret, frame = self.cap.read()
      if not ret:
        break
      if not self.q.empty():
        try:
          self.q.get_nowait()   # discard previous (unprocessed) frame
        except Queue.Empty:
          pass
      self.q.put(frame)

  def read(self):
    return self.q.get()

cap = VideoCapture(0)
while True:
  time.sleep(.5)   # simulate time between events
  frame = cap.read()
  cv2.imshow("frame", frame)
  if chr(cv2.waitKey(1)&255) == 'q':
    break

帧读取器线程封装在自定义VideoCapture类中,并且通过队列与主线程进行通信.

The frame reader thread is encapsulated inside the custom VideoCapture class, and communication with the main thread is via a queue.

我为node.js 问题发布了非常相似的代码,而JavaScript解决方案会更好.我对该问题的另一个答案的评论详细说明了为什么没有单独线程的非脆弱解决方案似乎很困难.

I posted very similar code for a node.js question, where a JavaScript solution would have been better. My comments on another answer to that question give details why a non-brittle solution without separate thread seems difficult.

使用CAP_PROP_BUFFERSIZE较为容易,但仅某些OpenCV后端支持此替代解决方案. 2.4个文档指出,仅受支持目前由DC1394 [Firewire] v 2.x后端提供."对于Linux后端V4L,请根据 3.4.5代码,已在2018年3月9日添加了支持,但我为此后端完全获得了VIDEOIO ERROR: V4L: Property <unknown property string>(38) not supported by device的支持.首先可能值得尝试;代码很简单:

An alternative solution that is easier but supported only for some OpenCV backends is using CAP_PROP_BUFFERSIZE. The 2.4 docs state it is "only supported by DC1394 [Firewire] v 2.x backend currently." For Linux backend V4L, according to a comment in the 3.4.5 code, support was added on 9 Mar 2018, but I got VIDEOIO ERROR: V4L: Property <unknown property string>(38) not supported by device for exactly this backend. It may be worth a try first; the code is as easy as this:

cap.set(cv2.CAP_PROP_BUFFERSIZE, 0)

这篇关于如何从opencv中的捕获设备(相机)获取最新帧[python]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆