Page 1 of 1
Smoother FillArea routine
Posted: Tue Oct 12, 2021 8:16 pm
by firace
I am a total 2D/3D graphics newbie, so I was wondering if there is any clever FillArea algorithms that can replace a color in an image such as the below without causing annoying artefacts due to antialiasing?

Re: Smoother FillArea routine
Posted: Tue Oct 12, 2021 8:26 pm
by Olli
If nobody answers this question in less than a week, I switch my computer on and give an algo.
- Redo a filling algo
- Choose a three-color limit (here, 0;0;0)
- Blend the fill color with the background color, in the area of the filling algo.
This will be a very very good subject, because, just the title seems to talk about a light and shadow smooth, instead of just an aA.
Re: Smoother FillArea routine
Posted: Tue Oct 12, 2021 9:20 pm
by STARGÅTE
Here is an example algorithm which uses a color distance to blend the filling color with the pixel.
Use the left mouse click to fill areas with blue color and see the result.
Code: Select all
Enumeration
#Window
#Gadget
#Image
EndEnumeration
Structure Vector
X.i
Y.i
EndStructure
; Calculate the distance between two colors. This value is between 0.0 and 441.67
Procedure.f ColorDistance(Color1.l, Color2.l)
Protected dR.i = Abs(Red(Color1)-Red(Color2))
Protected dG.i = Abs(Green(Color1)-Green(Color2))
Protected dB.i = Abs(Blue(Color1)-Blue(Color2))
ProcedureReturn Sqr(dR*dR + dG*dG + dB*dB)
EndProcedure
; Mix two colors with a linear interpolation. color = color1*(1-factor) + color2*factor
Procedure.l ColorMix(Color1.l, Color2.l, Factor.f)
Protected R.i = Red(Color1)*(1-Factor) + Red(Color2)*Factor
Protected G.i = Green(Color1)*(1-Factor) + Green(Color2)*Factor
Protected B.i = Blue(Color1)*(1-Factor) + Blue(Color2)*Factor
ProcedureReturn RGB(R, G, B)
EndProcedure
; Perform a smooth filling of area (x,y) with color FillColor using the max color distance MaxColorDistance
Procedure SmoothFillArea(X.i, Y.i, FillColor.l, MaxColorDistance.f)
Protected Dim Filled.i(OutputWidth()-1, OutputHeight()-1)
Protected NewList Seeds.Vector()
Protected Factor.f
Protected SeedColor.l = Point(X, Y)
AddElement(Seeds()) : Seeds()\X = X : Seeds()\Y = Y : Filled(X, Y) = #True
ResetList(Seeds())
While NextElement(Seeds())
*Seed.Vector = @Seeds()
With *Seed
If MaxColorDistance = 0
Factor = Bool(ColorDistance(Point(\X, Seeds()\Y), SeedColor) <> 0.0)
Else
Factor = ColorDistance(Point(\X, Seeds()\Y), SeedColor) / MaxColorDistance
EndIf
If Factor < 1.0
Plot(\X, \Y, ColorMix(FillColor, Point(\X, \Y), Factor*Factor))
If \X > 0 And Filled(\X-1, \Y) = #False
AddElement(Seeds()) : Seeds()\X = \X-1 : Seeds()\Y = \Y : Filled(\X-1, \Y) = #True
EndIf
If \X < OutputWidth()-1 And Filled(\X+1, \Y) = #False
AddElement(Seeds()) : Seeds()\X = \X+1 : Seeds()\Y = \Y : Filled(\X+1, \Y) = #True
EndIf
If \Y > 0 And Filled(\X, \Y-1) = #False
AddElement(Seeds()) : Seeds()\X = \X : Seeds()\Y = \Y-1 : Filled(\X, \Y-1) = #True
EndIf
If \Y < OutputHeight()-1 And Filled(\X, \Y+1) = #False
AddElement(Seeds()) : Seeds()\X = \X : Seeds()\Y = \Y+1 : Filled(\X, \Y+1) = #True
EndIf
ChangeCurrentElement(Seeds(), *Seed)
EndIf
EndWith
Wend
EndProcedure
;- Example
InitNetwork()
UsePNGImageDecoder()
CatchImage(#Image, ReceiveHTTPMemory("https://i.ibb.co/WP4XVGd/cat3.png"))
OpenWindow(#Window, 0, 0, ImageWidth(#Image), ImageHeight(#Image), "Smooth Fill Area", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))
If StartDrawing(CanvasOutput(#Gadget))
DrawImage(ImageID(#Image), 0, 0)
StopDrawing()
EndIf
Define FillColor.l = $FFB040 ; Filling color
Define MaxColorDistance.f = 400.0 ; Max distance of the colors: 0.0 until 441.67
; 0.0 meens only exacly same pixel color. Value over 441.67 fills all pixels
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case #Gadget
Select EventType()
Case #PB_EventType_LeftClick
If StartDrawing(CanvasOutput(#Gadget))
SmoothFillArea(GetGadgetAttribute(#Gadget, #PB_Canvas_MouseX), GetGadgetAttribute(#Gadget, #PB_Canvas_MouseY), FillColor, MaxColorDistance)
StopDrawing()
EndIf
EndSelect
EndSelect
EndSelect
ForEver
End
Re: Smoother FillArea routine
Posted: Tue Oct 12, 2021 9:28 pm
by firace
@STARGÅTE: Awesome code, thanks!

Re: Smoother FillArea routine
Posted: Tue Oct 12, 2021 9:57 pm
by Caronte3D
+1000

Re: Smoother FillArea routine
Posted: Wed Oct 13, 2021 5:27 am
by juergenkulow
Coloring the cat's eye takes 13 ms where the seeds list has 3536 elements,
Can this be done under 1 ms?
Re: Smoother FillArea routine
Posted: Wed Oct 13, 2021 7:04 pm
by Michael Vogel
Speeding up can be done by doing direct memory access instead using the Plot/Point functions. Anyhow it is a great example how difficult problems could be solved (by purebasic and a clever nerd)
Only added a slider quicly to see how different parameter values change the behaviour of the filling routine:
Code: Select all
Enumeration
#Window
#Gadget
#Slider
#Image
EndEnumeration
Structure Vector
X.i
Y.i
EndStructure
; Calculate the distance between two colors. This value is between 0.0 and 441.67
Procedure.f ColorDistance(Color1.l, Color2.l)
Protected dR.i = Abs(Red(Color1)-Red(Color2))
Protected dG.i = Abs(Green(Color1)-Green(Color2))
Protected dB.i = Abs(Blue(Color1)-Blue(Color2))
ProcedureReturn Sqr(dR*dR + dG*dG + dB*dB)
EndProcedure
; Mix two colors with a linear interpolation. color = color1*(1-factor) + color2*factor
Procedure.l ColorMix(Color1.l, Color2.l, Factor.f)
Protected R.i = Red(Color1)*(1-Factor) + Red(Color2)*Factor
Protected G.i = Green(Color1)*(1-Factor) + Green(Color2)*Factor
Protected B.i = Blue(Color1)*(1-Factor) + Blue(Color2)*Factor
ProcedureReturn RGB(R, G, B)
EndProcedure
; Perform a smooth filling of area (x,y) with color FillColor using the max color distance MaxColorDistance
Procedure SmoothFillArea(X.i, Y.i, FillColor.l, MaxColorDistance.f)
Protected Dim Filled.i(OutputWidth()-1, OutputHeight()-1)
Protected NewList Seeds.Vector()
Protected Factor.f
Protected SeedColor.l = Point(X, Y)
AddElement(Seeds()) : Seeds()\X = X : Seeds()\Y = Y : Filled(X, Y) = #True
ResetList(Seeds())
While NextElement(Seeds())
*Seed.Vector = @Seeds()
With *Seed
If MaxColorDistance = 0
Factor = Bool(ColorDistance(Point(\X, Seeds()\Y), SeedColor) <> 0.0)
Else
Factor = ColorDistance(Point(\X, Seeds()\Y), SeedColor) / MaxColorDistance
EndIf
If Factor < 1.0
Plot(\X, \Y, ColorMix(FillColor, Point(\X, \Y), Factor*Factor))
If \X > 0 And Filled(\X-1, \Y) = #False
AddElement(Seeds()) : Seeds()\X = \X-1 : Seeds()\Y = \Y : Filled(\X-1, \Y) = #True
EndIf
If \X < OutputWidth()-1 And Filled(\X+1, \Y) = #False
AddElement(Seeds()) : Seeds()\X = \X+1 : Seeds()\Y = \Y : Filled(\X+1, \Y) = #True
EndIf
If \Y > 0 And Filled(\X, \Y-1) = #False
AddElement(Seeds()) : Seeds()\X = \X : Seeds()\Y = \Y-1 : Filled(\X, \Y-1) = #True
EndIf
If \Y < OutputHeight()-1 And Filled(\X, \Y+1) = #False
AddElement(Seeds()) : Seeds()\X = \X : Seeds()\Y = \Y+1 : Filled(\X, \Y+1) = #True
EndIf
ChangeCurrentElement(Seeds(), *Seed)
EndIf
EndWith
Wend
EndProcedure
;- Example
InitNetwork()
UsePNGImageDecoder()
CatchImage(#Image, ReceiveHTTPMemory("https://i.ibb.co/WP4XVGd/cat3.png"))
width=ImageWidth(#Image)
height=ImageHeight(#Image)
OpenWindow(#Window,0,0,width,height+30,"Smooth Fill Area",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget,0,0,width,height)
TrackBarGadget(#Slider,0,height,width,30,0,440)
If StartDrawing(CanvasOutput(#Gadget))
DrawImage(ImageID(#Image), 0, 0)
StopDrawing()
EndIf
Define FillColor.l = $FFB040 ; Filling color
Define MaxColorDistance.f = 200.0 ; Max distance of the colors: 0.0 until 441.67
; 0.0 meens only exacly same pixel color. Value over 441.67 fills all pixels
SetGadgetState(#Slider,MaxColorDistance)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case #Slider
MaxColorDistance=GetGadgetState(#Slider)
SetWindowTitle(#Window,"Distance = "+Str(MaxColorDistance))
Case #Gadget
Select EventType()
Case #PB_EventType_LeftClick
If StartDrawing(CanvasOutput(#Gadget))
SmoothFillArea(GetGadgetAttribute(#Gadget, #PB_Canvas_MouseX), GetGadgetAttribute(#Gadget, #PB_Canvas_MouseY), FillColor, MaxColorDistance)
StopDrawing()
EndIf
EndSelect
EndSelect
EndSelect
ForEver
End
Re: Smoother FillArea routine
Posted: Thu Oct 14, 2021 9:19 am
by kernadec
hello,
Really nice thanks @ STARGÅTE, Michael Vogel
Best Regards