我尝试从IP摄像机读取并显示带有OpenCV(C++)的视频流。有时,应用程序会冻结几秒钟,然后报告接收到一个空框架。我正在寻找删除空帧并以视频不会冻结几秒钟的方式读取下一帧的可能性。

我使用下面的简单示例代码,并尝试在出现空白帧时重新读取下一帧。视频开始正​​常播放,但是一段时间后停顿了几秒钟。
我在VLC媒体播放器中打开了流,并在那里流畅地运行。
我尝试了不同的方法来读取下一帧:例如cap.read(frame);而不是帽子>>框架;我还尝试更改waitKey的延迟,但始终会得到相同的结果。我不想使用tcp(在流地址的末尾插入?tcp),因为在最终应用程序中,我不能容忍较大的延迟。

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main(){

  string filename = "rtsp://[myStreamIP]:554/stream.mjpeg"
  VideoCapture cap(filename);

  if(!cap.isOpened()){
    return 1;
  }

  int frameNumber = 0;
  while(cap.isOpened()){

    Mat frame;
    cap >> frame;
    frameNumber++;

    while (frame.empty()){
          cout << "empty frame" << "-";
      cap >> frame;

    }

    cout << frameNumber << "-";
    imshow( "Frame", frame );
    waitKey(1);

  }

  cap.release();
  destroyAllWindows();
  return 0;
}


我得到的输出看起来像这样:

1-2 -...- 123- [几秒钟过去了,什么也没发生,并且视频冻结了]-空帧-124-125-
...

当我不得不尝试重新读取帧几次时,我会理解一定的延迟(仍然小得多),但是我不明白为什么延迟在输出中的第一次“空帧”之前出现。

最佳答案

我认为在循环中查找空框架不是一个好习惯,我宁愿使用if else语句,但我不认为这是问题所在:

Mat frame;
while(cap.isOpened()){

    cap >> frame;
    frameNumber++;

    if(frame.empty()){
      cout << "empty frame" << "-";
      continue;
    }

    cout << frameNumber << "-";
    imshow( "Frame", frame );
    waitKey(1);
}

并在while循环之外声明Mat frame,以便您可以重用相同的内存空间。

编辑:
读取opencv doc时,您可以看到该读取调用是对grab()和retrieve()的组合调用。其中retrieve()是“慢速”函数,该函数将您的图片写在cv::Mat中,grab()只是获取下一张图片并返回 bool(boolean) 值(如果有图片的话)。也许像这样的作品:
Mat frame;
while(cap.isOpened()){

    if(!cap.grab()){
      cout << "empty frame" << "-";
      continue;
    }

    frame = cap.retrieve();
    frameNumber++;

    cout << frameNumber << "-";
    imshow( "Frame", frame );
    waitKey(1);
}

关于c++ - 使用OpenCV显示流有时会收到一个空帧并卡住,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57767336/

10-11 21:08