【OpenCV】CUDA模块6:Stream

cv::cuda::Stream 是 OpenCV CUDA 模块中的一个类,它表示一个 CUDA 流。

CUDA 流是 CUDA 并行计算模型中的一个核心概念,允许在 GPU 上并行执行多个任务。通过将任务分配到不同的流中,可以实现任务间的并行化,从而提高 GPU 的利用率和计算效率。

在 CUDA 编程中,流是一系列按照特定顺序执行的命令。这些命令可以是内存传输操作(如从主机到设备的数据传输)、核函数执行等。同一个流中的命令会按照它们被添加到流中的顺序执行,而不同流中的命令则可以并行执行,具体取决于 GPU 的硬件资源和调度策略。

cv::cuda::Stream 类提供了创建和操作 CUDA 流的功能。你可以使用这个类来创建新的流,或者使用默认流(通常是流0)。在 OpenCV 的 CUDA 模块中,许多函数都接受一个 Stream 参数,以便你可以指定在哪个流上执行该操作。

以下是使用 cv::cuda::Stream 的基本示例:

#include <opencv2/opencv.hpp>  
#include <opencv2/cudaimgproc.hpp>  
  
int main()  
{  
    // 初始化 CUDA  
    cv::cuda::setDevice(0); // 设置要使用的 GPU 设备  
  
    // 创建两个 CUDA 流  
    cv::cuda::Stream stream1;  
    cv::cuda::Stream stream2;  
  
    // 分配 GPU 内存并上传数据到 GPU 
    cv::Mat hostMat1 = ...; // 从某处获取或创建图像数据  
    cv::Mat hostMat2 = ...;  
    cv::cuda::GpuMat gpuMat1(hostMat1);  
    cv::cuda::GpuMat gpuMat2(hostMat2);  
  
    // 在流1上执行某个操作(例如阈值处理)  
    cv::cuda::threshold(gpuMat1, gpuMat1, 128.0, 255.0, cv::THRESH_BINARY, stream1);  
  
    // 在流2上执行另一个操作(例如模糊)  
    cv::cuda::GaussianBlur(gpuMat2, gpuMat2, cv::Size(5, 5), 0, 0, stream2);  
  
    // 等待流1和流2上的操作完成  
    stream1.waitForCompletion();  
    stream2.waitForCompletion();  
  
    // 下载结果到 CPU(如果需要的话)  
    cv::Mat result1(gpuMat1);  
    cv::Mat result2(gpuMat2);  
  
    // ... 处理或显示 result1 和 result2 ...  
  
    return 0;  
}

在实际应用中,通常不会在每个操作之后都调用 waitForCompletion(),因为这样会失去并行化的优势。正确的做法是让操作在后台异步执行,直到你需要使用结果时才同步流。

正确的示例应该是这样的:

#include <opencv2/opencv.hpp>  
#include <opencv2/cudaimgproc.hpp>  
  
int main()  
{  
    // 初始化 CUDA  
    cv::cuda::setDevice(0); // 设置要使用的 GPU 设备  
  
    // 创建两个 CUDA 流  
    cv::cuda::Stream stream1 = cv::cuda::Stream::Null(); // 使用默认流或创建新流  
    cv::cuda::Stream stream2 = cv::cuda::Stream::Null(); // 这里为了简化示例使用默认流,实际应该创建新流  
  
    // 分配 GPU 内存并上传数据到 GPU  
    cv::Mat hostMat1 = ...; // 从某处获取或创建图像数据  
    cv::Mat hostMat2 = ...;  
    cv::cuda::GpuMat gpuMat1(hostMat1);  
    cv::cuda::GpuMat gpuMat2(hostMat2);  
  
    // 在流1上执行某个操作(例如阈值处理)  
    // 注意:这里由于使用了默认流,实际上并没有并行化。为了并行化,应该创建不同的非默认流。  
    cv::cuda::threshold(gpuMat1, gpuMat1, 128.0, 255.0, cv::THRESH_BINARY); // 默认使用 Null 流  
  
    // 在流2上执行另一个操作(例如模糊)  
    // 注意:同上,这里也并没有真正并行化。  
    cv::cuda::GaussianBlur(gpuMat2, gpuMat2, cv::Size(5, 5), 0, 0); // 默认使用 Null 流  
  
    // ... 如果需要的话,可以在这里同步流 ...  
    // 但由于我们使用的是默认流,所以不需要(也不应该)调用 waitForCompletion()。  
  
    // 下载结果到 CPU(如果需要的话)  
    cv::Mat result1(gpuMat1); // 这会自动同步流(如果使用了非默认流的话)  
    cv::Mat result2(gpuMat2); // 同上  
  
    // ... 处理或显示 result1 和 result2 ...  
  
    return 0;  
}

然而,上面的代码示例实际上并没有利用到 CUDA 的并行性,因为我们没有创建真正的独立流。为了真正实现并行处理,你需要创建不同的流并将它们传递给 CUDA 函数。

这里是一个更正确的示例框架:

#include <opencv2/opencv.hpp>  
#include <opencv2/cudaimgproc.hpp>  
  
int main()  
{  
    // 初始化 CUDA 并设置设备  
    cv::cuda::setDevice(0);  
  
    // 创建独立的 CUDA 流以实现并行处理  
    cv::cuda::Stream stream1 = cv::cuda::Stream::Stream(); // 创建新流1  
    cv::cuda::Stream stream2 = cv::cuda::Stream::Stream(); // 创建新流2  
  
    // 准备数据并上传到 GPU  
    cv::Mat hostMat1 = ...; // 加载或生成图像1  
    cv::Mat hostMat2 = ...; // 加载或生成图像2  
    cv::cuda::GpuMat gpuMat1(hostMat1); // 上传到 GPU  
    cv::cuda::GpuMat gpuMat2(hostMat2); // 上传到 GPU  
  
    // 在不同流上异步执行操作  
    cv::cuda::threshold(gpuMat1, gpuMat1, 128.0, 255.0, cv::THRESH_BINARY, stream1); // 在流1上执行阈值处理  
    cv::cuda::GaussianBlur(gpuMat2, gpuMat2, cv::Size(5, 5), 0, 0, stream2); // 在流2上执行高斯模糊  
  
    // ... 这里可以继续添加其他操作到不同的流 ...  
  
    // 在需要结果之前同步流(通常是在下载数据到 CPU 之前)  
    // 可以通过调用 cuda::Stream::waitForCompletion() 或者简单地在下载数据时隐式同步  
    stream1.waitForCompletion(); // 等待流1完成(可选,因为下载操作会隐式同步)  
    stream2.waitForCompletion(); // 等待流2完成(可选,因为下载操作会隐式同步)  
  
    // 将结果从 GPU 下载到 CPU(如果需要)  
    // 注意:这个操作会隐式地同步流,所以上面的 waitForCompletion() 调用实际上是多余的。  
    cv::Mat result1(gpuMat1); // 下载结果1到 CPU(隐式同步流1)  
    cv::Mat result2(gpuMat2); // 下载结果2到 CPU(隐式同步流2)  
  
    // ... 处理或显示 result1 和 result2 ...  
  
    return 0;  
}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值