It has no tie to the background color like my general-purpose Edge Blur does.
To use it you simply need to know the location and diameter of the circle, as is the case if you ever use PB's Circle() command - its parameters are identical, making it very easy to blur the edges of those. It doesn't actually need a pre-drawn circle though - just location and diameter; you could for example apply it to a portrait where a face remains unblurred but everything outside the circle area of the face is blurred, if blurdistance is set large.
It only blurs the circle edges; all other content is left untouched.
As with the other Edge Blur, you're free to use any 3x3 convolution filter, there's a lot of gaussian levels to choose from as well as other models like 'smooth'; i've included 3 to choose from. It supports a variable blur distance, but generally this will only ever be set to 1 or 2, maybe 3 (remembering it's a 3x3 filter).
I'll be adapting it soon for rectangles and squares now that annoying circles are taken care of. Thanks again to MrMat for the trigonometry refresher! (tried my best to avoid it for this long, lol). Btw i think PB's excellent vector library produces circles with smoother edges than PB's Circle(), but obviously that isn't going to be the target or an option in all cases.
Windows/Linux/Mac, 24/32bit images, x86/x64, Uni/Ascii, Weekdays/Weekends.
Example:
CircleEdgeBlur.pbi
Code: Select all
Global Dim TargetMatrix.a(0,0)
Global Dim ConvMatrix.f(2,2)
;### Gaussian Blur (weak)
;ConvMatrix(0,0) = 0.03125: ConvMatrix(0,1) = 0.0625: ConvMatrix(0,2) = 0.03125
;ConvMatrix(1,0) = 0.0625: ConvMatrix(1,1) = 0.625: ConvMatrix(1,2) = 0.0625
;ConvMatrix(2,0) = 0.03125: ConvMatrix(2,1) = 0.0625: ConvMatrix(2,2) = 0.03125
;### Gaussian Blur (medium)
ConvMatrix(0,0) = 0.0625: ConvMatrix(0,1) = 0.125: ConvMatrix(0,2) = 0.0625
ConvMatrix(1,0) = 0.125: ConvMatrix(1,1) = 0.25: ConvMatrix(1,2) = 0.125
ConvMatrix(2,0) = 0.0625: ConvMatrix(2,1) = 0.125: ConvMatrix(2,2) = 0.0625
;### Smooth
;ConvMatrix(0,0) = 0.11111: ConvMatrix(0,1) = 0.11111: ConvMatrix(0,2) = 0.11111
;ConvMatrix(1,0) = 0.11111: ConvMatrix(1,1) = 0.11111: ConvMatrix(1,2) = 0.11111
;ConvMatrix(2,0) = 0.11111: ConvMatrix(2,1) = 0.11111: ConvMatrix(2,2) = 0.11111
Procedure.l ConvolutePixel(*imgbuf, X,Y, width,height, pitch, pixbytes)
Protected r.f, g.f, b.f
For yy = -1 To 1 ;\ Good candidates for unrolling
For xx = -1 To 1 ;/
filter.f = ConvMatrix(xx+1,yy+1)
curx = x + xx: cury = y + yy
If curx < 0: curx = 0: EndIf
If curx => width: curx = width: EndIf
If cury < 0: cury = 0: EndIf
If cury => height: cury = height: EndIf
color.l = PeekL(*imgbuf + (cury * pitch) + (curx * pixbytes))
r + (Red(color) * filter)
g + (Green(color) * filter)
b + (Blue(color) * filter)
Next xx
Next yy
ar.a = r: ab.a = b: ag.a = g
color = (ab << 16 | ag << 8 | ar) | $FF000000
ProcedureReturn color
EndProcedure
Procedure GaussianBlurImage(*imgbuf, hImg, MiddleX, MiddleY, width, height, depth)
If StartDrawing(ImageOutput(hImg))
pitch = DrawingBufferPitch()
*out = DrawingBuffer()
Pixbytes = depth/8
w=width-1
h=height-1
For y = 0 To h
*pixelin = *imgbuf + (y * pitch)
*pixelout = *out + (y * pitch)
For x = 0 To w
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
mtx = TargetMatrix(X, h-Y)
CompilerElse
mtx = TargetMatrix(X, Y)
CompilerEndIf
If mtx
color = ConvolutePixel(*imgbuf, X, Y, width,height, pitch, pixbytes)
Else
color = PeekL(*pixelin)
EndIf
PokeL(*pixelout, color)
*pixelin + Pixbytes
*pixelout + Pixbytes
Next x
Next y
StopDrawing()
EndIf
EndProcedure
Procedure BuildCircleEdge(*buf, MiddleX, MiddleY, width,height, LineLen)
Protected multiplier.f, degrees.f, CalcDegrees.f, LastX=$7FFFFFFF, LastY=$7FFFFFFF
multiplier = Sqr(LineLen)
If multiplier < 2: multiplier = 2: EndIf
degmax = 360*multiplier
For i = 0 To degmax
degrees = i/multiplier ;If we only did every 1.0 degrees we may end up missing pixels at 0.25, 0.5 etc
CalcDegrees = 360 - Degrees + 180
X = MiddleX + (Sin(CalcDegrees * (2 * #PI / 360)) * LineLen)
Y = MiddleY + (Cos(CalcDegrees * (2 * #PI / 360)) * LineLen)
If X <> LastX Or Y <> LastY
If X => 0 And X < width And Y => 0 And Y < height
TargetMatrix(X,Y)=1
LastX = X: LastY = Y
EndIf
;Plot(X,Y, RGB(255,0,0)) show marking
EndIf
Next i
EndProcedure
Procedure BlurCircleEdge(*buf, MiddleX, MiddleY, width,height, LineLen, depth, blurdistance=2)
Dim TargetMatrix(width,height)
If blurdistance < 1: blurdistance = 1: EndIf
For i = 1 To blurdistance
BuildCircleEdge(*buf, MiddleX, MiddleY, width,height, LineLen+(i-1))
Next i
hImg = CreateImage(#PB_Any, width, height, depth)
If hImg
GaussianBlurImage(*buf, hImg, MiddleX, MiddleY, width, height, depth)
EndIf
ProcedureReturn hImg
EndProcedure
Example.pb
Code: Select all
XIncludeFile("CircleEdgeBlur.pbi")
If OpenWindow(0, 0, 0, 300, 300, "Circle Edge Blur", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
width=300: height=300
hImg1 = CreateImage(#PB_Any, width,height, 32)
If hImg1 And StartDrawing(ImageOutput(hImg1))
Diameter = 50
Radius = Diameter/2
MiddleX = Radius+10
MiddleY = Radius+10
LineLen = Radius-5
Circle(MiddleX, MiddleY, LineLen, $FFFF00)
*buf = DrawingBuffer()
depth=ImageDepth(hImg1)
StopDrawing()
blurdistance=2
hImg2 = BlurCircleEdge(*buf, MiddleX, MiddleY, width,height, LineLen, depth, blurdistance) ;Note: Same params as Circle()
FreeImage(hImg1)
ImageGadget(0, 0, 0, width, height, ImageID(hImg2))
EndIf
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf