Code archives/Graphics/Gaussian Blur Filter
This code has been declared by its author to be Public Domain code.
Download source code
| This Gaussian Blur filter is simple to use and provides great results without those weird artifacts you get when you use simple box blurs. Setting the radius to something small gives a nice smoothing effect. Naturally, larger radii will take longer to process. Please let me know of any optimizations that can be made! |
'======== Example ========
SuperStrict
Local pix:TPixmap = gaussianblur(LoadPixmap("yourimagehere.png"), 5)
Local gfx:TGraphics = Graphics(pix.width, pix.height)
DrawPixmap(pix, 0, 0)
Flip
WaitMouse()
'====== Example Ends ======
Function gaussianblur:TPixmap(tex:TPixmap, radius:Int)
If radius <=0 Return tex
Local texclone:TPixmap = tex.copy() 'clone incoming texture
Local filter:TGaussianFilter = New TGaussianFilter 'instantiate a new gaussian filter
filter.radius = radius 'configure it
Return filter.apply(tex, texclone)
End Function
Type TGaussianFilter
Field radius:Double
Field kernel:TKernel
Method apply:TPixmap(src:TPixmap, dst:TPixmap)
Self.kernel = makekernel(Self.radius)
Self.convolveAndTranspose(Self.kernel, src, dst, PixmapWidth(src), PixmapHeight(src), True)
Self.convolveAndTranspose(Self.kernel, dst, src, PixmapHeight(dst), PixmapWidth(dst), True)
dst = Null
GCCollect()
Return src
End Method
'Make a Gaussian blur kernel.
Method makekernel:TKernel(radius:Double)
Local r:Int = Int(Ceil(radius))
Local rows:Int = r*2+1
Local matrix:Double[] = New Double[rows]
Local sigma:Double = radius/3.0
Local sigma22:Double = 2*sigma*sigma
Local sigmaPi2:Double = 2*Pi*sigma
Local sqrtSigmaPi2:Double = Double(Sqr(sigmaPi2))
Local radius2:Double = radius*radius
Local total:Double = 0
Local index:Int = 0
For Local row:Int = -r To r
Local distance:Double = Double(row*row)
If (distance > radius2)
matrix[index] = 0
Else
matrix[index] = Double(Exp(-(distance/sigma22)) / sqrtSigmaPi2)
total:+matrix[index]
index:+1
End If
Next
For Local i:Int = 0 Until rows
matrix[i] = matrix[i]/total 'normalizes the gaussian kernel
Next
Return mkernel(rows, 1, matrix)
End Method
Function mkernel:TKernel(w:Int, h:Int, d:Double[])
Local k:TKernel = New TKernel
k.width = w
k.height = h
k.data = d
Return k
End Function
Method convolveAndTranspose(kernel:TKernel, in:TPixmap, out:TPixmap, width:Int, height:Int, alpha:Int)
Local inba:Byte Ptr = in.pixels
Local outba:Byte Ptr = out.pixels
Local matrix:Double[] = kernel.getKernelData()
Local cols:Int = kernel.getWidth()
Local cols2:Int = cols/2
For Local y:Int = 0 Until height
Local index:Int = y
Local ioffset:Int = y*width
For Local x:Int = 0 Until width
Local r:Double = 0, g:Double = 0, b:Double = 0, a:Double = 0
Local moffset:Int = cols2
For Local col:Int = -cols2 To cols2
Local f:Double = matrix[moffset+col]
If (f <> 0)
Local ix:Int = x+col
If ( ix < 0 )
ix = 0
Else If ( ix >= width)
ix = width-1
End If
Local rgb:Int = (Int Ptr inba)[ioffset+ix]
a:+f *((rgb Shr 24) & $FF)
b:+f *((rgb Shr 16) & $FF)
g:+f *((rgb Shr 8) & $FF)
r:+f *(rgb & $FF)
End If
Next
Local ia:Int
If alpha = True Then ia = clamp(Int(a+0.5)) Else ia = $FF
Local ir:Int =clamp( Int(r+0.5))
Local ig:Int = clamp(Int(g+0.5))
Local ib:Int = clamp(Int(b+0.5))
(Int Ptr outba)[index] =((ia Shl 24) | (ib Shl 16) | (ig Shl 8) | (ir Shl 0))
index:+height
Next
Next
End Method
End Type
Type TKernel
Field width:Int
Field height:Int
Field data:Double[]
Method getkerneldata:Double[]()
Return Self.data
End Method
Method getwidth:Int()
Return Self.width
End Method
Method getheight:Int()
Return Self.height
End Method
End Type
Function clamp:Int(val:Int)
If val < 0
Return 0
ElseIf val > 255
Return 255
Else
Return val
EndIf
End Function |