opencv3UMat介绍,以及测试比较opencl,cuda性能

来源:互联网 发布:微信数据怎么放到sd卡 编辑:程序博客网 时间:2024/05/21 18:44

在opencv中,已经嵌入了opencl运行的方式,通过使用UMat对象,opencv会自动在支持OpenCL的设备上使用GPU运算,在不支持OpenCL的设备仍然使用CPU运算,这样就避免了程序运行失败,而且统一了接口。

一般正常基于CPU的读写视频一帧图像代码如下:

cv::Mat inMat, outMat;vidInput >> inMat;cv::cvtColor(inMat, outMat, cv::COLOR_RGB2GRAY);vidOutput << outMat;
基于OpenCL的GPU方式读写视频一帧图像代码如下:

cv::Mat inMat, outMat;vidInput >> inMat;cv::ocl::oclMat inOclMat(inMat);cv::ocl::oclMat outOclMat;cv::ocl::cvtColor(inOclMat, outOclMat, cv::COLOR_RGB2GRAY);outMat = outOclMat;vidOutput << outMat;

上述代码通过添加ocl前缀空间实现OpenCL支持设备的GPU运算能力提高。但是上述代码在不支持OpenCL的平台上还会运行失败,使用起来及其不方便。对开发者来说不是统一API和底层透明。

而如果在OpenCV3中使用UMat,则如下:

cv::UMat inMat, outMat;vidInput >> inMat;cv::cvtColor(inMat, outMat, cv::COLOR_RGB2GRAY);vidOutput << outMat;
这样就无需像OpenCV2中那样通过显式声明的调用方式。很明显UMat与Mat极其类似。而且两者之间是可以相互转换的。

从UMat中获取Mat对象使用UMat的get方法UMat::getMat(int access_flags)支持的FLAG如下:

  • ACCESS_READ
  • ACCESS_WRITE
  • ACCESS_RW
  • ACCESS_MASK
  • ACCESS_FAST 
    最常用的就是读写,注意当使用这种方式的时候UMat对象将会被LOCK直到CPU使用获取Mat对象完成操作,销毁临时Mat对象之后,UMat才可以再被使用。
反过来也是一样,但是有的时候我用会出问题

所以我会直接使用cv::CopyTo(),可能这样做会减少错误,但不知道会有什么影响

cv::UMat aMat;cv::Mat bMat;bMat.CopyTo(aMat);aMat.CopyTo(bMat);

UMat不能提取其中某个特定元素的值,毕竟已经存到gpu中了,提取方法是先转换成Mat,再提取,下面提供一种提取方法

UMat test_umat;test_umat.getMat(ACCESS_READ).at<uchar>(row, column);
注意,不要过多地进行Mat和UMat之间地转化,因为内存显存之间传递信息耗时很大,这是像我这种初学者,很容易犯的错误。



之后我打算用一段程序测试OpenCL和CUDA的性能,程序如下:

#include <iostream>#include <opencv2/opencv.hpp>#include <opencv2/core/ocl.hpp>#include <opencv2/core/cuda.hpp>#include <opencv2/cudaobjdetect.hpp>#include <opencv2/cudaimgproc.hpp>int main(int argc, char**argv) {    std::cout << "OpenCV version=" << std::hex << CV_VERSION << std::dec << std::endl;    cv::Mat frame;    cv::UMat uframe, uFrameGray;    cv::cuda::GpuMat image_gpu, image_gpu_gray;    cv::VideoCapture capture("path_to_the_video");    bool useOpenCL = (argc == 2);    std::cout << "Use OpenCL=" << useOpenCL << std::endl;    cv::ocl::setUseOpenCL(useOpenCL);    bool useCuda = (argc == 3);    std::cout << "Use CUDA=" << useCuda << std::endl;    cv::Ptr<cv::CascadeClassifier> cascade = cv::makePtr<cv::CascadeClassifier>("data/lbpcascades/lbpcascade_frontalface_at.xml");    cv::Ptr<cv::cuda::CascadeClassifier> cascade_gpu = cv::cuda::CascadeClassifier::create("data/lbpcascades/lbpcascade_frontalface_at.xml");    double time = 0.0;    int nb = 0;    if(capture.isOpened()) {        for(;;) {            capture >> frame;            if(frame.empty() || nb >= 1000) {                break;            }            std::vector<cv::Rect> faces;            double t = 0.0;            if(!useCuda) {                t = (double) cv::getTickCount();                frame.copyTo(uframe);                cv::cvtColor(uframe, uFrameGray, CV_BGR2GRAY);                cascade->detectMultiScale(uFrameGray, faces);                t = ((double) cv::getTickCount() - t) / cv::getTickFrequency();            } else {                t = (double) cv::getTickCount();                image_gpu.upload(frame);                cv::cuda::cvtColor(image_gpu, image_gpu_gray, CV_BGR2GRAY);                cv::cuda::GpuMat objbuf;                cascade_gpu->detectMultiScale(image_gpu_gray, objbuf);                cascade_gpu->convert(objbuf, faces);                t = ((double) cv::getTickCount() - t) / cv::getTickFrequency();            }            time += t;            nb++;            for(std::vector<cv::Rect>::const_iterator it = faces.begin(); it != faces.end(); ++it) {                cv::rectangle(frame, *it, cv::Scalar(0,0,255));            }            std::stringstream ss;            ss << "FPS=" << (nb / time);            cv::putText(frame, ss.str(), cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0,0,255));            cv::imshow("Frame", frame);            char c = cv::waitKey(30);            if(c == 27) {                break;            }        }    }    std::cout << "Mean time=" << (time / nb) << " s" << " ; Mean FPS=" << (nb / time) << " ; nb=" << nb << std::endl;    system("pause");    return 0;}

lbpcascade_frontalface_at.xml
文件可以百度搜索就能下载到,是一个级联分类器训练好的模型,用于识别人脸正面,很常用。具体资料可以参考http://blog.csdn.net/yang_xian521/article/details/6973667

只需要将

    cv::VideoCapture capture("path_to_the_video");

这里填入你想检测的视频的地址,时长最好在十几秒,情况视你的处理器情况所定。

再将

 cv::Ptr<cv::CascadeClassifier> cascade = cv::makePtr<cv::CascadeClassifier>("data/lbpcascades/lbpcascade_frontalface_at.xml");    cv::Ptr<cv::cuda::CascadeClassifier> cascade_gpu = cv::cuda::CascadeClassifier::create("data/lbpcascades/lbpcascade_frontalface_at.xml");

两处填入下载好的xml文件的地址即可运行

运行方式为

g++ -o 文件名 文件名.cpp `pkg-config opencv --cflags --libs`

此处要链接上opencv的库,注意不要少了`这个符号,它在键盘数字1旁边。

如果额外输入一个参数,程序将利用opencl进行加速,如果额外输入两个,程序将利用cuda进行加速,没有额外参数,将正常运行


我的结果很意外,opencl基本没有加速效果,而cuda加速效果很明显,不知道原因在哪里






原创粉丝点击