且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

由于捕获缓冲区,OpenCV VideoCapture 滞后

更新时间:2022-03-25 21:52:40

OpenCV 解决方案

根据这个源,您可以设置cv::VideoCapture 对象的缓冲区大小.

OpenCV Solution

According to this source, you can set the buffersize of a cv::VideoCapture object.

cv::VideoCapture cap;
cap.set(CV_CAP_PROP_BUFFERSIZE, 3); // internal buffer will now store only 3 frames

// rest of your code...

但是有一个重要的限制:

There is an important limitation however:

CV_CAP_PROP_BUFFERSIZE 存储在内部缓冲存储器中的帧数(注意:目前仅支持 DC1394 v 2.x 后端)

CV_CAP_PROP_BUFFERSIZE Amount of frames stored in internal buffer memory (note: only supported by DC1394 v 2.x backend currently)

从评论中更新.在较新版本的 OpenCV (3.4+) 中,限制似乎消失了,代码使用了作用域枚举:

Update from comments. In newer versions of OpenCV (3.4+), the limitation seems to be gone and the code uses scoped enumerations:

cv::VideoCapture cap;
cap.set(cv::CAP_PROP_BUFFERSIZE, 3);

解决方法 1

如果解决方案不起作用,请查看这篇博文 解释了如何解决这个问题.


Hackaround 1

If the solution does not work, take a look at this post that explains how to hack around the issue.

简而言之:测量查询一帧所需的时间;如果它太低,则表示该帧是从缓冲区中读取的,可以丢弃.继续查询帧,直到测量的时间超过某个限制.发生这种情况时,缓冲区为空,返回的帧是最新的.

In a nutshell: the time needed to query a frame is measured; if it is too low, it means the frame was read from the buffer and can be discarded. Continue querying frames until the time measured exceeds a certain limit. When this happens, the buffer was empty and the returned frame is up to date.

(链接帖子上的答案显示:从缓冲区返回帧的时间大约是返回最新帧的时间的 1/8.当然,您的里程可能会有所不同!)

(The answer on the linked post shows: returning a frame from the buffer takes about 1/8th the time of returning an up to date frame. Your mileage may vary, of course!)

一个不同的解决方案,灵感来自这篇帖子, 是创建第三个线程,高速连续抓取帧,保持缓冲区为空.这个线程应该使用 cv::VideoCapture.grab() 以避免开销.

A different solution, inspired by this post, is to create a third thread that grabs frames continuously at high speed to keep the buffer empty. This thread should use the cv::VideoCapture.grab() to avoid overhead.

您可以使用一个简单的自旋锁来同步真正的工作线程和第三个线程之间的阅读帧.

You could use a simple spin-lock to synchronize reading frames between the real worker thread and the third thread.