0

我正在制作一个程序来模糊 CUDA 中的 16 位灰度图像。

在我的程序中,如果我使用 sigma = 20 或 30 的高斯模糊函数,则需要很多时间,而 sigma = 2.0 或 3.0 则速度很快。

我在一些网站上读到,带有 FFT 的高斯模糊适用于大内核大小或大 sigma 值:

  • 这是真的吗?
  • 我应该使用哪种算法:简单的高斯模糊或带 FFT 的高斯模糊?

我的高斯模糊代码如下。在我的代码中,是否有问题?

在此处输入代码

__global__ 
void gaussian_blur(
    unsigned short* const       blurredChannel,                     // return value: blurred channel (either red, green, or blue)
    const unsigned short* const inputChannel,                       // red, green, or blue channel from the original image
    int                         rows, 
    int                         cols,
    const float* const          filterWeight,                       // gaussian filter weights. The weights look like a bell shape.
    int                         filterWidth                         // number of pixels in x and y directions for calculating average blurring
    )
{
    int r           =  blockIdx.y * blockDim.y + threadIdx.y;       // current row
    int c           =  blockIdx.x * blockDim.x + threadIdx.x;       // current column


    if ((r >= rows) || (c >= cols))
    {
        return;
    }

    int           half   = filterWidth / 2;
    float         blur   = 0.f;                             // will contained blurred value
    int           width  = cols - 1;
    int           height = rows - 1;

    for (int i = -half; i <= half; ++i)                 // rows
    {
        for (int j = -half; j <= half; ++j)             // columns
        {
            // Clamp filter to the image border
            int     h       = min(max(r + i, 0), height);
            int     w       = min(max(c + j, 0), width);

            // Blur is a product of current pixel value and weight of that pixel.
            // Remember that sum of all weights equals to 1, so we are averaging sum of all pixels by their weight.
            int     idx     = w + cols * h;                                         // current pixel index
            float   pixel   = static_cast<float>(inputChannel[idx]);

                    idx     = (i + half) * filterWidth + j + half;
            float   weight  = filterWeight[idx];

            blur += pixel * weight;
        }
    }

    blurredChannel[c + r * cols] = static_cast<unsigned short>(blur);
}





void createFilter(float *gKernel,double sigma,int radius)
{

    double r, s = 2.0 * sigma * sigma;

    // sum is for normalization
    double sum = 0.0;

    // generate 9*9 kernel
    int m=0;
    for (int x = -radius; x <= radius; x++)
    {
        for(int y = -radius; y <= radius; y++)
        {
            r = std::sqrtf(x*x + y*y);
            gKernel[m] = (exp(-(r*r)/s))/(3.14 * s);
            sum += gKernel[m];
            m++;
        }
    }
 m=0;
    // normalize the Kernel
    for(int i = 0; i < (radius*2 +1); ++i)
        for(int j = 0; j < (radius*2 +1); ++j)
            gKernel[m++] /= sum;


}


int main()
{

    cudaError_t cudaStatus;
    const int size =81;
    float gKernel[size];

    float *dev_p=0;
    cudaStatus =  cudaMalloc((void**)&dev_p, size * sizeof(float));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
    }
    createFilter(gKernel,20.0,4);

    cudaStatus = cudaMemcpy(dev_p, gKernel, size* sizeof(float), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
    }

    /*  i read image Buffere in unsigned short that code is not added here ,becouse it is large , and copy image data of buffere from host to device*/

    /* So, suppose i have unsigned short *d_img which contain image data */

    cudaMalloc( (void**)&d_img, length* sizeof(unsigned short));
    cudaMalloc( (void**)&d_blur_img, length* sizeof(unsigned short));

    static const int BLOCK_WIDTH = 32;
    int image_width=1580.0,image_height=1050.0;

    int x = static_cast<int>(ceilf(static_cast<float>(image_width) / BLOCK_WIDTH));
    int y = static_cast<int>(ceilf(static_cast<float>((image_height) ) / BLOCK_WIDTH));

    const dim3 grid (x, y, 1);                              // number of blocks
    const dim3 block(BLOCK_WIDTH, BLOCK_WIDTH, 1);  

    gaussian_blur<<<grid,block>>>(d_blur_img,d_img,1050.0,1580.0,dev_p,9.0);

    cudaDeviceSynchronize();

    /* after bluring image i will copied buffer from Device to Host and free gpu memory */
    cudaFree(d_img);
    cudaFree(d_blur_img);
    cudaFree(dev_p);


return 0;
}
4

1 回答 1

1

简短的回答:两种算法在图像模糊方面都很好,所以请随意为您的用例选择最好(最快)的一种。

内核大小sigma 值直接相关:sigma 越大,内核越大(因此获得最终结果的每像素操作越多)。如果你实现了一个朴素的卷积,那么你应该尝试一个可分离的卷积实现;它已经将计算时间减少了一个数量级。

现在有了更多见解:它们实现了几乎相同的高斯模糊操作。为什么差不多?这是因为对图像进行 FFT 确实会隐含地对其进行周期化。因此,在图像的边界处,卷积核看到的图像已经缠绕在其边缘。这称为循环卷积(因为包裹)。另一方面,高斯模糊实现了一个简单的线性卷积

于 2013-10-10T13:39:58.703 回答