Home | Download | Documents | Tips & Tutorials | Code Library | Help / User Group | Order

Blur filters tutorial, Part II

 

As we have seen in the Part One of current tutorial, we need to spead the blur filter up by dividing the square kernel onto two line kernels. To do this, we need one more array for storing intermediate values between horizontal and vertical blur passes. Current release of FM have a predefined array called "t" having the size equal to that of source image, whose cells may be accessed through "tget(x,y,z)" and "tset(x,y,z)" functions just as source image pixels were accessed through "src(x,y,z)" and "pset(x,y,z)".

Here goes the sample implementation of such a two-pass algorithm. Again, the filter code fragments are followed by explanations. You are supposed to know many parts of the code remained unchanged since Part One so they aren't explained. The code of the filter under consideration is available for download.

%ffp
Category: "FM Tutorial"
Title: "Blur  II"
Author: "Ilyich the Toad"

ctl[0]:"Blur Width",range=(2,scaleFactor*X/2),val=3,pagesize=3,linesize=1
ctl[1]:"Blur Height",range=(2,scaleFactor*Y/2),val=3,pagesize=3,linesize=1

ForEveryTile:
{

int kernelheight; int kernelwidth;
int xlook; int ylook;
int sum; int amount; int progress;

 

One more variable added - "progress" - to easily count total progress during multistep processeing.


setCtlRange(0,2,scaleFactor*X/2);
setCtlRange(1,2,scaleFactor*Y/2);

kernelheight=max(ctl(1)/scaleFactor, 1);
kernelwidth=max(ctl(0)/scaleFactor, 1);

progress=0;

 

Here we start first pass of the filter:

for (y=0; y < Y; y++) {
 if(updateProgress(progress,2*Y)) break;  progress++;

 

We update progress bar as usual, at every row calculation, but now we use 2*Y as a maximum value since we process the entire image two times.


for (x=0; x   for (z= 0; z < Z; z++) {
  sum=0; amount=0;
  for (xlook=0; xlook<kernelwidth; xlook++)
  {
  sum+= src((x+xlook-kernelwidth/2),y,z);
  amount++;
  }; //accumulate pixels in a raw
  tset(x,y,z,sum/amount);

 

We calculate blur along "xlook" only and store the result into "t" array using "tset" function.


  }
 }
}

 

Finishing first pass. Now the "semiblurred" image is stored in "t" array and we start a second pass:

for (y=0; y < Y; y++) {
 if(updateProgress(progress, 2*Y)) break;
 progress++;
 for (x=0; x < X; x++) {
  for (z= 0; z < Z; z++) {
  sum=0; amount=0;
  for (ylook=0; ylook<kernelheight; ylook++)
  {
  sum+= tget(x,(y+ylook-kernelheight/2),z);

 

Retrieving values from "t" array using "tget" command.


  amount++;
  }; //accumulate pixels in a column
  pset(x,y,z,sum/amount); //divide the sum onto kernel size
  }
 }
}

updateProgress(0, 100);
true;
}

 

Filter ended.

Testing this filter, we see a great speed improvement without any loss of quality. It should be noted that such a two-pass architecture may be applied to many other convolution filters.

Ok, now we feel really happy about performance of our filter... Do we? Is there something that can be done to increase speed any further?

And we see the Wise Man coming to bring us new idea...

 

Home | Download | Documents | Tips & Tutorials | Code Library | Help / User Group | Order