我想连接到照相机,只有在发生事件时(例如按键)才能捕捉到一个帧。我想做的一个简化版本是:
cap = cv2.VideoCapture(device_id)
while True:
if event:
img = cap.read()
preprocess(img)
process(img)
cv.Waitkey(10)然而,cap.read似乎只捕获队列中的下一个帧,而不是最新的。我在网上做了很多搜索,似乎有很多问题,但没有明确的答案。只有一些肮脏的漏洞,包括在抓取之前和之后打开和关闭捕获设备(这对我不起作用,因为我的事件可能会被每秒触发多次);或者假设一个固定的框架并在每个事件上读取固定的n次(因为我的事件是不可预测的,并且可能在任何时间间隔发生)。
一个很好的解决办法是:
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来显示)
发布于 2019-02-18 21:37:05
我认为问题中提到的解决方案,即有一个单独的线程来清除缓冲区,是最简单的非脆性解决方案。这里的代码(我认为)相当不错:
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_BUFFERSIZE。2.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。它可能值得一试;代码就像这样简单:
cap.set(cv2.CAP_PROP_BUFFERSIZE, 0)发布于 2021-09-11 08:56:20
以下是Ulrich解决方案的简化版本。OpenCV的read()函数在一个调用中组合了grab()和检索(),在这个调用中,grab()只加载内存中的下一个帧,并检索解码最新抓取的帧(去捕获和运动jpeg解压缩)。
我们只对解码实际读取的帧感兴趣,因此该解决方案节省了一些CPU,并消除了对队列的需求
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发布于 2019-02-18 13:11:38
如果您不想在没有发生事件时捕获该帧,为什么要预处理/处理您的帧?如果不处理框架,则可以简单地丢弃它,除非事件发生。您的程序应该能够捕获,评估您的状况,并以足够的速度丢弃,即足够快的比您的相机FPS捕获率,始终得到最后的帧在队列中。
如果我不精通python,因为我在OpenCV中使用C++,但是它看起来应该类似于以下内容:
vidcap = cv.VideoCapture( filename )
while True:
success, frame = vidcap.read()
If Not success:
break
If cv.waitKey(1):
process(frame)根据OpenCV引用,vidcap.read()返回一个bool。如果框架被正确读取,它将是真实的。然后,将捕获的帧存储在可变帧中。如果没有按键,则循环继续进行。当按下键时,您将处理最后捕获的帧。
https://stackoverflow.com/questions/43665208
复制相似问题