Page 1 of 1

FloodFill with threshold possible?

Posted: Sat Mar 22, 2025 8:40 am
by amyren
Is there a way to achieve FloodFill to also fill the surrounding pixels with near-similar colors?
Preferably by being able to set a threshold value to control this.
Something like the threshold setting found in Gimp.

If not, would this be possible to add as an option to FloodFill in the future?

Re: FloodFill with threshold possible?

Posted: Sun Mar 23, 2025 6:58 pm
by amyren
Deepseek came up with a way to floodfill with a threshold value.
I asked it to make a small example of a working code that loads a 640x480 testimage and floodfills it with RED color in the area where clicked, and to use a threshold variable to also fill similar colors. After quite a lot of corrections, the code is working. The Filling process is quite slow but it does what it was asked to. Setting the threshold value to 0 will only fill the exact same color.

Here is the working code:
Any suggestions to speed up the process?

Code: Select all

@DISPLAY {Title = "Flood Fill with Threshold", Width = 640, Height = 480, Color = #WHITE}

; Constants
CANVAS_WIDTH = 640
CANVAS_HEIGHT = 480

; Global variables
Global activeBrush
Global threshold = 1 ; Default threshold (1-100)
Global colorToFill = #RED ; Default fill color


; Function to calculate the color difference between two colors
Function ColorDifference(color1, color2)
    ; If the colors are identical, return 0
    If color1 = color2
        Return(0)
    EndIf

    ; Extract RGB components from color1
    r1 = (color1 >> 16) & 255
    g1 = (color1 >> 8) & 255
    b1 = color1 & 255

    ; Extract RGB components from color2
    r2 = (color2 >> 16) & 255
    g2 = (color2 >> 8) & 255
    b2 = color2 & 255

    ; Calculate the Euclidean distance between the two colors
    diff = Sqrt((r1 - r2)^2 + (g1 - g2)^2 + (b1 - b2)^2)

    ; Normalize the difference to a range of 0-100
    normalizedDiff = (diff / 441.67) * 100
    Return(normalizedDiff)
EndFunction

; Custom flood fill function with threshold
Function FloodFillWithThreshold(x, y, targetColor, fillColor, threshold)

    ; Create a stack for storing pixels to process
    stack = CreateList()
    InsertItem(stack, {x = x, y = y})

    ; Create a visited matrix to avoid reprocessing pixels
    visited = {} ; Use a table to simulate a 2D array
    For Local i = 0 To CANVAS_WIDTH - 1
        visited[i] = {}
        For Local j = 0 To CANVAS_HEIGHT - 1
            visited[i][j] = False
        Next
    Next

    ; Process the stack
    While ListItems(stack) > 0
        ; Pop the last pixel from the stack
        pixel = RemoveItem(stack, ListItems(stack) - 1)
        x = pixel.x
        y = pixel.y

        ; Check if the pixel is within bounds
        If x >= 0 And x < CANVAS_WIDTH And y >= 0 And y < CANVAS_HEIGHT
            ; Check if the pixel has already been visited
            If Not visited[x][y]
                ; Get the color of the current pixel from the brush
                currentColor = ReadBrushPixel(activeBrush, x, y)

                ; Calculate the color difference
                diff = ColorDifference(currentColor, targetColor)
                If IsNil(diff)
                Else
                    ; Check if the color difference is within the threshold
                    If diff <= threshold
                        ; Set the pixel in the brush to the fill color
                        SelectBrush(activeBrush)
                        Line(x, y, x, y, fillColor)

                        ; Mark the pixel as visited
                        visited[x][y] = True

                        ; Add neighboring pixels to the stack
                        InsertItem(stack, {x = x + 1, y = y})
                        InsertItem(stack, {x = x - 1, y = y})
                        InsertItem(stack, {x = x, y = y + 1})
                        InsertItem(stack, {x = x, y = y - 1})
                    EndIf
                EndIf

                ; Increment the debug counter
                debugCounter = debugCounter + 1
            EndIf
        EndIf
    Wend
EndFunction

; Main program
Function p_Main()
    ; Load the test image with an explicit brush ID (or use NIL for auto-assign)
    activeBrush = LoadBrush(Nil, "testfile.png")
    If activeBrush = Nil
        DebugPrint("Error: Could not load testfile.png!")
        Return
    EndIf

    ; Display the loaded brush
    DisplayBrush(activeBrush, 0, 0)

    ; Main loop
    Repeat
        ; Wait for a mouse click event
        WaitLeftMouse

        ; Get the mouse position
        x = MouseX()
        y = MouseY()

        ; Check if the click is within the canvas bounds
        If x >= 0 And x < CANVAS_WIDTH And y >= 0 And y < CANVAS_HEIGHT
            ; Get the target color at the clicked pixel from the brush
            targetColor = ReadBrushPixel(activeBrush, x, y)

            ; Perform the flood fill with the specified threshold and color
            FloodFillWithThreshold(x, y, targetColor, colorToFill, threshold)

            ; Update the display
            DisplayBrush(activeBrush, 0, 0)
        EndIf
    Forever
EndFunction

; Run the program
p_Main()

Re: FloodFill with threshold possible?

Posted: Sun Mar 23, 2025 9:14 pm
by airsoftsoftwair
amyren wrote: Sat Mar 22, 2025 8:40 am If not, would this be possible to add as an option to FloodFill in the future?
Not likely to come as an addition to Hollywood's graphics core but there may be a dedicated image processing plugin in the future which could do that.