Gaussian Blur Filter C++

I got asked to make some new blur filters.

The available convolution filters turned out to be rather slow and a set of new ones was requested. Getting to know the specific PDK (plugin development kit) was tricky, writing the plug-ins on the other end was a lot of fun. Below there is a snippet of code on how to write a Gaussian and Box blur kernel in C++.

Note that the height field input parameter (HField *inHeightMap and BuildContext &inContext)   can be replaced with any other (pixel) matrix using for example Devil or FreeImage.

The BuildContext is used to generate a second image and is used as a temporary pixel placeholder.

Now for the code:

I’ll start by defining the Gaussian Kernel. When called this kernel function returns an array of floats that define the actual per pixel scalar values.

// Calculates a 1d gaussian bell shaped kernel
float* GBlur::ComputeGaussianKernel(const int inRadius, const float inWeight)
{
    int mem_amount = (inRadius*2)+1;
    float* gaussian_kernel = (float*)malloc(mem_amount*sizeof(float));

    float twoRadiusSquaredRecip = 1.0 / (2.0 * inRadius * inRadius);
    float sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * PI) * inRadius);
    float radiusModifier = inWeight;

    // Create Gaussian Kernel
    int r = -inRadius;
    float sum = 0.0f;
    for (int i = 0; i < mem_amount; i++)
    {
        float x = r * radiusModifier;
        x *= x;
        float v = sqrtTwoPiTimesRadiusRecip * exp(-x * twoRadiusSquaredRecip);
        gaussian_kernel[i] = v;
           
        sum+=v;
        r++;
    }

    // Normalize distribution
    float div = sum;
    for (int i = 0; i < mem_amount; i++)
        gaussian_kernel[i] /= div;

    return gaussian_kernel;
}

Now this kernel can be used to blur an image. The image comes in as a an array of floats.
This array represents a greyscale image. A colored image would have the RGB(A) components blurred.

// Calculates the Gaussian Blur and stores the result on the height map given
void GBlur::GaussianBlur(HFPointer inHeightMap, const int inRadius, BuildContext &inContext, const float inWeight)
{
    int pixels_on_row = 1+(inRadius*2);
    int height = inHeightMap->h();
    int width = inHeightMap->w();

    HFPointer temp_smap   = GetNewHF(inContext);    ///< Temporary map used for storing intermediate results
    temp_smap->Clear();
    //temp_smap->AddRef();

    float* gaussian_kernel = ComputeGaussianKernel(inRadius,inWeight); ///< Compute our gaussian 1d kernel

    float* pheight_map = inHeightMap->GetDataPtr();             ///< Pointer to current map
    float* ptemp_map = temp_smap->GetDataPtr();                 ///< Pointer to intermediate map
                                                           
    int current = 0;                                            ///< Helps keep track of where we are

    // Do a one dimensional blur in the y direction
    // We use the temp map to find the horizontally blurred pixels
    // These are then used to compute a first blur pass and stored in the original map
    float* out = ptemp_map;
    int height_clamp = height - 1;
    int width_clamp = width - 1;

    for(int y=0;y<height; y++)
    {
        int row = y*width;              ///< Specifies the current row

        for(int x=0;x<width; x++)
        {
            float blurred_value = 0.0f;
            for(int xoffset = 0; xoffset < pixels_on_row; xoffset++)
            {
                // Clamp x index
                int sx = iClamp(0,width_clamp,(x-inRadius)+xoffset);
               
                // Calculate newly blurred value
                blurred_value += pheight_map[row+sx]*gaussian_kernel[xoffset];
            }

            // Set our calculated value to our temp map
            *out++ = blurred_value;

            // Increment where we are
            current++;
        }

        inContext.ReportDeviceProgress(this, y/2 ,inHeightMap->h());
    }

    // Used for showing progress
    int half_height(inHeightMap->h() / 2);

    // Do a one dimensional blur in the x direction
    // We use the temp map to find the horizontally blurred pixels
    // These are then used to compute a second blur pass and stored in the original map
    out = pheight_map;
    for(int y=0;y<height; y++)
    {
        for(int x=0;x<width; x++)
        {
            float blurred_value = 0.0f;
            for(int yoffset = 0; yoffset < pixels_on_row; yoffset++)
            {
                // Clamp our offset in y
                int sy = iClamp(0,height_clamp,(y-inRadius)+yoffset);

                // Calculate blurred value
                blurred_value += (ptemp_map[(sy * width) + x]*gaussian_kernel[yoffset]);
            }

            // Set the original height map value to our computed value
            // This is the actual blurred value (previously scaled)
            *out++ = blurred_value;

            // increment counter and report progress to wm
            current++;
            inContext.ReportDeviceProgress(this,current/2,inHeightMap->area());
        }

        inContext.ReportDeviceProgress(this, half_height + (y/2),inHeightMap->h());
    }

    // Release
    free(gaussian_kernel);
    gaussian_kernel=NULL;
    temp_smap->Clear();
    temp_smap->releaseAccessible();
}

12 thoughts on “Gaussian Blur Filter C++

  1. Hey,
    thanks for this nice post. I’m not sure if I’m missing something, but I miss “float*” in front of “gaussian_kernel” in the 5th line of your code. Sorry if I oversee something.
    Cheers, Alexey

  2. hi,
    Nice code here but i don’t understand why this
    float v = sqrtTwoPiTimesRadiusRecip * exp(-x * sqrtTwoPiTimesRadiusRecip);

    shouldn’t it be
    float v = sqrtTwoPiTimesRadiusRecip * exp(-x * twoRadiusSquaredRecip);

  3. I don’t even know the way I ended up the following, but I thought this article was superb. I have no idea who you could be but clearly you?¯re likely to a celebrated blogger if you aren?¯t previously Cheers!

  4. hi blogger, I found your website from altavista and browse just a few within your other website posts.These are pleasant. Pleasee hold them coming. Have a great day, Thomas Everyday.

Leave a Reply

Your email address will not be published. Required fields are marked *