C++ Nvidia NPP nppiFilter与2d内核进行卷积时会产生垃圾

C++ Nvidia NPP nppiFilter与2d内核进行卷积时会产生垃圾,c++,image-processing,cuda,convolution,npp,C++,Image Processing,Cuda,Convolution,Npp,提供nppiFilter函数,用于将用户提供的映像与用户提供的内核进行卷积。对于一维卷积核,nppiFilter工作正常。但是,nppiFilter正在为2D内核生成垃圾映像 我使用典型的Lena图像作为输入: 下面是我用1D卷积内核进行的实验,它可以产生良好的输出 #include <npp.h> // provided in CUDA SDK #include <ImagesCPU.h> // these image libraries are also in C

提供
nppiFilter
函数,用于将用户提供的映像与用户提供的内核进行卷积。对于一维卷积核,
nppiFilter
工作正常。但是,
nppiFilter
正在为2D内核生成垃圾映像

我使用典型的Lena图像作为输入:


下面是我用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); 
}
下面是使用2D内核的输出图像
[-1 0 1;-1 0 1;-1 0 1]

我做错了什么?

描述了一个类似的问题,如用户Steenstrup的图像所示:


最后几点注意事项:

  • 对于2D内核,对于某些锚定值(例如,
    nppipointoanchor={0,0}
    {1,1}
    ),我得到error
    -24
    ,根据。这一问题在报告中简要提到
  • 这段代码非常冗长。这不是主要问题,但是有人对如何使代码更简洁有什么建议吗

您正在为内核阵列使用2D内存分配器。内核阵列是密集的一维阵列,而不是典型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)。

啊,太好了。我现在正在尝试1D
cudamaloc
和1D
cudaMemcpy
。另外,听起来好像
ScaleFactor=0
不会给出缩放,对吗?使用1D malloc和memcpy解决了这个问题!!谢谢这是使用2d 3x3内核处理的图像:如果NPP按
2^(-ScaleFactor)
缩放,那么我认为
ScaleFactor=0
应该给出1的除数。但是,设置
ScaleFactor=0
会给我一个空白图像。
//1D instead of 2D
cudaMalloc((void**)&deviceKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s));
cudaMemcpy(deviceKernel, hostKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s), cudaMemcpyHostToDevice);