【问题标题】:CUDA, NPP FiltersCUDA、NPP 过滤器
【发布时间】:2012-09-28 12:16:09
【问题描述】:

CUDA NPP 库支持使用 nppiFilter_8u_C1R 命令过滤图像,但不断出现错误。启动并运行 boxFilterNPP 示例代码没有问题。

eStatusNPP = nppiFilterBox_8u_C1R(oDeviceSrc.data(), oDeviceSrc.pitch(), 
                                  oDeviceDst.data(), oDeviceDst.pitch(), 
                                  oSizeROI, oMaskSize, oAnchor);

但如果我将其更改为使用 nppiFilter_8u_C1R,eStatusNPP 将返回错误 -24 (NPP_TEXTURE_BIND_ERROR)。下面的代码是我对原始 boxFilterNPP 示例所做的修改。

NppiSize oMaskSize = {5,5};
npp::ImageCPU_32s_C1 hostKernel(5,5);

for(int x = 0 ; x < 5; x++){
    for(int y = 0 ; y < 5; y++){
        hostKernel.pixels(x,y)[0].x = 1;
    }
}

npp::ImageNPP_32s_C1 pKernel(hostKernel);

Npp32s nDivisor = 1;

eStatusNPP = nppiFilter_8u_C1R(oDeviceSrc.data(), oDeviceSrc.pitch(), 
                               oDeviceDst.data(), oDeviceDst.pitch(), 
                               oSizeROI, 
                               pKernel.data(),
                               oMaskSize, oAnchor,
                               nDivisor);

这已在 CUDA 4.2 和 5.0 上进行过尝试,结果相同。

当 oMaskSize = {1,1} 时,代码以预期结果运行

【问题讨论】:

  • 您使用的是哪个 CUDA 版本?

标签: c++ image-processing cuda convolution npp


【解决方案1】:

过滤器应用向上和向左延伸的掩码,遵循两个函数之间的卷积反转第二个函数的方向的数学约定。

盒子过滤器遮罩向下向右延伸,这可能更直观。

在任何情况下,问题是由于更改代码中的输入图像必须在有效的 SOURCE[-4, -4) 处采样才能计算 DESTINATION[0, 0] .由于输入图像是通过纹理采样器访问的,因此将源图像指针偏移量绑定 (-4, -4) 会导致您看到的纹理绑定错误。

解决方法:解决此问题的最简单的解决方法是将锚点设置为 (4, 4),这样可以有效地将遮罩向下和向右移动。您仍然需要注意,您希望反转内核数组中的权重(即K[-4, -4] -&gt; K[0, 0]、K[0, 0] -&gt; K[-4, -4] 等)。

【讨论】:

    【解决方案2】:

    感谢您的帮助。 克服了错误,但我看到了一些奇怪的行为。图像会根据我之前运行的程序而变化,并且图像不会显示我要做什么。

    我试图模仿的例子是使用 nppiFilter_8u_C1R 的 nppiFilterBox_8u_C1R,我将内核设置为 1,将 nDivisor 设置为内核的总和。

    此代码仍然是对 boxFilterNPP 示例代码的修改。

    NppiSize oMaskSize = {5,5};
    npp::ImageCPU_32s_C1 hostKernel(5,5);
    for(int x = 0 ; x < 5; x++){
        for(int y = 0 ; y < 5; y++){
            hostKernel.pixels(x,y)[0].x = 1;
        }
    }
    
    npp::ImageNPP_32s_C1 pKernel(hostKernel);
    Npp32s nDivisor = 25;
    NppiPoint oAnchor = {4, 4};
    eStatusNPP = nppiFilter_8u_C1R(oDeviceSrc.data(),oDeviceSrc.pitch(), 
                                   oDeviceDst.data(), oDeviceDst.pitch(), 
                                   oSizeROI, 
                                   pKernel.data(),
                                   oMaskSize, oAnchor,
                                   nDivisor);
    

    由于内核只是一个内核,因此需要反转权重应该不是问题。

    此代码返回的 5 种不同类型的图像如下所示。大多是最后一个返回。

    http://1ordrup.dk/kasper/image/Lena_boxFilter1.jpg
    http://1ordrup.dk/kasper/image/Lena_boxFilter2.jpg
    http://1ordrup.dk/kasper/image/Lena_boxFilter3.jpg
    http://1ordrup.dk/kasper/image/Lena_boxFilter4.jpg 
    http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg
    

    我认为发生这种情况的原因是内核未正确初始化或未使用,因此内核使用了具有伪随机内容的数据。

    【讨论】:

    • 您最终弄清楚为什么我们会看到这些奇怪的输出图像了吗?我发现nppiFilter 适用于 1D 内核,但存在您为 2D 内核描述的问题。我发布了另一个关于它的问题:stackoverflow.com/questions/12902688/…
    【解决方案3】:

    当我将内核存储为ImageCPU/ImageNPP 时,我遇到了同样的问题。

    一个好的解决方案是将内核作为传统的一维数组存储在设备上。我试过了,它给了我很好的结果(而且没有那些不可预测或垃圾图像)。

    感谢 this StackOverflow post 中的 Frank Jargstorff 提出的一维创意。

    NppiSize oMaskSize = {5,5};
    Npp32s hostKernel[5*5];
    
    for(int x = 0 ; x < 5; x++){
        for(int y = 0 ; y < 5; y++){
            hostKernel[x*5+y] = 1;
        }
    }
    
    Npp32s* pKernel; //just a regular 1D array on the GPU
    cudaMalloc((void**)&pKernel, 5 * 5 * sizeof(Npp32s));
    cudaMemcpy(pKernel, hostKernel, 5 * 5 * sizeof(Npp32s), cudaMemcpyHostToDevice);
    

    使用this original image,这是我使用一维内核数组从您的代码中得到的模糊结果:

    我使用的其他参数:

    Npp32s nDivisor = 25;
    NppiPoint oAnchor = {4, 4};
    

    【讨论】:

      猜你喜欢
      • 2016-12-09
      • 2019-06-27
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多