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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由于捕获缓冲区,OpenCV VideoCapture滞后相关的知识,希望对你有一定的参考价值。

我正在通过网络摄像头捕获视频,该网络摄像头提供了一个mjpeg流。我在工作线程中进行了视频捕获。我像这样开始捕获:

const std::string videoStreamAddress = "http://192.168.1.173:80/live/0/mjpeg.jpg?x.mjpeg";
qDebug() << "start";
cap.open(videoStreamAddress);
qDebug() << "really started";
cap.set(CV_CAP_PROP_FRAME_WIDTH, 720);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 576);

摄像机以20fps的速度输入流。但是,如果我像这样以20fps读取:

if (!cap.isOpened()) return;

        Mat frame;
        cap >> frame; // get a new frame from camera
        mutex.lock();

        m_imageFrame = frame;
        mutex.unlock();

然后有3秒多的延迟。原因是捕获的视频首先存储在缓冲区中。当我第一次启动摄像机时,缓冲区被累积但我没有读出帧。所以如果我从缓冲区读取它总是给我旧帧。我现在唯一的解决方案是以30fps的速度读取缓冲区,这样它就可以快速清理缓冲区并且没有更严重的延迟。

有没有其他可能的解决方案,以便每次启动相机时我都可以手动清理/刷新缓冲区?

答案

根据this源代码,您可以设置cv::VideoCapture对象的缓冲区大小。

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

// rest of your code...

但是有一个重要的限制:

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


如果解决方案不起作用,请查看解释如何解决问题的this post

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

(链接帖子上的答案显示:从缓冲区返回一个帧大约需要返回最新帧的1/8。当然,你的里程可能会有所不同!)


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

您可以使用简单的自旋锁来同步实际工作线程和第三个线程之间的读取帧。

另一答案

伙计们这是非常愚蠢和令人讨厌的解决方案,但接受的答案并没有因为某些原因帮助我。 (python中的代码,但实质上很清楚)

# vcap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
data = np.zeros((1140, 2560))
image = plt.imshow(data)

while True:
    vcap = cv2.VideoCapture("rtsp://admin:@192.168.3.231")
    ret, frame = vcap.read()
    image.set_data(frame)
    plt.pause(0.5) # any other consuming operation
    vcap.release()
另一答案

你可以确保抓住框架花了一点时间。编码非常简单,虽然有点不可靠;可能,此代码可能导致死锁。

#include <chrono>
using clock = std::chrono::high_resolution_clock;
using duration_float = std::chrono::duration_cast<std::chrono::duration<float>>;
// ...
while (1) {
    TimePoint time_start = clock::now();
    camera.grab();
    if (duration_float(clock::now() - time_start).count() * camera.get(cv::CAP_PROP_FPS) > 0.5) {
        break;
    }
}
camera.retrieve(dst_image);

该代码使用C ++ 11。

以上是关于由于捕获缓冲区,OpenCV VideoCapture滞后的主要内容,如果未能解决你的问题,请参考以下文章

带有 IP 摄像机的 OpenCV 问题

使用opencv线程捕获空白图像

QT6 C++ 中音频捕获原始数据的选项[关闭]

java glReadpixels 到 OpenCV 垫

无法在 android 上使用 C++ OpenCV 打开相机

用于视频处理的图像缓冲区 [关闭]