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

针对cvQueryFrame读取摄像头速度慢的问题,本文提出了将数据获取与处理分别在两个线程中进行的解决方案。在C++11环境下,通过创建线程并使用线程锁保护数据中转区,确保线程安全,有效提升了运行效率。

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;

转载请注明出处

如果有帮助请点个赞谢谢

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值