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

Nya*_*uko 21 c++ video opencv

我正在通过网络摄像头捕获视频,该网络摄像头提供了一个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);
Run Code Online (Sandbox Code Playgroud)

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

if (!cap.isOpened()) return;

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

        m_imageFrame = frame;
        mutex.unlock();
Run Code Online (Sandbox Code Playgroud)

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

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

Maa*_*lis 27

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

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

// rest of your code...
Run Code Online (Sandbox Code Playgroud)

但是有一个重要的限制:

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


如果解决方案不起作用,请查看此帖子,解释如何解决问题.

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

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


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

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

  • `cv :: VideoCapture`接口不允许您获取该信息.另一种解决方案是创建一个不断抓取帧的不同线程(使用[`cv :: VideoCapture.grab()`](http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-grab )功能)高速.这将确保当真正的工作线程读取下一帧时缓冲区为空(当然,在读取帧时不要忘记同步这些线程). (3认同)
  • 不幸的是看起来这个常量不在Python opencv中:如果thing.find("CAP _")> - 1运行`[事物在dir(cv)中的东西)` (3认同)
  • “仅受 DC1394 v 2.x 后端支持”是什么意思?这是一种相机吗? (2认同)
  • 由于`CAP_PROP_BUFFERSIZE`与后端`dc1394`(这是一个摄像头捕获后端)相关,它是否只影响直接从网络摄像头读取数据?如果我通过 udp 接收 h264 流,这根本没有帮助,对吗?对于该用例,我还应该研究任何其他缓冲属性吗? (2认同)

Iva*_*aev 6

伙计们,这是非常愚蠢和讨厌的解决方案,但是由于某些原因,被接受的答案并没有帮助我。(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()
Run Code Online (Sandbox Code Playgroud)

  • cv2.VideoCapture("rtsp://admin:@192.168.3.231") 每次都会新建一个对象,这会非常慢 (3认同)