Question

I have been trying to implement a simple Gaussian blur algorithm, for my image editing program. However, I have been having some trouble making this work, and I think the problem lies in the below snippet:

        for( int j = 0; j < pow( kernel_size, 2 ); j++ )
        {
            int idx = ( i + kx + ( ky * img.width ));

            //Try and overload this whenever possible
            valueR += ( img.p_pixelArray[ idx ].r * kernel[ j ] );
            valueG += ( img.p_pixelArray[ idx ].g * kernel[ j ] );
            valueB += ( img.p_pixelArray[ idx ].b * kernel[ j ] );

            if( kx == kernel_limit )
            {
                kx = -kernel_limit;
                ky++;
            }

            else    
            {
                kx++;
            }
       }

       kx = -kernel_limit;
       ky = -kernel_limit;

A brief explanation of the code above: kernel size is the size of the kernel (or matrix) generated by the Gaussian blur formula. kx and ky are variables to be used for iterating over the kernel. i is the parent loop, that nests this one, and goes over every pixel in the image. Each value variable simply holds a float R, G, or B value, and is used afterwards to obtain the final result. The if-else is used to increase kx and ky. idx is used to find the correct pixel. kernel limit is a variable set to

(*kernel size* - 1) / 2

So I can have kx going from -1 ( with a 3x3 kernel ) to +1, and the same thing with ky. I think the problem lies with the line

int idx = ( i + kx + ( ky * img.width ));

But I am not sure. The image I get is:

Lenna

As can be seen, the color is blurred in a diagonal direction, and looks more like some kind of motion blur than Gaussian blur. If someone could help out, I would be very grateful.

EDIT: The way I fill the kernel is as follows:

for( int i = 0; i < pow( kernel_size, 2 ); i++ )
{
    // This. Is. Lisp.
    kernel[i] = (( 1 / ( 2 * pi * pow( sigma, 2 ))) * pow (e, ( -((( pow( kx, 2 ) + pow( ky, 2 )) / 2 * pow( sigma, 2 ))))));

    if(( kx + 1 ) == kernel_size )
    {
        kx = 0;
        ky++;
    }

    else
    {
        kx++;
    }
}
Était-ce utile?

La solution

Few problems:

Your Gaussian misses brackets (even though you already have plenty..) around 2 * pow( sigma, 2 ). Now you multiply by variance instead of divide.

But what your problem is, is that your gaussian is centered at kx = ky = 0, as you let it run from 0 to kernel_size, instead of from -kernel_limit to kernel_limit. This results in the diagonal blurring. Something like the following should work better

kx = -kernel_limit;
ky = -kernel_limit;

int kernel_size_sq = kernel_size * kernel_size;

for( int i = 0; i < kernel_size_sq; i++ )
{
  double sigma_sq = sigma * sigma;
  double kx_sq = kx * kx;
  double ky_sq = ky * ky;
  kernel[i] =  1.0 / ( 2 * pi * sigma_sq) * exp(-(kx_sq + ky_sq) / (2 * sigma_sq));

  if(kx == kernel_limit )
  {
    kx = -kernel_limit;
    ky++;
  }
  else
  {
    kx++;
  }
}

Also note how I got rid of your lisp-ness and some improvements: use some intermediate variables for clarity (compiler will optimize them away if anyway you ask it to); simple multiplication is faster than pow(x, 2); pow(e, x) == exp(x).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top