我想连接到相机,并且只在事件发生时捕获帧(例如按键)。我想做的事情的简化版本是这样的:
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_hasframes 是什么?是否有可能获得该信息?我尝试查看 _CV_CAP_PROP_POSFRAMES 但它始终为 -1。
现在我有一个单独的线程,捕获以全 fps 运行,在我的事件中,我从该线程获取最新图像,但这似乎有点过分了。
(顺便说一句,我在 Ubuntu 16.04 上,但我想这应该没关系。我也在使用 pyqtgraph 进行显示)
原文由 memo 发布,翻译遵循 CC BY-SA 4.0 许可协议
我认为问题中提到的解决方案,即有一个单独的线程来清除缓冲区,是 最简单 的非脆弱解决方案。这里相当不错(我认为)代码:
帧读取器线程封装在自定义 VideoCapture 类中,与主线程的通信是通过队列进行的。
我为 node.js 问题 发布了非常相似的代码,其中 JavaScript 解决方案会更好。我对该问题的另一个 答案 的评论详细说明了为什么没有单独线程的非脆弱解决方案似乎很困难。
一种更简单但仅支持某些 OpenCV 后端的 替代解决方案 是使用
CAP_PROP_BUFFERSIZE
。 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
正是这个后端。可能值得先试一试;代码就像这样简单: