Flood Fill Help

BlitzMax Forums/BlitzMax Programming/Flood Fill Help

Qweeg(Posted 2006) [#1]
Could someone please help me? I am playing about with a routine to flood fill areas of the screen and have got it almost working - but not quite. I am using a black and white line drawing and the idea is that you click on the image and it fills that section with a random colour. But what actually happens is it fills most of the area but not right up to the lines. At first I thought it was because the picture was greyscale rather than just black and white, but I changed it to be only 2 colours and the problem still occurs.

Below is my code - I am sure it is just my logic on how to do this is a little screwed, but can't see for looking.

I got the image from here (sorry I don't have anywhere to host it at the moment), and just cropped to 1024*768 and reduced to just 2 colours.

http://www.bbc.co.uk/cbeebies/printables/printcolour/storymakers/

Any help would be really appreciated.




Qweeg(Posted 2006) [#2]
Stupid jpg format! Okay my fault the code works fine - even though I was setting the image to be two colours, on saving as a jpg some sort of dithering was happening so it wasn't two colours anymore. Saving as a png instead solves this.

But - whilst this code works fine; it is really slow to fill larger areas. Does anyone have any suggestion on how to improve this to speed things up a bit?


(tu) ENAY(Posted 2006) [#3]
Presuming you're only filling up only a single colour.
What you could is scan the image and make a lookup table (array the size of your image) of all the valid pixels you can write too and ones that you can't, true and false.

Then you can perform all your gfx operations by just consulting the lookup table and you'll only need to plot the pixels, should cut down significantly on the number of readpixels going on, quicker to read your array of ints.

Briefly scanning your code you appear to be kind of like bleeding your pixels around and checking its neighbours, looking at true or false values is better than checking the colours every time (since you're often checking the same pixel more than once)

May be worth a look, might be faster.


tonyg(Posted 2006) [#4]
Snarty's fill code was one of the best for BB and here's a Bmax version.
<edit>because it's BlueCow...
'Fill Routines
' Written By Paul Snart (Snarty) - Converted to BMax by klepto2 in Oct 2005
' Oct 2001

' RCol = RGB Color To Fill with
' Ax = X Start on Image To Fill
' Ay = Y Start on Image To Fill
' Image = Image To fill on

Strict


Type Point
	Global Point_List:TList
     Field x
     Field y

	Method New()
		If Point.Point_List = Null Then Point.Point_List = New TList
		Point.Point_List.AddLast(Self)
	End Method
	
End Type

Function FloodFill(RCol,ax,ay,Image:TPixmap)

    	 Local timeit=MilliSecs()
         Local y:Int
 		 Local BCol=Image.ReadPixel(ax,ay)
    	 Local ImW=Image.width
    	 Local ImH=Image.Height
     
      If BCol<>RCol
      
	Local   Hlt=-1
	Local  	Hlb=-1
    Local   Hrt=-1
	Local	Hrb=-1
    Local   Entrys=1
	Local   FP:Point = New Point
            Fp.x=ax
            Fp.y=ay  
            
          Repeat
               FP:Point=Point(Point.Point_List.First())
        Local  Lx=Fp.x
        Local  Rx=Fp.x+1
        Local  HitL=False
	   	Local  HitR=False
               Hlt=-1
			   Hlb=-1
               Hrt=-1 
			   Hrb=-1
               Repeat
                    If Lx=>0 And HitL=False
        Local           CColL=Image.ReadPixel(Lx,Fp.y)
                         If CColL=BCol
                              Image.WritePixel Lx,Fp.y,RCol
                              If Fp.y>0
                                   CColL=Image.ReadPixel(Lx,Fp.y-1)
                                   If CColL=BCol
                                        Hlt=Lx
                                   Else
                                        If Hlt<>-1
                                             y=Fp.y-1
                                             FP:Point = New Point
                                             Fp.y=y
									    Fp.x=Hlt
                                             Hlt=-1
                                             FP:Point = Point(Point.Point_List.First())
                                             Entrys=Entrys+1
                                        EndIf
                                   EndIf
                              EndIf
                              If Fp.y<ImH-1 
                                   CColL=Image.ReadPixel(Lx,Fp.y+1)
                                   If CColL=BCol
                                        Hlb=Lx
                                   Else
                                        If Hlb<>-1
                                             y=Fp.y+1
                                             FP:Point = New Point
                                             Fp.y=y
									    Fp.x=Hlb
                                             Hlb=-1
                                             FP:Point = Point(Point.Point_List.First())
                                             Entrys=Entrys+1
                                        EndIf
                                   EndIf
                              EndIf
                              Lx=Lx-1
                         Else
                              HitL=True
                              If Hlt<>-1 
                                   y=Fp.y-1
                                   FP:Point = New Point
                                   Fp.y=y
							   Fp.x=Hlt
                                   Hlt=-1
                                   FP:Point = Point(Point.Point_List.First())
                                   Entrys=Entrys+1
                              EndIf
                              If Hlb<>-1 
                                   y=Fp.y+1
                                   FP:Point = New Point
                                   Fp.y=y
							   Fp.x=Hlb
                                   Hlb=-1
                                   FP:Point = Point(Point.Point_List.First())
                                   Entrys=Entrys+1
                              EndIf
                         EndIf
                    Else
                         HitL=True
                         If Hlt<>-1 
                              y=Fp.y-1
                              FP:Point = New Point
                              Fp.y=y
						   Fp.x=Hlt
                              Hlt=-1
                              FP:Point = Point(Point.Point_List.First())
                              Entrys=Entrys+1
                         EndIf
                         If Hlb<>-1 
                              y=Fp.y+1
                              FP:Point = New Point
                              Fp.y=y
						   Fp.x=Hlb
                              Hlb=-1
                              FP:Point = Point(Point.Point_List.First())
                              Entrys=Entrys+1
                         EndIf
                    EndIf
                    If Rx<=ImW-1 And HitR=False
        Local           CColR=Image.ReadPixel(Rx,Fp.y)
                         If CColR=BCol
                              Image.WritePixel Rx,Fp.y,RCol
                              If Fp.y>0 
                                   CColR=Image.ReadPixel(Rx,Fp.y-1)
                                   If CColR=BCol
                                        Hrt=Rx
                                   Else
                                        If Hrt<>-1
                                             y=Fp.y-1
                                             FP:Point = New Point
                                             Fp.y=y
									    Fp.x=Hrt
                                             Hrt=-1
                                             FP:Point = Point(Point.Point_List.First())
                                             Entrys=Entrys+1
                                        EndIf
                                   EndIf
                              EndIf
                              If Fp.y<ImH-1
                                   CColR=Image.ReadPixel(Rx,Fp.y+1)
                                   If CColR=BCol
                                        Hrb=Rx
                                   Else
                                        If Hrb<>-1
                                             y=Fp.y+1
                                             FP:Point = New Point
                                             Fp.y=y
									    Fp.x=Hrb
                                             Hrb=-1
                                             FP:Point = Point(Point.Point_List.First())
                                             Entrys=Entrys+1
                                        EndIf
                                   EndIf
                              EndIf
                              Rx=Rx+1
                         Else
                              HitR=True
                              If Hrt<>-1
                                   y=Fp.y-1
                                   FP:Point = New Point
                                   Fp.y=y
							   Fp.x=Hrt
                                   Hrt=-1
                                   FP:Point = Point(Point.Point_List.First())
                                   Entrys=Entrys+1
                              EndIf
                              If Hrb<>-1
                                   y=Fp.y+1
                                   FP:Point = New Point
                                   Fp.y=y
							   Fp.x=Hrb
                                   Hrb=-1
                                   FP:Point = Point(Point.Point_List.First())
                                   Entrys=Entrys+1
                              EndIf
                         EndIf
                    Else
                         HitR=True
                         If Hrt<>-1
                              y=Fp.y-1
                              FP:Point = New Point
                              Fp.y=y
	   					   Fp.x=Hrt
                              Hrt=-1
                              FP:Point = Point(Point.Point_List.First())
                              Entrys=Entrys+1
                         EndIf
                         If Hrb<>-1
                              y=Fp.y+1
                              FP:Point = New Point
                              Fp.y=y
						 Fp.x=Hrb
                              Hrb=-1
                              FP:Point = Point(Point.Point_List.First())
                              Entrys=Entrys+1
                         EndIf
                    EndIf
                    
               Until (HitR=True And HitL=True) Or KeyHit(1)
               FP:Point=Point(Point.Point_List.First())
               Point.Point_List.Remove(FP)
               Entrys=Entrys-1  
              
               
          Until Entrys=False Or KeyHit(1)
     EndIf
               
	Local     mhit=False
    		  DebugLog (Float(MilliSecs()-TimeIt)/1000)+" seconds"

End Function
Graphics 800,600
Local image:timage=LoadImage("bluecow.png")
While Not KeyHit(1)
  Cls
  DrawImage image,0,0
  If MouseHit(1)
	Local Test:TPixmap = LockImage(image)
	FloodFill($FFff00ff,MouseX(),MouseY(),Test)
  EndIf
Flip
Wend



Curtastic(Posted 2006) [#5]
My BB flood fill is faster and easier to understand, but nobody cares about old me...
I think I'll convert it to blitzmax.

http://www.blitzbasic.com/codearcs/codearcs.php?code=314


Qweeg(Posted 2006) [#6]
thanks guys.

@Enay - good idea, this seems to be kinda what Curtastic's code does, so definitely worth looking at using arrays.

@Tony - thanks for this, this is loads quicker than mine! (I just need to work through the code to get my head around it).

@Curtastic - thanks for your code. I do think it is a little easier to understand initially (even though I don't know BB at all). It seems to be a little similar to my code in essence, except you track each pixel you check in an array, so that it only gets read once, whereas in mine each pixel could potentially be read several times - obviously slowing things down a lot. Be interesting to see it converted into blitzmax to compare.

Thanks chaps - big help as always


Curtastic(Posted 2006) [#7]
thanks for checking it out.

Expanding on what Enay was saying is that if you have all the pixel colors in an array, you can just keep track of every pixel you change and you never EVER have to use readpixel!