【问题标题】:Is there a way to avoid buffering images when using RTSP camera in OpenCV?在 OpenCV 中使用 RTSP 相机时,有没有办法避免缓冲图像?
【发布时间】:2018-06-29 02:41:30
【问题描述】:

假设我们在 OpenCV 中有一个名为 process 的进程,当我们调用它时,它需要大约 2 秒才能在一帧上完成。

当我们使用Videocapture 捕获我们的帧时,帧存储在缓冲区中,当第第n 帧 上的process 完成时,它会抓取下一帧((n+1 )th frame),但是,我想实时抓取这些帧,而不是按顺序。

例如你可以测试下面的例子

Mat frame;
VideoCapture cap("rtsp url");
while (true) {
    cap.read(frame);
    imshow("s",frame);
    waitKey(2000);     //artificial delay
}

运行上面的例子,你会看到显示的帧属于过去,而不是现在。我想知道如何跳过这些帧?

【问题讨论】:

  • 请尝试添加一些标点符号以使您的问题更容易理解。
  • 对不起,我不是本地人(我尽力了),但是如果你运行示例代码,你就会明白我想说的话
  • 为了做到这一点,您必须编写对处理函数的非阻塞调用 - 即使用线程。 OpenCV 本身不提供这样的功能。否则,无论您做什么,如果处理时间超过帧之间的间隔,它都会阻止视频捕获调用。
  • @MaxWalczak 你能发表一个答案吗
  • 类似于 Max.... 可能会在程序的开头启动第二个线程,该线程与当前线程连续运行并并行运行。它会说 4 或 8 个缓冲区 (Mats),它按循环顺序获取,Mat[0]、Mat[1]、Mat[2]、Mat[3]、Mat[0]、Mat[1].. .. 当您当前的线程想要一个新帧时,它会检查另一个线程当前正在获取哪一个并获取之前的一个,即最近完成的一个。我建议使用几个垫子,这样你就不可能拿一个在你拿它的时候仍然被覆盖的垫子。

标签: c++ opencv


【解决方案1】:
  • 新方法

启动videoCapture后,就可以在OpenCV中使用如下函数了。

videoCapture cap(0);
cap.set(CV_CAP_PROP_BUFFERSIZE, 1); //now the opencv buffer just one frame.
  • 使用线程

任务是使用多线程编程完成的。请问这个问题的意义何在?如果您使用的是 raspberrypi 之类的弱处理器,或者您有一个需要很长时间运行的大型算法,您可能会遇到此问题,从而导致帧出现较大延迟。

这个问题在 Qt 中通过使用 QtConcurrent 类来解决,该类能够轻松运行线程并且几乎不需要编码。基本上,我们将主线程作为一个处理单元运行并运行一个线程来连续捕获帧,因此当主线程完成对一个特定帧的处理时,它会从第二个线程请求另一帧。在第二个线程中,毫不延迟地捕获帧非常重要。因此,如果一个处理单元需要 2 秒,而在 0.2 秒内捕获一帧,我们就会丢失中间帧。

项目附如下

1.main.cpp

#include <opencv2/opencv.hpp>
#include <new_thread.h>     //this is a custom class that required for grab frames(we dedicate a new thread for this class)
#include <QtConcurrent/QtConcurrent>    
using namespace cv;
#include <QThread>     //need for generate artificial delay, which in real situation it will produce by weak processor or etc. 
int main()
{
      Mat frame;
      new_thread th;       //create an object from new_thread class
      QtConcurrent::run(&th,&new_thread::get_frame);   //start a thread with QtConcurrent
      QThread::msleep(2000); //need some time to start(open) camera
      while(true)
      {
          frame=th.return_frame();
          imshow("frame",frame);
          waitKey(20);
          QThread::msleep(2000); //artifical delay, or a big process
      }
}  

2.new_thread.h

#include <opencv2/opencv.hpp>
using namespace cv;
class new_thread
{
public:
    new_thread();             //constructor
    void get_frame(void);     //grab frame
    Mat return_frame();       //return frame to main.cpp
private:
    VideoCapture cap;         
    Mat frame;               //frmae i
};

3.new_thread.cpp

#include <new_thread.h>
#include <QThread>
new_thread::new_thread()
{
    cap.open(0);        //open camera when class is constructing
}

void new_thread::get_frame()       //get frame method 
{
    while(1)                     // while(1) because we want to grab frames continuously 
    {
        cap.read(frame);
    }
}

Mat new_thread::return_frame()
{
    return frame;              //whenever main.cpp need updated frame it can request last frame by usign this method
}

【讨论】:

  • 干得好!感谢您与社区分享。
  • 不,谢谢你,我从你的 cmets 那里得到这个想法:)
猜你喜欢
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多