Search code examples
arraysjuliaflood-fill

How does one implement flood fill in a 2D array in Julia?


The problem

Suppose I have a 2D matrix, with some random integers being either a 0 or a 1. How do I flood-fill a continuous region in my array?

This algorithm can especially be used in image processing to fill a color with another color in an enclosed region like the paint-bucket tool.

Example

Suppose my array is:

1 0 1 1 1 1 0
0 0 1 1 1 1 1
0 0 0 1 1 1 1
0 1 0 0 0 1 1
0 0 0 1 1 1 1

I want to fill the region of 1s in the top-right corner with something else like an 8. How do I implement this? I know the indices of any 1 in that region, and I have the indices of any one of the 1s.

After filling with 8s, the array should look like this:

1 0 8 8 8 8 0
0 0 8 8 8 8 8
0 0 0 8 8 8 8
0 1 0 0 0 8 8
0 0 0 8 8 8 8 

My efforts:

I have tried the following methods:

  • Going through each item in the array, checking if it is a 1, replacing it with an 8. Clearly this didn’t work since it simply replaced all the 1s with 8s. Even the 1s outside the region were converted to 8s.
  • Using relative coordinates, checking for 1s, and replacing with 8s for the initial indices we are given. In short, replacing all neighbors whose values are 1 with an 8. This also did not work since it only replaced the nearest 8 neighbors and did not fill the region as I wanted.

Solution

  • Voila! The answer lied in recursion:

    The function takes in your array as arr, and the coordinates (or indices) of the 1 you know in the form of a tuple (x, y) as arguments.

    When using relative coordinates, we call the flood_fill function on each of them:

    function flood_fill(arr, (x, y))
        # check every element in the neighborhood of the element at (x, y) in arr
        for x_off in -1:1
            for y_off in -1:1
                # put the next part in a try-catch block so that if any index
                # is outside the array, we move on to the next element.
                try
                    # if the element is a 1, change it to an 8 and call flood_fill 
                    # on it so it fills it's neighbors
                    if arr[x + x_off, y + y_off] == 1
                        arr[x + x_off, y + y_off] = 8
                        flood_fill(arr, (x + x_off, y + y_off))
                    end
                catch
                    continue
                end
            end
        end
    end