[bb] FloodFill - Really!!! by Adam Novagen [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : FloodFill - Really!!!
Author : Adam Novagen
Posted : 1+ years ago

Description : FLOODFILL
By Adam Novagen

After just an hour & a half of typing, I've finally perfected a Flood Fill routine, like those used in paint programs! It can theoretically fill any size image region, and any shape too!
Depending on computer configuration, graphics mode, and the number of pixels to be filled, the fill can take anywhere from 5 to 1000 milliseconds (.005 to 1 seconds); just trust the code!

HOW TO USE FLOODFILL()
FloodFill() is declared like this (not verbatim):
<div class="quote"> FloodFill(Image,Fill X,Fill Y,Fill Red,Fill Green,Fill Blue)
</div>
Image is the image to be filled; I'm afraid the routine doesn't work directly on graphics buffers. Fill X & Y are the starting coordinates for the fill, and Fill Red, Green and Blue are the RGB color values to fill with.

THE TESTING LOOP
This file contains a small testing loop at the end. It draws an image of your choice at 0,0, and shows the mouse location with a flashing pixel. Left-clicking on the image will fill that part with a random color; the FloodFill() RGB values in the testing loop are set to Rand(255). The Esc key ends the program, as usual.

OPTIONAL CODE
The FloodFill() routine contains two sets of optional code, which at the moment has been commented with a semicolon (;). The first line, the interrupt line, is a special "Panic Button" line that lets the Esc key end the program at any point during the execution of FloodFill(). You might want to uncomment this until you have faith in FloodFill's ability to avoid crashes & freezes, but trust me, you won't need it forever!
The second bit of optional code lets you watch the fill in action (theoretically.) Depending on your computer configuration, this will probably slow FloodFill() down, but it's worth watching at least once; in a small image, that is!

ADDITIONAL FUNCTIONS: PIXELRED/GREEN/BLUE()
PixelRed(), PixelGreen(), and PixelBlue() are function used by FloodFill to obtain color information of certain pixels without changing the actual Color R,G,B settings. However, you can also use them like this:
<div class="quote"> PixelRed(Pixel X,Pixel Y)
</div>
PixelGreen() & Blue() are declared the same way, and all three return a value from 0 to 255.

FINAL NOTES
All the variables in the FloodFill routine, except for the Pixel type, are preceded by "Ghz_Lib_Var_". This is to minimize the possibility of you accidentally creating a variable with the same name, thus causing FloodFill() or your program to generate bugs. "Ghz_Lib_Var_" is used because FloodFill() and the Pixel functions are all used in the Gigahertz Games Command Library. Gigahertz_Library_Variable = Ghz_Lib_Var, get it? You can mess around with these variables if you really want to get into the FloodFill routine, but I only recommend that for expert Blitzers.

Enjoy!


Code :
Code: blitzbasic
Type Pixel
	Field X,Y
End Type


Function FloodFill(FillImage,FX,FY,FR,FG,FB);COMPLETE


If FX < 0 Or FX > ImageWidth(FillImage) - 1 Or FY < 0 Or FY > ImageHeight(FillImage) - 1
	RuntimeError("GHZLIB ERROR" + Chr(10) + "Invalid coordinates: " + FX + "," + FY + Chr(10) + "Coords must be within image boundaries")
EndIf


Local CurrentBuffer = GraphicsBuffer()
Local CurrentRed = ColorRed()
Local CurrentGreen = ColorGreen()
Local CurrentBlue = ColorBlue()


SetBuffer ImageBuffer(FillImage)
LockBuffer


Local TarR = PixelRed(FX,FY)
Local TarG = PixelGreen(FX,FY)
Local TarB = PixelBlue(FX,FY)


Color FR,FG,FB
WritePixelFast FX,FY,FB + (FG * 256) + (FR * (256 * 256))
Pixel.Pixel = New Pixel
PixelX = FX
PixelY = FY


Repeat
Local PixelsRemaining = False
For Pixel.Pixel = Each Pixel
Local PixelLeft = False
Local PixelAbove = False
Local PixelRight = False
Local PixelBelow = False
Local PixelX = PixelX
Local PixelY = PixelY
If PixelX > 0;check left
	If PixelRed(PixelX - 1,PixelY) = TarR And PixelGreen(PixelX - 1,PixelY) = TarG And PixelBlue(PixelX - 1,PixelY) = TarB
		PixelLeft = True
		PixelsRemaining = True
	EndIf
EndIf
If PixelY > 0;check above
	If PixelRed(PixelX,PixelY - 1) = TarR And PixelGreen(PixelX,PixelY - 1) = TarG And PixelBlue(PixelX,PixelY - 1) = TarB
		PixelAbove = True
		PixelsRemaining = True
	EndIf
EndIf
If PixelX < ImageWidth(FillImage) - 1;check right
	If PixelRed(PixelX + 1,PixelY) = TarR And PixelGreen(PixelX + 1,PixelY) = TarG And PixelBlue(PixelX + 1,PixelY) = TarB
		PixelRight = True
		PixelsRemaining = True
	EndIf
Else
	PixelRight = False
EndIf
If PixelY < ImageHeight(FillImage) - 1;check below
	If PixelRed(PixelX,PixelY + 1) = TarR And PixelGreen(PixelX,PixelY + 1) = TarG And PixelBlue(PixelX,PixelY + 1) = TarB
		PixelBelow = True
		PixelsRemaining = True
	EndIf
Else
	PixelBelow = False
EndIf
;If KeyDown(1) Then End
Delete Pixel
PixelNum = PixelNum - 1
;LockBuffer
If PixelLeft = True
	Pixel.Pixel = New Pixel
	PixelX = PixelX - 1
	PixelY = PixelY
	PixelNum = PixelNum + 1
	PixelLeft = False
	WritePixelFast PixelX,PixelY,FB + (FG * 256) + (FR * (256 * 256))
EndIf
If PixelAbove = True
	Pixel.Pixel = New Pixel
	PixelX = PixelX
	PixelY = PixelY - 1
	PixelNum = PixelNum + 1
	PixelAbove = False
	WritePixelFast PixelX,PixelY,FB + (FG * 256) + (FR * (256 * 256))
EndIf
If PixelRight = True
	Pixel.Pixel = New Pixel
	PixelX = PixelX + 1
	PixelY = PixelY
	PixelNum = PixelNum + 1
	PixelRight = False
	WritePixelFast PixelX,PixelY,FB + (FG * 256) + (FR * (256 * 256))
EndIf
If PixelBelow = True
	Pixel.Pixel = New Pixel
	PixelX = PixelX
	PixelY = PixelY + 1
	PixelNum = PixelNum + 1
	PixelBelow = False
	WritePixelFast PixelX,PixelY,FB + (FG * 256) + (FR * (256 * 256))
EndIf
;!UNCOMMENT THE FOLLOWING CODE TO SEE FLOODFILL IN ACTION!
;UnlockBuffer
;SetBuffer CurrentBuffer
;DrawImage FillImage,0,0
;Flip
;SetBuffer ImageBuffer(FillImage)
;LockBuffer
Next
Until PixelsRemaining = False

UnlockBuffer
SetBuffer CurrentBuffer
Color CurrentRed,CurrentGreen,CurrentBlue


End Function


Function PixelGreen(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)


Local Ghz_Lib_Var_CurrentRed = ColorRed()
Local Ghz_Lib_Var_CurrentGreen = ColorGreen()
Local Ghz_Lib_Var_CurrentBlue = ColorBlue()

GetColor(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)
Local Ghz_Lib_Var_Green = ColorGreen()

Color Ghz_Lib_Var_CurrentRed,Ghz_Lib_Var_CurrentGreen,Ghz_Lib_Var_CurrentBlue

Return Ghz_Lib_Var_Green


End Function


Function PixelRed(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)


Local Ghz_Lib_Var_CurrentRed = ColorRed()
Local Ghz_Lib_Var_CurrentGreen = ColorGreen()
Local Ghz_Lib_Var_CurrentBlue = ColorBlue()

GetColor(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)
Local Ghz_Lib_Var_Red = ColorRed()

Color Ghz_Lib_Var_CurrentRed,Ghz_Lib_Var_CurrentGreen,Ghz_Lib_Var_CurrentBlue

Return Ghz_Lib_Var_Red


End Function


Function PixelBlue(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)


Local Ghz_Lib_Var_CurrentRed = ColorRed()
Local Ghz_Lib_Var_CurrentGreen = ColorGreen()
Local Ghz_Lib_Var_CurrentBlue = ColorBlue()

GetColor(Ghz_Lib_Var_PixelX,Ghz_Lib_Var_PixelY)
Local Ghz_Lib_Var_Blue = ColorBlue()

Color Ghz_Lib_Var_CurrentRed,Ghz_Lib_Var_CurrentGreen,Ghz_Lib_Var_CurrentBlue

Return Ghz_Lib_Var_Blue


End Function


;!TESTING LOOP
;To use this mini-program, just click anywhere on the image.
;The cursor is represented by a flashing pixel.
Graphics 800,600,0,2
Global Image = LoadImage("sample image 1.bmp");replace "image.bmp" with a valid filename
SetBuffer BackBuffer()
SeedRnd MilliSecs()
While Not KeyDown(1)
Cls
If MouseHit(1) Then FloodFill(Image,MouseX(),MouseY(),Rand(255),Rand(255),Rand(255))
DrawImage Image,0,0
Color Rand(255),Rand(255),Rand(255)
Plot MouseX(),MouseY();the makeshift cursor
Flip
Wend
End


Comments :


_33(Posted 1+ years ago)

 Very handy, thank you!My pimped up version (for archival purpose):
Code: BASIC
Graphics 800,600,0,2
Global Image = LoadImage("apple_logo_640x480.jpg") ; <---- put image filename here
SetBuffer BackBuffer()
SeedRnd MilliSecs()
While Not KeyDown(1)
	Cls
	If MouseHit(1) Then FloodFill(Image,MouseX(),MouseY(),Rand(255),Rand(255),Rand(255))
	DrawImage Image,0,0
	Color 255,255,255
	Plot MouseX(),MouseY()
	Flip
Wend
End


Type Pixel
	Field X,Y
End Type

Function FloodFill(FillImage, Fill_X, Fill_Y, FR, FG, FB)
	Local width% = ImageWidth(FillImage)
	Local height% = ImageHeight(FillImage)

	If Fill_X < 0 Or Fill_X > width - 1 Or Fill_Y < 0 Or Fill_Y > height - 1
		Return ; Coords ouside image boundaries
	EndIf

	Local CurrentBuffer = GraphicsBuffer()
	SetBuffer ImageBuffer(FillImage)
	LockBuffer

	Local Current_RGB% = ReadPixelFast(Fill_X, Fill_Y)

	Local RGB% = FB + FG Shl 8 + FR Shl 16
	Pixel.Pixel = New Pixel
	PixelX = Fill_X
	PixelY = Fill_Y
	WritePixelFast PixelX,PixelY,RGB

	Repeat
		Local PixelsRemaining = False
		For Pixel.Pixel = Each Pixel
			PixelX = PixelX
			PixelY = PixelY
			PixelLeft = False
			PixelAbove = False
			PixelRight = False
			PixelBelow = False
			If PixelX > 0;check left
				If Current_RGB = ReadPixelFast(PixelX - 1,PixelY) Then
					PixelLeft = True
					PixelsRemaining = True
				EndIf
			EndIf
			If PixelY > 0;check above
				If Current_RGB = ReadPixelFast(PixelX,PixelY - 1) Then
					PixelAbove = True
					PixelsRemaining = True
				EndIf
			EndIf
			If PixelX < width - 1;check right
				If Current_RGB = ReadPixelFast(PixelX + 1,PixelY) Then
					PixelRight = True
					PixelsRemaining = True
				EndIf
			EndIf
			If PixelY < height - 1;check below
				If Current_RGB = ReadPixelFast(PixelX,PixelY + 1) Then
					PixelBelow = True
					PixelsRemaining = True
				EndIf
			EndIf
			Delete Pixel
			If PixelLeft = True
				Pixel.Pixel = New Pixel
				PixelX = PixelX - 1
				PixelY = PixelY
				PixelLeft = False
				WritePixelFast PixelX,PixelY,RGB
			EndIf
			If PixelAbove = True
				Pixel.Pixel = New Pixel
				PixelX = PixelX
				PixelY = PixelY - 1
				PixelAbove = False
				WritePixelFast PixelX,PixelY,RGB
			EndIf
			If PixelRight = True
				Pixel.Pixel = New Pixel
				PixelX = PixelX + 1
				PixelY = PixelY
				PixelRight = False
				WritePixelFast PixelX,PixelY,RGB
			EndIf
			If PixelBelow = True
				Pixel.Pixel = New Pixel
				PixelX = PixelX
				PixelY = PixelY + 1
				PixelBelow = False
				WritePixelFast PixelX,PixelY,RGB
			EndIf
		Next
	Until PixelsRemaining = False
	UnlockBuffer
	SetBuffer CurrentBuffer
End Function