CUDA,NPP过滤器

时间:2012-10-08 09:04:59

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

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}

时,代码以预期结果运行

3 个答案:

答案 0 :(得分:7)

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

盒式过滤器面罩向下和向右延伸,这可能更直观。

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

解决方法:此问题的最简单的解决方法是将锚点设置为(4,4),这将有效地将掩码向下移动到右侧。你仍然需要知道你想要反转内核数组中的权重(即K[-4, -4] -> K[0, 0]K[0, 0] -> K[-4, -4]等。)。

答案 1 :(得分:2)

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

一个好的解决方案是将内核存储为设备上的传统1D阵列。我尝试了这个,它给了我很好的结果(并没有那些不可预测或垃圾图像)。

感谢Frank Jargstorff在this StackOverflow post中提出的1D想法。

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,这是我使用1D内核数组从代码中获得的模糊结果: enter image description here

我使用的其他参数:

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

答案 2 :(得分:1)

感谢您的帮助。 克服了错误,但我看到了一些奇怪的行为。图像会根据我之前运行的程序而改变,图像不会显示我想要的内容。

我试图模仿的例子是使用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

我认为发生这种情况的原因是内核没有正确启动或没有使用,因此内核使用了伪随机内容的数据。