gpt4 book ai didi

c++ - Nvidia NPP nppiFilter 在与 2d 内核卷积时产生垃圾

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:45:10 26 4
gpt4 key购买 nike

Nvidia Performance Primitives (NPP)提供 nppiFilter 函数,用于将用户提供的图像与用户提供的内核进行卷积。对于一维卷积核,nppiFilter 可以正常工作。但是,nppiFilter 正在为 2D 内核生成垃圾图像。

我使用典型的 Lena 图像作为输入: enter image description here


这是我使用 1D 卷积核进行的实验,它产生了良好的输出。

#include <npp.h> // provided in CUDA SDK
#include <ImagesCPU.h> // these image libraries are also in CUDA SDK
#include <ImagesNPP.h>
#include <ImageIO.h>

void test_nppiFilter()
{
npp::ImageCPU_8u_C1 oHostSrc;
npp::loadImage("Lena.pgm", oHostSrc);
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc); // malloc and memcpy to GPU
NppiSize kernelSize = {3, 1}; // dimensions of convolution kernel (filter)
NppiSize oSizeROI = {oHostSrc.width() - kernelSize.width + 1, oHostSrc.height() - kernelSize.height + 1};
npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height); // allocate device image of appropriately reduced size
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
NppiPoint oAnchor = {2, 1}; // found that oAnchor = {2,1} or {3,1} works for kernel [-1 0 1]
NppStatus eStatusNPP;

Npp32s hostKernel[3] = {-1, 0, 1}; // convolving with this should do edge detection
Npp32s* deviceKernel;
size_t deviceKernelPitch;
cudaMallocPitch((void**)&deviceKernel, &deviceKernelPitch, kernelSize.width*sizeof(Npp32s), kernelSize.height*sizeof(Npp32s));
cudaMemcpy2D(deviceKernel, deviceKernelPitch, hostKernel,
sizeof(Npp32s)*kernelSize.width, // sPitch
sizeof(Npp32s)*kernelSize.width, // width
kernelSize.height, // height
cudaMemcpyHostToDevice);
Npp32s divisor = 1; // no scaling

eStatusNPP = nppiFilter_8u_C1R(oDeviceSrc.data(), oDeviceSrc.pitch(),
oDeviceDst.data(), oDeviceDst.pitch(),
oSizeROI, deviceKernel, kernelSize, oAnchor, divisor);

cout << "NppiFilter error status " << eStatusNPP << endl; // prints 0 (no errors)
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch()); // memcpy to host
saveImage("Lena_filter_1d.pgm", oHostDst);
}

以上代码与内核 [-1 0 1] 的输出——它看起来像一个合理的渐变图像: enter image description here


但是,如果我使用 2D 卷积核,nppiFilter 会输出垃圾图像。以下是我从上面的代码更改为使用 2D 内核运行的内容 [-1 0 1; -1 0 1; -1 0 1]:

NppiSize kernelSize = {3, 3};
Npp32s hostKernel[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
NppiPoint oAnchor = {2, 2}; // note: using anchor {1,1} or {0,0} causes error -24 (NPP_TEXTURE_BIND_ERROR)
saveImage("Lena_filter_2d.pgm", oHostDst);

下面是使用2D核[-1 0 1; -1 0 1; -1 0 1].

我做错了什么?

enter image description here

This StackOverflow post描述了一个类似的问题,如用户 Steenstrup 的图片所示:http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg


一些最后的说明:

  • 对于 2D 内核,对于某些 anchor 值(例如 NppiPoint oAnchor = {0, 0}{1, 1}),我得到错误 -24,根据 NPP User Guide 转换为 NPP_TEXTURE_BIND_ERROR . this StackOverflow post 中简要提到了这个问题.
  • 这段代码非常冗长。这不是主要问题,但有人对如何使这段代码更简洁有任何建议吗?

最佳答案

您正在为内核数组使用二维内存分配器。内核阵列是密集的一维阵列,而不是像典型 NPP 图像那样的二维跨步阵列。

只需将 2D CUDA malloc 替换为大小为 kernelWidth*kernelHeight*sizeof(Npp32s) 的简单 cuda malloc,然后执行普通的 CUDA memcopy 而不是 memcopy 2D。

//1D instead of 2D
cudaMalloc((void**)&deviceKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s));
cudaMemcpy(deviceKernel, hostKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s), cudaMemcpyHostToDevice);

顺便说一句,1 的“缩放因子”并不意味着没有缩放。缩放发生在因子 2^(-ScaleFactor) 上。

关于c++ - Nvidia NPP nppiFilter 在与 2d 内核卷积时产生垃圾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12902688/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com