首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从opencv中的捕捉设备(摄像机)获取最新帧

如何从opencv中的捕捉设备(摄像机)获取最新帧
EN

Stack Overflow用户
提问于 2017-04-27 18:15:47
回答 4查看 27.2K关注 0票数 29

我想连接到照相机,只有在发生事件时(例如按键)才能捕捉到一个帧。我想做的一个简化版本是:

代码语言:javascript
复制
cap = cv2.VideoCapture(device_id)

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

    process(img)
    cv.Waitkey(10)

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

一个很好的解决办法是:

代码语言:javascript
复制
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。

现在,我有一个单独的线程,捕获以完整的fps运行,在我的事件中,我从该线程中获取最新的图像,但这似乎有点过分了。

(我在Ubuntu 16.04,但我想这不重要。我也使用pyqtgraph来显示)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-02-18 21:37:05

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

代码语言:javascript
复制
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类中,与主线程的通信是通过队列进行的。

我为node.js 问题发布了非常类似的代码,在那里JavaScript解决方案会更好。我对这个问题的另一个回答的评论给出了为什么没有独立线程的非脆性解决方案似乎很难。

替代解决方案更简单,但只支持某些OpenCV后端,它使用CAP_PROP_BUFFERSIZE2.4博士状态它是“目前只有DC1394 Firewire v2.x后端支持的”。对于Linux后端V4L,根据3.4.5代码中的一条评论,2018年3月9日增加了支持,但我得到的正是这个后端的VIDEOIO ERROR: V4L: Property <unknown property string>(38) not supported by device。它可能值得一试;代码就像这样简单:

代码语言:javascript
复制
cap.set(cv2.CAP_PROP_BUFFERSIZE, 0)
票数 39
EN

Stack Overflow用户

发布于 2021-09-11 08:56:20

以下是Ulrich解决方案的简化版本。OpenCV的read()函数在一个调用中组合了grab()和检索(),在这个调用中,grab()只加载内存中的下一个帧,并检索解码最新抓取的帧(去捕获和运动jpeg解压缩)。

我们只对解码实际读取的帧感兴趣,因此该解决方案节省了一些CPU,并消除了对队列的需求

代码语言:javascript
复制
import cv2
import threading

# bufferless VideoCapture
class VideoCapture:

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

    # grab frames as soon as they are available
    def _reader(self):
        while True:
            ret = self.cap.grab()
            if not ret:
                break

    # retrieve latest frame
    def read(self):
        ret, frame = self.cap.retrieve()
        return frame
票数 6
EN

Stack Overflow用户

发布于 2019-02-18 13:11:38

如果您不想在没有发生事件时捕获该帧,为什么要预处理/处理您的帧?如果不处理框架,则可以简单地丢弃它,除非事件发生。您的程序应该能够捕获,评估您的状况,并以足够的速度丢弃,即足够快的比您的相机FPS捕获率,始终得到最后的帧在队列中。

如果我不精通python,因为我在OpenCV中使用C++,但是它看起来应该类似于以下内容:

代码语言:javascript
复制
vidcap = cv.VideoCapture(   filename    )

while True:
    success, frame = vidcap.read()
    If Not success:
         break
    If cv.waitKey(1):
         process(frame)

根据OpenCV引用,vidcap.read()返回一个bool。如果框架被正确读取,它将是真实的。然后,将捕获的帧存储在可变帧中。如果没有按键,则循环继续进行。当按下键时,您将处理最后捕获的帧。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43665208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档