cvQueryFrame速度过慢的问题
转载请注明出处
我的 上一篇博文中讲到通过cvQueryFrame读取摄像头的图像,其速度是受到硬件限制的。换句话说,无论你怎么写代码,cvQueryFrame都有一个反应速度。对于笔记本电脑自带的摄像头,大约是50ms左右。
但是有的情况下,即使图像不能及时更新,我们也希望可以快速的读取到一帧,而不是卡在那里等待总线向我们传输新的一帧。图像可以以50ms一次的效率更新(这受限于硬件是没办法的),但是我们希望可以以更高的频率获取图像并且进行处理。这种情况往往出现在一些半物理的实时系统中,系统的整体周期并不以图像为核心,因此需要图像无论何时都能短周期读取,而不会影响系统的整体周期。
这次在完成一个任务的时候,我就遇到了一个问题,程序的运行周期是严格的20ms,一个周期必须准时运行完毕。但是图像读取到达了40ms左右。因此利用多线程的思路,开发了并行的读取方式,让图像的拉取和图像的处理程序在两个线程里独立完成。这样来解决了问题。
实现代码及思路
实现思路
具体思路就是数据处理与从硬件拉取数据两者分开,在两个线程内。
从硬件拉取数据的线程,每拉取到一帧新的数据,就储存在数据中转区。数据处理的线程每一个程序运行循环,从数据中转区复制出数据进行使用。数据中转区用线程锁锁住防止两个线程冲突访问。
C++多线程相关的知识参考这篇文章即可。
实现环境
实现环境为c++11下opencv 2.4.9
#include <thread>
#include <mutex>
#include <cv.h>
多线程代码
需要定义的变量如下:
CvCapture *capture;//数据流指针
thread *capThread;//图像读取线程指针
IplImage *pSrcImg;//中转图像所在指针
mutex *mut;//线程锁
IplImage *getPic;//最终获取到的图像指针
int *endFlag;//线程结束标志变量指针
系统初始化代码:
IplImage *testPic;//用于测试获取到的图像大小的图像指针
CvSize srcImgSize;//图像大小变量
capture = cvCaptureFromCAM(0);//打开摄像头,获取视频流
if (capture == nullptr)
{
cout << "获取视频流错误" << endl;
return ;
}
mut = new mutex;//新建一个线程锁
testPic = cvQueryFrame(capture);//获取一张测试图像
srcImgSize = cvGetSize(testPic);//获取测试图像大小
pSrcImg = cvCreateImage(cvSize(srcImgSize.width, srcImgSize.height), IPL_DEPTH_8U, 3);//根据测试图像创建中转图像缓存
getPic = cvCreateImage(cvSize(srcImgSize.width, srcImgSize.height), IPL_DEPTH_8U, 3);//创建最终获取图像的缓存
endFlag = new int;//新建线程结束标志位并且设为0
*endFlag = 0;
capThread = new thread(captureThread,capture,pSrcImg,mut,endFlag);//启动线程
线程函数的定义
void captureThread(CvCapture *capture,IplImage *pSrcImg,mutex *mut,int *end)
{
while(1)//循环执行
{
IplImage *pic;//创建一个图像指针
if (pic = cvQueryFrame(capture))//指针指向视频流抓取到的图片的位置
{
}
else //如果没有获取图像则报错退出
{
cvReleaseCapture(&capture);
cout << "no image stream!\n";
system("pause");
return ;
}
mut->lock();//锁上进程锁,防止冲突访问
cvCopy(pic,pSrcImg);//将图像里的信息保存到中转图像中。
if(*end)//如果标志位是1的话则关闭线程
{
return ;
}
mut->unlock();//解锁进程锁
}
}
处理数据的循环
while(循环条件)
{
mut->lock();
cvCopy(pSrcImg,getPic);//从中转数据拷到最终数据区。(其实也可以不这样,但是为了程序鲁棒性这样以后好改)
mut->unlock();
一些操作(getPic);
}
关闭线程的代码
mut->lock();
*endFlag = 1;//设置标志位
mut->unlock();
capThread->join();//等待线程结束
释放内存也是必要的
cvReleaseImage(&pSrcImg);
cvReleaseImage(&getPic);
cvReleaseCapture(&capture);
delete capThread;
delete mut;
delete endFlag;
转载请注明出处
针对cvQueryFrame读取摄像头速度慢的问题,本文提出了将数据获取与处理分别在两个线程中进行的解决方案。在C++11环境下,通过创建线程并使用线程锁保护数据中转区,确保线程安全,有效提升了运行效率。
1009

被折叠的 条评论
为什么被折叠?



