OpenCV - 将 GpuMat 复制到 cuda 设备数据中

Posted

技术标签:

【中文标题】OpenCV - 将 GpuMat 复制到 cuda 设备数据中【英文标题】:OpenCV - Copy GpuMat into cuda device data 【发布时间】:2019-01-02 05:08:48 【问题描述】:

我正在尝试将cv::cuda::GpuMat 中的数据复制到要在内核中使用的uint8_t* 变量中。

GpuMat 包含分辨率为 752x480 且类型为 CV_8UC1 的图像数据。下面是示例代码:

uint8_t *imgPtr;
cv::Mat left, downloadedLeft;
cv::cuda::GpuMat gpuLeft;

left = imread("leftview.jpg", cv::IMREAD_GRAYSCALE);
gpuLeft.upload(left);

cudaMalloc((void **)&imgPtr, sizeof(uint8_t)*gpuLeft.rows*gpuLeft.cols);
cudaMemcpyAsync(imgPtr, gpuLeft.ptr<uint8_t>(), sizeof(uint8_t)*gpuLeft.rows*gpuLeft.cols, cudaMemcpyDeviceToDevice);

// following code is just for testing and visualization...
cv::cuda::GpuMat gpuImg(left.rows, left.cols, left.type(), imgPtr);
gpuImg.download(downloadedLeft);
imshow ("test", downloadedLeft);
waitKey(0);

但输出不如预期。以下分别是输入和输出图像。

输入

输出

我尝试将cv::Mat 源提供给cudaMemcpy。它似乎工作正常。问题似乎出在cv::cuda::GpuMatcudaMemcpy 上。 here

中讨论了类似的问题

此外,如果图像为 256 或 512,则程序似乎运行良好。

我错过了什么? 752x480 的图片应该怎么做才能正常工作?

【问题讨论】:

在它告诉你In contrast with Mat, in most cases GpuMat::isContinuous() == false . This means that rows are aligned to a size depending on the hardware. Single-row GpuMat is always a continuous matrix.的文档中,我对 GpuMat 的工作并不多,所以我不确定如何知道填充了多少以及如何避免它...... 感谢您的即时回复@api55。我也被困在同一部分。另外,我想了解它如何处理宽度为 256 或 512 的图像。 @talonmies 你能详细说明一下吗 没有。直接去阅读GpuMat文档,看看step属性 @sam ,它之所以起作用,是因为它不需要具有此类值的填充,可能是填充到 2 的幂,在这种情况下不需要。填充用于将行对齐到某个数字。 【参考方案1】:

OpenCV GpuMat 使用跨步存储(因此图像不会连续存储在内存中)。简而言之,您的示例在大多数情况下都失败了,因为

    您不会将整个图像复制到 CUDA 内存分配中,并且 从 GPU 指针创建第二个 GpuMat 实例时,您没有正确指定内存布局。

通过阅读文档,您可能想要这样的东西:

uint8_t *imgPtr;
cv::Mat left, downloadedLeft;
cv::cuda::GpuMat gpuLeft;

left = imread("leftview.jpg", cv::IMREAD_GRAYSCALE);
gpuLeft.upload(left);

cudaMalloc((void **)&imgPtr, gpuLeft.rows*gpuLeft.step);
cudaMemcpyAsync(imgPtr, gpuLeft.ptr<uint8_t>(), gpuLeft.rows*gpuLeft.step, cudaMemcpyDeviceToDevice);

// following code is just for testing and visualization...
cv::cuda::GpuMat gpuImg(left.rows, left.cols, left.type(), imgPtr, gpuLeft.step);
gpuImg.download(downloadedLeft);
imshow ("test", downloadedLeft);
waitKey(0);

[由从未使用过 OpenCV、未编译或测试的人编写,使用风险自负]

只有当 GpuMat 的行间距与列数乘以存储在矩阵中的类型大小相同时,您的代码才能正常工作。这可能是大小为 2 的整数次方的图像。

【讨论】:

以上是关于OpenCV - 将 GpuMat 复制到 cuda 设备数据中的主要内容,如果未能解决你的问题,请参考以下文章

提取一个连续的 OpenCV cuda::GpuMat?

gpumat 和 mat 错误

请问opencv的GPU模块里,与GpuMat挂钩的PtrStep 和 PtrStepSz两个数据结构有啥区别?

如何在 CUDA 内核中正确操作 CV_16SC3 Mat

数据库的平滑扩展

将 cv::cuda::GpuMat 与推力和测试推力 API 一起使用时出现问题