OpenCV读取视频产生稳定延迟情况的解决方案(二)
Solution for reading pictures with stable delay by OpenCV
最近在做对代码的延时标定,发现了一个问题,图像处理已经达到了20ms每循环,但OpenCV的视频帧整体延时了500ms,并且第一帧收帧时如果在500ms以内就imshow帧,则出现错误中断。
搜寻了很久解决方案,有用的相关链接是以下两个:
https://blog.csdn.net/qq_24345721/article/details/102544550
https://blog.csdn.net/sazass/article/details/106946915
Opencv的videocapture库在开启后,会将照片数据不断存入缓冲区,而代码会将该缓冲区从时间最早的那张图片开始处理,如果代码处理速度小于存缓冲区的速度,则缓冲区的照片一直是满的,程序一直取的是缓冲区最早的那张照片,因此会出现几百毫秒的延迟。
解决方案:
新建一个线程,在该线程创建一个Vector < Mat >容器,并不停地将OpenCV缓冲区的照片以堆栈的形式存到该容器中,而主线程的处理程序以取栈顶的方式从容器中取出要处理的照片,因此,主程序将一直处理的是最新的照片。
#include <opencv2\opencv.hpp>
#include <opencv2\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <thread>
#include <mutex>
#include <time.h>
#include ...
using namespace cv;
using namespace std;
//缓存容器
vector<Mat> m_vec_frame;
//互斥锁
mutex m_mutex;
//videocapture
VideoCapture capture;
void run();
bool get_frame(Mat &frame);
void put_frame(Mat frame);
int main(int argc, char* argv)
{
Mat frame;
//开始线程
thread th1(run);//实例化一个线程对象th1,使用函数t1构造,然后该线程就开始执行了
th1.detach();
Sleep(2000);//要等待一段时间等线程一初始化完成,容器里会是空的,这里等待2000ms
while (1)
{
bool ret = get_frame(frame);
if (ret == false || frame.empty()) {
cout << "false!" << endl;
}
cv::imshow("【视频1】", frame);
waitKey(50);
}
return 0;
}
void run()
{
capture.open(1);
capture.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));//参照解决方案(一)
capture.set(CV_CAP_PROP_FRAME_WIDTH, 1600); //设置捕获视频的宽度
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1200); //设置捕获视频的高度
if (!capture.isOpened()) //判断是否成功打开相机
{
cout << "captureOpen failed!" << endl;
}
Mat current_frame;
capture >> current_frame;
resize(current_frame, current_frame, Size(current_frame.cols / 2, current_frame.rows / 2), 0, 0, INTER_LINEAR);
Sleep(50);//初始化一定要有这个初步等待延时
while (1)
{
capture >> current_frame;
resize(current_frame, current_frame, Size(current_frame.cols / 2, current_frame.rows / 2), 0, 0, INTER_LINEAR);//1600*1200太大了,缩小到800*600
if (current_frame.empty())
{
cout << "frame empty\n" << endl;
return;
}
put_frame(current_frame);
}
}
void put_frame(Mat frame)
{
m_mutex.lock();
// 这边采用的更简单粗暴的清理方式,可以根据实际情况自定义清理方式
if (m_vec_frame.size() >3)//测试后发现3的延时最小
m_vec_frame.clear();
//存入容器
m_vec_frame.push_back(frame);
m_mutex.unlock();
return;
}
bool get_frame(Mat &frame)
{
m_mutex.lock();
if (m_vec_frame.size() < 1)
return false;
else
{
//从容器中取图像
frame = m_vec_frame.back();
}
m_mutex.unlock();
return true;
}
总结:
- 通过解决方案(一)和(二),OpenCV延时从500ms降低到160ms,我的大实验循环也是150ms,是一个量级的,可行。
- 剩下的160ms个人认为是硬件延时,不能再减少了。如果有新想法的朋友,欢迎留言讨论。