Superfast blur

BlitzMax Forums/BlitzMax Programming/Superfast blur

Hitori(Posted 2009) [#1]
I found this box blur argorithm:
// Super Fast Blur v1.1
// by Mario Klingemann <http://incubator.quasimondo.com>
//
// Tip: Multiple invovations of this filter with a small 
// radius will approximate a gaussian blur quite well.
//
BImage a;
BImage b;

void setup()
{

  a=loadImage("dog.jpg");
  size(a.width, a.height);
  b=new BImage(a.width, a.height);
  fill(255);
  noStroke();
  framerate(25);

}

void loop()
{
  System.arraycopy(a.pixels,0,b.pixels,0,a.pixels.length);
  fastblur(b,mouseY/8);
  image(b, 0, 0);
}

void fastblur(BImage img,int radius){

  if (radius<1){
    return;
  }
  int w=img.width;
  int h=img.height;
  int wm=w-1;
  int hm=h-1;
  int wh=w*h;
  int div=radius+radius+1;
  int r[]=new int[wh];
  int g[]=new int[wh];
  int b[]=new int[wh];
  int rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw;
  int vmin[] = new int[max(w,h)];
  int vmax[] = new int[max(w,h)];
  int[] pix=img.pixels;
  int dv[]=new int[256*div];
  for (i=0;i<256*div;i++){
     dv[i]=(i/div); 
  }
  
  yw=yi=0;
 
  for (y=0;y<h;y++){
    rsum=gsum=bsum=0;
    for(i=-radius;i<=radius;i++){
      p=pix[yi+min(wm,max(i,0))];
      rsum+=(p & 0xff0000)>>16;
      gsum+=(p & 0x00ff00)>>8;
      bsum+= p & 0x0000ff;
   }
    for (x=0;x<w;x++){
    
      r[yi]=dv[rsum];
      g[yi]=dv[gsum];
      b[yi]=dv[bsum];

      if(y==0){
        vmin[x]=min(x+radius+1,wm);
        vmax[x]=max(x-radius,0);
       } 
       p1=pix[yw+vmin[x]];
       p2=pix[yw+vmax[x]];

      rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
      gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
      bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
      yi++;
    }
    yw+=w;
  }
  
  for (x=0;x<w;x++){
    rsum=gsum=bsum=0;
    yp=-radius*w;
    for(i=-radius;i<=radius;i++){
      yi=max(0,yp)+x;
      rsum+=r[yi];
      gsum+=g[yi];
      bsum+=b[yi];
      yp+=w;
    }
    yi=x;
    for (y=0;y<h;y++){
      pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
      if(x==0){
        vmin[y]=min(y+radius+1,hm)*w;
        vmax[y]=max(y-radius,0)*w;
      } 
      p1=x+vmin[y];
      p2=x+vmax[y];

      rsum+=r[p1]-r[p2];
      gsum+=g[p1]-g[p2];
      bsum+=b[p1]-b[p2];

      yi+=w;
    }
  }

}

and i wanted to convert it to blitzmax code,here is what i've done:
SuperStrict
Graphics 800,600
Global a:TPixmap
Global b:TPixmap
a=LoadPixmap("dog.PNG")
b=fastblur(a,3)
DrawImage(LoadImage(b),0,0)
Repeat
Flip
Until KeyDown(key_enter)

Function fastblur:TPixmap(img:TPixmap,radius:Int)
	If radius<1 Return img
	Local blur:TPixmap=CopyPixmap(img)
	Local w:Int=blur.width
	Local h:Int=blur.height
	Local wm:Int=w-1
	Local hm:Int=h-1
	Local wh:Int=w*h
	Local div:Int=radius+radius+1
	Local r:Int[]=New Int[wh]
	Local g:Int[]=New Int[wh]
	Local b:Int[]=New Int[wh]
	Local rsum:Int,gsum:Int,bsum:Int,x:Int,y:Int,y1:Int,y2:Int,i:Int,p:Int,p1:Int,p2:Int,yp:Int,yi:Int,yw:Int
	Local vmin:Int[]=New Int[Max(w,h)]
	Local vmax:Int[]=New Int[Max(w,h)]
	Local pix:Byte Ptr=blur.pixels
	Local dv:Int[]=New Int[256*div]
	For i=0 To 256*div-1
		dv[i]=(i/div)
	Next
	yw=0
	yi=0
	For y=0 To h-1
		rsum=0
		gsum=0
		bsum=0
		For i=-radius To radius
			p=blur.ReadPixel((yi+Min(wm,Max(i,0))) Mod blur.width,Floor((yi+Min(wm,Max(i,0)))/blur.width))
			Print rsum
			Print gsum
			Print bsum
			Print (p And $ff000000) Shr 24
			rsum:+(p And $ff0000) Shr 16
			gsum:+(p And $00ff00) Shr 8
			bsum:+p And $0000ff
		Next
		For x=0 To w-1
			r[yi]=dv[rsum]
			g[yi]=dv[gsum]
			b[yi]=dv[bsum]
			If y=0
				vmin[x]=Min(x+radius+1,wm)
				vmax[x]=Max(x-radius,0)
			EndIf
			p1=blur.ReadPixel((yw+vmin[x]) Mod blur.width,Floor((yw+vmin[x])/blur.width))
			p2=blur.ReadPixel((yw+vmax[x]) Mod blur.width,Floor((yw+vmax[x])/blur.width))
			rsum:+((p1 And $ff0000)-(p2 And $ff0000)) Shr 16
			gsum:+((p1 And $00ff00)-(p2 And $00ff00)) Shr 8
			bsum:+(p1 And $0000ff)-(p2 And $0000ff)
			yi:+1
		Next
		For x=0 To w-1
			rsum=0
			gsum=0
			bsum=0
			yp=-radius*w
			For i=-radius To radius
				yi=Max(0,yp)+x
				rsum:+r[yi]
				gsum:+g[yi]
				bsum:+b[yi]
				yp:+w
			Next
			yi=x
			For y1=0 To h-1
				blur.WritePixel(yi Mod blur.width,Floor(yi/blur.width),$ff000000 + (dv[rsum] Shl 16) + (dv[gsum] Shl 8) + dv[bsum])
				If x=0
					vmin[y1]=Min(y1+radius+1,hm)*w
					vmax[y1]=Max(y1-radius,0)*w
				EndIf
				p1=x+vmin[y1]
				p2=x+vmax[y1]
				rsum:+r[p1]-r[p2]
				gsum:+g[p1]-g[p2]
				gsum:+b[p1]-b[p2]
				yi:+w
			Next
		Next
	Next
	Return blur
EndFunction

But,no matter what i try,it doesn't work.
Once it gives me boundary error,other time only fills image blue.
Can anyone take a look at this and show me what am i doing wrong ?


Robert Cummings(Posted 2009) [#2]
thats not fast blur, its slow for 3D hardware. fast blur would be to draw 4 copies of the image offset with alpha / 4


ImaginaryHuman(Posted 2009) [#3]
Yeah you're looking at doing a blur on a pixmap, with the cpu doing all the processing.

I did not follow the code, but it's not going to be fast, as Rob said.


Jesse(Posted 2009) [#4]
just so you know the "&" and "|" are the same in bmax and C.


AdamRedwoods(Posted 2011) [#5]
Sorry to dig this up, but it's good to have around.

Couple things wrong with the above code. That first for-next that was encapsulating too much, and the bit math (p1-p2) would get overflow problems, so you have to work the mask in before doing subtraction or addition.

I created my own port here, with alpha (dont forget to use setblend):


Last edited 2011


Kryzon(Posted 2011) [#6]
It's good to have around indeed :)
Thanks for sharing, Adam.


ImaginaryHuman(Posted 2011) [#7]
It's faster to use the GPU to blur.


Czar Flavius(Posted 2011) [#8]
What language is that?

Last edited 2011