Flood Fill Algorithm in C#

Flood fill is the algorithm that I struggled when I tried to implement at first, however I found a better way to implement it for me. Of course, this way it's not best approach but it is enough for now. There are some types of implementation methods. At first, I tried to implement flood fill algorithm using recursive function. But the recursion method is not efficient way, especially for the big structures. Probably, this usage can be caused stack overflow. Maybe, the recursion method can be used for the small structures but I would not prefer that anyway.

pseudo

Another method is the implementation using stack. However, this can be caused stack overflow, although not very often. Therefore, I'm going to use dictionary struct to minimize this risk. We can understand from the source code in below why I use dictionaryDictionary<uint, bool> visited;. I used C# programming language:

void fillColor(Vector2 nodePos)
{
    Stack<Vector2> nodes = new Stack<Vector2>();
   	
    Dictionary<Vector2, bool> registry = new Dictionary<Vector2, bool>();

    nodes.Push(nodePos);

    while(nodes.Count != 0)
    {
        Vector2 currentNode = nodes.Pop();
        
        if(!(currentNode.x >= 0 && currentNode.x < 17 && currentNode.y >= 0 && currentNode.y < 32))
        {
            continue;
        }
        if(array[(int)currentNode.x, (int)currentNode.y] != 0)
        {
            continue;
        }
        else if(array[(int)currentNode.x, (int)currentNode.y] == 0)
        {   
            array[(int)currentNode.x, (int)currentNode.y] = 3;

            if(!registry.ContainsKey(new Vector2(currentNode.x-1, currentNode.y)))
            {
                registry[new Vector2(currentNode.x-1, currentNode.y)] = true;
                nodes.Push(new Vector2(currentNode.x-1, currentNode.y));
            }
            if(!registry.ContainsKey(new Vector2(currentNode.x + 1, currentNode.y)))
            {
                registry[new Vector2(currentNode.x + 1, currentNode.y)] = true;
                nodes.Push(new Vector2(currentNode.x + 1, currentNode.y));
            }
            if(!registry.ContainsKey(new Vector2(currentNode.x, currentNode.y - 1)))
            {
                registry[new Vector2(currentNode.x, currentNode.y - 1)] = true;
                nodes.Push(new Vector2(currentNode.x, currentNode.y - 1));
            }
            if(!registry.ContainsKey(new Vector2(currentNode.x, currentNode.y + 1)))
            {
                registry[new Vector2(currentNode.x, currentNode.y + 1)] = true;
                nodes.Push(new Vector2(currentNode.x, currentNode.y + 1));
            }
        }
    }
}
Let's examine the code in order:

  1. Primarily, we execute the method with the position of the chosen node as argument.
  2. The stack structure called nodes is created. This structure of stack contains the position of the nodes as value.
  3. Also, the dictionary called registry is created. The reason I use this if the current node position is already visited before that then avoid it to adding to the stack called nodes. After the visit any node we marked as visited via assign true.
  4. The first node position is added to the stack. 
  5. While loop is started. The running of this loop will continue as long as the length of elements contained in the stack structure is higher than 0.
    1. At the beginning of the loop, the node position to be handled for that moment is popped from the stack structure.
    2. First, it is checked whether this node position is suitable for the main structure to be filled.
    3. If the position represents a non-existent position, the loop is rerun directly and step a is executed and continued same steps.
    4. A second control block is used. If the given position does not have the value to be filled, this node position is skipped and the loop is rerun directly and step a is executed again and continued same steps. For instance, we want to turn a red region blue. If the pixel coordinate to be visited is not red but it's green or another color, it will be skipped and the loop will be continued from the beginning of the loop.
    5. If there is a node position that does not comply with the first two conditions, that node can be filled. In this case, the required value is assigned to the position to be filled. Afterwards, all the neighbors of this node are checked separately and if it has not been visited before, the position value is added to the nodes stack structure. We consider only the NEST neighbors of the existing node.

No comments:

Post a Comment