Oct 14, 2018 原创文章

  OpenCV GPU 模块学习 (2)GPU的流操作

使用OpenCV gpu::Stream 类进行流操作

分享到: 0

请保证您的浏览器支持MathJax插件,以免数学公式无法显示


软件信息
OpenCV Version : 2.4.13.6
CUDA Version : 8.0

OpenCV gpu::Stream 手册
https://docs.opencv.org/2.4.13.6/modules/gpu/doc/data_structures.html#gpu::Stream

OpenCV 通过 gpu::Stream 类封装了一个异步调用。

在OpenCV的gpu模块中提供的一些函数具有附加 gpu::Stream 参数的重载,这些函数可以进行初始化工作,启动GPU核函数,并且可以在结果计算完成之前返回。

编程思想:

新建一个Stream队列,使用 gpu::Strean::enqueueUpload() 将需要操作的数据放入队列中,然后在队列中进行所需要的操作,可以通过gpu::Stream::queryIfComplete() 和 gpu::Stream::waitForCompletion() 判断和检测操作是否完成。等待队列中的操作完成,使用 gpu::strean::enqueueDownload() 将数据返回。相较于默认的数据传输方法,使用Stream队列实现了数据的异步调用,不需要等待数据全部上传完成后再对数据进行操作,只需要在确定所需的数据,即可在上传数据的同时对数据进行操作,达到GPU计算的同时进行GPU与CPU之间的数据交换,从而达到提升效率的目。

关于CPU和GPU异步并行的概念和意义详见:《CUDA并行编程学习(5)– 异步并行》

类的内容:


class CV_EXPORTS Stream
{
public:
    Stream();
    ~Stream();

    Stream(const Stream&);
    Stream& operator=(const Stream&);

    bool queryIfComplete();
    void waitForCompletion();

    void enqueueDownload(const GpuMat& src, CudaMem& dst);
    void enqueueDownload(const GpuMat& src, Mat& dst);

    void enqueueUpload(const CudaMem& src, GpuMat& dst);
    void enqueueUpload(const Mat& src, GpuMat& dst);

    void enqueueCopy(const GpuMat& src, GpuMat& dst);

    void enqueueMemSet(const GpuMat& src, Scalar val);
    void enqueueMemSet(const GpuMat& src, Scalar val, const GpuMat& mask);

    void enqueueConvert(const GpuMat& src, GpuMat& dst, int type,
                        double a = 1, double b = 0);

    typedef void (*StreamCallback)(Stream& stream, int status, void* userData);
    void enqueueHostCallback(StreamCallback callback, void* userData);
};

例程:

通过该例程,简单展示了opencv gpu::Stream 类及其方法的使用。



#include "iostream"
#include "opencv2/opencv.hpp"
#include "opencv2/gpu/gpu.hpp"


int main(int argc, char *argv[])
{
    // 读取图片为 8bit单通道 Mat
    cv::Mat rawImage = cv::imread("lena.jpg", CV_8UC1);
    cv::imshow("rawResult", rawImage);

    // 申请Page-locked内存 allocate page-locked memory
    cv::gpu::CudaMem host_src_pl(rawImage.cols, rawImage.rows, CV_8UC1, cv::gpu::CudaMem::ALLOC_PAGE_LOCKED);
    cv::gpu::CudaMem host_dst_pl;

    // 填满申请到的PL内存 Do something to fill host_src_pl
    memcpy(host_src_pl.datastart, rawImage.datastart, host_src_pl.cols * host_src_pl.rows);

    // 创建GpuMat
    cv::gpu::GpuMat gpu_src,gpu_dst;

    // 创建Stream
    cv::gpu::Stream stream;
    
    // 从主机(CPU)向设备(GPU)复制数据
    stream.enqueueUpload(host_src_pl, gpu_src);

    // 在设备中对数据进行处理
    cv::gpu::threshold(gpu_src, gpu_dst, 128.0, 255.0, CV_THRESH_BINARY, stream);

    // 从设备向主机复制数据
    stream.enqueueDownload(gpu_dst, host_dst_pl);

    // 在主机中与设备并行的进行其他的处理
    cv::Mat binImage;
    cv::threshold(rawImage, binImage, 128.0, 255.0, CV_THRESH_BINARY);

    // 等待设备完成计算任务
    stream.waitForCompletion();

    // 现在可以使用设备中计算得到的数据
    cv::Mat host_dst = host_dst_pl;

    cv::imshow("gpuResult", host_dst);
    cv::imshow("cpuResult", binImage);
    cv::waitKey();

    return 0;
}



参考资料:

1、opencv中GPU的流操作 https://blog.csdn.net/eyes366/article/details/48438397

2、how to use gpu::Stream in OpenCV? https://stackoverflow.com/questions/17842827/how-to-use-gpustream-in-opencv


打赏


感谢您的支持,我会继续努力的!

扫码支持

长按识别二维码或打开支付宝扫一扫 完成打赏
或 使用<支付宝链接>打赏


关闭

分享到: 0