Intel® Integrated Performance Primitives
Deliberate problems developing high-performance vision, signal, security, and storage applications.
6704 Discussions

Generalized Gaussian Blur, borders and filters for whole images

pelesl
Beginner
319 Views
Hello all,

I had a bit of trouble in blurring an image with ippiFilterGauss and after it was promptly solved by a support ticket I ended up doing a more generalized Gaussian filter and would like to post that here as an example. You can see my other post if you're having trouble with building borders and applying filters.

My application is for 8bpp [greyscale] images.

-------

A Gaussian blur is nothing more than a convolution of an image with a "kernel" (small image) of a normalized two-dimensional Gaussian. First some background code to improve readability a bit:


typedef struct IppImage
{
Ipp32f *pixels; //allocate this with IppiMalloc
IppiSize dims; //width and height
int StepBytes; //for ippiMalloc
} IppImage;

IppImage MakeIppImage(int width, int height)
{
IppImage image;

image.dims.width=width;
image.dims.height=height;

image.pixels=ippiMalloc_32f_C1(width,height,&(image.StepBytes));
if(image.pixels==NULL)
{...}

return image;
}

void DeleteIppImage(IppImage img)
{
ippiFree(img.pixels);
img.dims.width=0;
img.dims.height=0;
}

//Macros to get and set pixels in IPP images
#define _ippiGet(IppImage, row, col)
((IppImage).pixels[(row)*(IppImage).StepBytes/sizeof(Ipp32f)+(col)])

#define _ippiSet(IppImage, row, col, val)
((IppImage).pixels[(row)*(IppImage).StepBytes/sizeof(Ipp32f)+(col)]=val)



Now for the blurring function. The idea is to:
1. Create a Gaussian kernel to blur the image
2. Create a scratch image which is the original image plus a border
3. Do a convolution of the kernel with an image using ippiConvValid.

Here is the entire function:



IppStatus BlurIppImage(IppImage img)
{
IppImage scratch;
IppStatus retval;
Ipp32f sum, Rxy, eval;
IppImage krnl;

int i,j;
int border=6;

krnl = MakeIppImage(2*border+1,2*border+1);

sum=0;

//Create the 13x13 kernel as a Gaussian with BLUR_RADIUS as the standard deviation.

double BLUR_RADIUS=1.0;

for(i=0;i
{
for(j=0;j
{
Rxy = (Ipp32f)((i-border)*(i-border)+(j-border)*(j-border));
eval=(Ipp32f)exp(-0.5*Rxy/BLUR_RADIUS/BLUR_RADIUS);
_ippiSet(krnl,i,j,eval);
sum+=eval;
}
}

//Normalize the Gaussian kernel
for(i=0;i
{
for(j=0;j
{
_ippiSet(krnl,i,j,_ippiGet(krnl,i,j)/sum);
}
}

//This image has to be bigger to accomodate the border
scratch=MakeIppImage(img.dims.width+2*border,img.dims.height+2*border);

//Should consider using a constant border rather than replicated.
retval=ippiCopyReplicateBorder_32s_C1R((const Ipp32s *)img.pixels, img.StepBytes,
img.dims, (Ipp32s *)scratch.pixels, scratch.StepBytes,
scratch.dims,border, border);
if(retval!=ippStsNoErr)
{...}

retval=ippiConvValid_32f_C1R(scratch.pixels,scratch.StepBytes,
scratch.dims,krnl.pixels,krnl.StepBytes,
krnl.dims,img.pixels,img.StepBytes);
if(retval!=ippStsNoErr)
{...}

DeleteIppImage(scratch);
DeleteIppImage(krnl);
return retval;
}



A quick walkthrough:

1. A Gaussian blur of radius "R" is a Gaussian with standard deviation "R" and mean 0. Thus the ippiFilterGauss masks are equivalent to a .85-pixel-radius blur (for the 3x3) and a 1-pixel- radius blur (for the 5x5). The first for-loop generates the 2D Gaussian values (where "Rxy" is the radial distance to what the manual calls the anchor pixel), and the second one normalizes it so that the "integral" is 1 - otherwise if you blur a completely white image you are not going to get white back.

2. In my function the size of the kernel is linked to the border size since you must have a border equal to (kernel width-1)/2 around your image for the filter to work properly. For the blur to be "accurate", you must have a kernel that is big enough to accomodate the radius. For example, setting BLUR_RADIUS=10 and having border=1 (3x3 kernel) will not be "as proper" a blur as would be a, say, 21x21 kernel. Wikipedia has a nice article.

3. The difference between ippiConvValid and ippiConvFull was a bit hard for me to grasp. The example "images" in the manual make it obvious. This is how I interpret it: a convolution in words is "holding one image still and shifting the other, adding the product of the pixels of the held and shifted image at each shift and setting the pixel value to this sum". The first product is that of the first image and the second image shifted so that only the bottom right pixel of the shifted one overlaps with the top left of the held; the second product is when two pixels overlap; this goes on until the last product which is the top left pixel of the shifted image overlapped with the bottom right of the held image. This is "ippiConvFull" and so the resulting image is bigger than the sources. When convolving an image with itself (as in the manual) with a constant border of 0 will yield a maximum pixel on the convolution image right at the place where the held and shifted images are directly on top of each other, because then they will have the most pixels in common. The value of the "0-shift" pixel of the convolution is what "ippiConvValid" returns. In this context and in the context of having one source be the target image and the other source being a "kernel" image, you can look at it as being a weighted average of pixels where the weights are the pixel values of the kernel image. By doing this in images of the Ipp32f type you don't get any "rounding errors" until you convert it back to a bitmap to view or save. The blur here is a weighted average where the weights have a Gaussian distribution

With this code example you should be able to apply any convolution-type filter you want. I don't do much image processing but I know there's plenty (in some older versions of Photoshop you could even enter your own kernel matrix!).

By the way, I compared this to Photoshop 7's "Gaussian Blur" and the center pixel is not as strong in Photoshop's filter.

Again, sorry the code looks so ugly. Trying to get it better....
0 Kudos
1 Reply
Vladimir_Dudnik
Employee
319 Views
was looking through forum and just recall this post.

It might be added that IPP provides actually several ways to implement blur filter. It is possible to use ippiFilterGauss from ippi library and ippiFilterGaussBorder or ippiFilterRowPipeline/ippiFilterColumnPipeline from ippcv library for implementation of generalized blur operation.

Vladimir
0 Kudos
Reply