利用多线程方案解决cvQueryFrame读取摄像头速度过慢的问题

cvQueryFrame速度过慢的问题

文章目录

  • cvQueryFrame速度过慢的问题
  • 实现代码及思路
    • 实现思路
    • 实现环境
    • 多线程代码
      • 如果有帮助请点个赞谢谢

转载请注明出处
我的 上一篇博文中讲到通过cvQueryFrame读取摄像头的图像,其速度是受到硬件限制的。换句话说,无论你怎么写代码,cvQueryFrame都有一个反应速度。对于笔记本电脑自带的摄像头,大约是50ms左右。
但是有的情况下,即使图像不能及时更新,我们也希望可以快速的读取到一帧,而不是卡在那里等待总线向我们传输新的一帧。图像可以以50ms一次的效率更新(这受限于硬件是没办法的),但是我们希望可以以更高的频率获取图像并且进行处理。这种情况往往出现在一些半物理的实时系统中,系统的整体周期并不以图像为核心,因此需要图像无论何时都能短周期读取,而不会影响系统的整体周期。
这次在完成一个任务的时候,我就遇到了一个问题,程序的运行周期是严格的20ms,一个周期必须准时运行完毕。但是图像读取到达了40ms左右。因此利用多线程的思路,开发了并行的读取方式,让图像的拉取和图像的处理程序在两个线程里独立完成。这样来解决了问题。

实现代码及思路

实现思路

具体思路就是数据处理与从硬件拉取数据两者分开,在两个线程内。
从硬件拉取数据的线程,每拉取到一帧新的数据,就储存在数据中转区。数据处理的线程每一个程序运行循环,从数据中转区复制出数据进行使用。数据中转区用线程锁锁住防止两个线程冲突访问。
C++多线程相关的知识参考这篇文章即可。

实现环境

实现环境为c++11下opencv 2.4.9

#include 
#include 
#include 

多线程代码

需要定义的变量如下:

    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;

转载请注明出处

如果有帮助请点个赞谢谢

你可能感兴趣的:(openCV)