Flood fill

Last updated
Recursive flood fill with 4 directions Recursive Flood Fill 4 (aka).gif
Recursive flood fill with 4 directions

Flood fill, also called seed fill, is a flooding algorithm that determines and alters the area connected to a given node in a multi-dimensional array with some matching attribute. It is used in the "bucket" fill tool of paint programs to fill connected, similarly colored areas with a different color, and in games such as Go and Minesweeper for determining which pieces are cleared. A variant called boundary fill uses the same algorithms but is defined as the area connected to a given node that does not have a particular attribute. [1]

Contents

Note that flood filling is not suitable for drawing filled polygons, as it will miss some pixels in more acute corners. [2] Instead, see Even-odd rule and Nonzero-rule.

The algorithm parameters

Recursive flood fill with 8 directions Recursive Flood Fill 8 (aka).gif
Recursive flood fill with 8 directions

The traditional flood-fill algorithm takes three parameters: a start node, a target color, and a replacement color. The algorithm looks for all nodes in the array that are connected to the start node by a path of the target color and changes them to the replacement color. For a boundary-fill, in place of the target color, a border color would be supplied.

In order to generalize the algorithm in the common way, the following descriptions will instead have two routines available. [3] One called Inside which returns true for unfilled points that, by their color, would be inside the filled area, and one called Set which fills a pixel/node. Any node that has Set called on it must then no longer be Inside.

Depending on whether we consider nodes touching at the corners connected or not, we have two variations: eight-way and four-way respectively.

Stack-based recursive implementation (four-way)

The earliest-known, implicitly stack-based, recursive, four-way flood-fill implementation goes as follows: [4] [5] [6] [7]

Flood-fill (node):  1. If node is not Inside return.  2. Set the node  3. Perform Flood-fill one step to the south of node.  4. Perform Flood-fill one step to the north of node  5. Perform Flood-fill one step to the west of node  6. Perform Flood-fill one step to the east of node  7. Return.

Though easy to understand, the implementation of the algorithm used above is impractical in languages and environments where stack space is severely constrained (e.g. Microcontrollers).

Moving the recursion into a data structure

Wfm floodfill animation queue.gif
Four-way flood fill using a queue for storage
Wfm floodfill animation stack.gif
Four-way flood fill using a stack for storage

Moving the recursion into a data structure (either a stack or a queue) prevents a stack overflow. It is similar to the simple recursive solution, except that instead of making recursive calls, it pushes the nodes onto a stack or queue for consumption, with the choice of data structure affecting the proliferation pattern:

Flood-fill (node):   1. Set Q to the empty queue or stack.   2. Add node to the end of Q.   3. While Q is not empty:   4.   Set n equal to the first element of Q.   5.   Remove first element from Q.   6.   If n is Inside:          Set the n          Add the node to the west of n to the end of Q.          Add the node to the east of n to the end of Q.          Add the node to the north of n to the end of Q.          Add the node to the south of n to the end of Q.   7. Continue looping until Q is exhausted.   8. Return.

Further potential optimizations

Advantages

Disadvantages

Span filling

Scanline fill using a stack for storage Smiley fill.gif
Scanline fill using a stack for storage

It's possible to optimize things further by working primarily with spans, a row with constant y. The first published complete example works on the following basic principle. [1]

  1. Starting with a seed point, fill left and right. Keep track of the leftmost filled point lx and rightmost filled point rx. This defines the span.
  2. Scan from lx to rx above and below the seed point, searching for new seed points to continue with.

As an optimisation, the scan algorithm does not need restart from every seed point, but only those at the start of the next span. Using a stack explores spans depth first, whilst a queue explores spans breadth first.

fn fill(x, y):     if not Inside(x, y) then return     let s = new empty stack or queue     Add (x, y) to s     while s is not empty:         Remove an (x, y) from s         let lx = x         while Inside(lx - 1, y):             Set(lx - 1, y)             lx = lx - 1         while Inside(x, y):             Set(x, y)             x = x + 1       scan(lx, x - 1, y + 1, s)       scan(lx, x - 1, y - 1, s)  fn scan(lx, rx, y, s):     let span_added = false     for x in lx .. rx:         if not Inside(x, y):             span_added = false         else if not span_added:             Add (x, y) to sspan_added = true

Over time, the following optimizations were realized:

The final, combined-scan-and-fill span filler was then published in 1990. In pseudo-code form: [8]

fn fill(x, y):     if not Inside(x, y) then return     let s = new empty queue or stack     Add (x, x, y, 1) to s     Add (x, x, y - 1, -1) to s     while s is not empty:         Remove an (x1, x2, y, dy) from s         let x = x1         if Inside(x, y):             while Inside(x - 1, y):                 Set(x - 1, y)                 x = x - 1             if x < x1:                 Add (x, x1 - 1, y - dy, -dy) to s         while x1 <= x2:             while Inside(x1, y):                 Set(x1, y)                 x1 = x1 + 1             if x1 > x:                 Add (x, x1 - 1, y + dy, dy) to s             if x1 - 1 > x2:                 Add (x2 + 1, x1 - 1, y - dy, -dy) to sx1 = x1 + 1             while x1 < x2 and not Inside(x1, y):                 x1 = x1 + 1             x = x1

Advantages

  • 2–8x faster than the pixel-recursive algorithm.
  • Access pattern is cache and bitplane-friendly. [6]
  • Can draw a horizontal line rather than setting individual pixels. [6]

Disadvantages

  • Still visits pixels it has already filled. (For the popular algorithm, 3 scans of most pixels. For the final one, only doing extra scans of pixels where there are holes in the filled area.) [3]
  • Not suitable for pattern filling, as it requires pixel test results to change.

Adding pattern filling support

Two common ways to make the span and pixel-based algorithms support pattern filling are either to use a unique color as a plain fill and then replace that with a pattern or to keep track (in a 2d boolean array or as regions) of which pixels have been visited, using it to indicate pixels are no longer fillable. Inside must then return false for such visited pixels. [3]

Graph-theoretic filling

Some theorists applied explicit graph theory to the problem, treating spans of pixels, or aggregates of such, as nodes and studying their connectivity. The first published graph theory algorithm worked similarly to the span filling, above, but had a way to detect when it would duplicate filling of spans. [9] Unfortunately, it had bugs that made it not complete some fills. [10] A corrected algorithm was later published with a similar basis in graph theory; however, it alters the image as it goes along, to temporarily block off potential loops, complicating the programmatic interface. [10] A later published algorithm depended on the boundary being distinct from everything else in the image and so isn't suitable for most uses; [11] [3] it also requires an extra bit per pixel for bookkeeping. [3]

Advantages

Disadvantages

Walk-based filling (Fixed-memory method)

A method exists that uses essentially no memory for four-connected regions by pretending to be a painter trying to paint the region without painting themselves into a corner. This is also a method for solving mazes. The four pixels making the primary boundary are examined to see what action should be taken. The painter could find themselves in one of several conditions:

  1. All four boundary pixels are filled.
  2. Three of the boundary pixels are filled.
  3. Two of the boundary pixels are filled.
  4. One boundary pixel is filled.
  5. Zero boundary pixels are filled.

Where a path or boundary is to be followed, the right-hand rule is used. The painter follows the region by placing their right-hand on the wall (the boundary of the region) and progressing around the edge of the region without removing their hand.

For case #1, the painter paints (fills) the pixel the painter is standing upon and stops the algorithm.

For case #2, a path leading out of the area exists. Paint the pixel the painter is standing upon and move in the direction of the open path.

For case #3, the two boundary pixels define a path which, if we painted the current pixel, may block us from ever getting back to the other side of the path. We need a "mark" to define where we are and which direction we are heading to see if we ever get back to exactly the same pixel. If we already created such a "mark", then we preserve our previous mark and move to the next pixel following the right-hand rule.

A mark is used for the first 2-pixel boundary that is encountered to remember where the passage started and in what direction the painter was moving. If the mark is encountered again and the painter is traveling in the same direction, then the painter knows that it is safe to paint the square with the mark and to continue in the same direction. This is because (through some unknown path) the pixels on the other side of the mark can be reached and painted in the future. The mark is removed for future use.

If the painter encounters the mark but is going in a different direction, then some sort of loop has occurred, which caused the painter to return to the mark. This loop must be eliminated. The mark is picked up, and the painter then proceeds in the direction indicated previously by the mark using a left-hand rule for the boundary (similar to the right-hand rule but using the painter's left hand). This continues until an intersection is found (with three or more open boundary pixels). Still using the left-hand rule the painter now searches for a simple passage (made by two boundary pixels). Upon finding this two-pixel boundary path, that pixel is painted. This breaks the loop and allows the algorithm to continue.

For case #4, we need to check the opposite 8-connected corners to see whether they are filled or not. If either or both are filled, then this creates a many-path intersection and cannot be filled. If both are empty, then the current pixel can be painted and the painter can move following the right-hand rule.

The algorithm trades time for memory. For simple shapes it is very efficient. However, if the shape is complex with many features, the algorithm spends a large amount of time tracing the edges of the region trying to ensure that all can be painted.

A walking algorithm was published in 1994. [12]

Pseudocode

This is a pseudocode implementation of an optimal fixed-memory flood-fill algorithm written in structured English:

The variables
The algorithm
NOTE: All directions (front, back, left, right) are relative to cur-dir
set cur to starting pixel set cur-dir to default direction clear mark and mark2 (set values to null) set backtrack and findloop to false  while front-pixel is empty do     move forward end while  jump to START  MAIN LOOP:     move forward     if right-pixel is inside thenif backtrack is true and findloop is false and either front-pixel or left-pixel is inside then             set findloop to true         end if         turn right PAINT:         move forward     end if START:     setcount to number of non-diagonally adjacent pixels filled (front/back/left/right ONLY)     ifcountis not 4 thendo             turn right         while front-pixel is inside         do             turn left         while front-pixel is not inside     end ifswitchcount         case 1             if backtrack is true then                 set findloop to true             else if findloop is true thenif mark is null then                     restore mark                 end ifelse if front-left-pixel and back-left-pixel are both inside then                 clear mark                 set cur                 jump to PAINT             end if         end case         case 2             if back-pixel is not inside thenif front-left-pixel is inside then                     clear mark                     set cur                     jump to PAINT                 end ifelse if mark is not set then                 set mark to cur                 set mark-dir to cur-dir                 clear mark2                 set findloop and backtrack to false             elseif mark2 is not set thenif cur is at mark thenif cur-dir is the same as mark-dir then                             clear mark                             turn around                             set cur                             jump to PAINT                         else                             set backtrack to true                             set findloop to false                             set cur-dir to mark-dir                         end ifelse if findloop is true then                         set mark2 to cur                         set mark2-dir to cur-dir                     end ifelseif cur is at mark then                         set cur to mark2                         set cur-dir to mark2-dir                         clear mark and mark2                         set backtrack to false                         turn around                         set cur                         jump to PAINT                     else if cur at mark2 then                         set mark to cur                         set cur-dir and mark-dir to mark2-dir                         clear mark2                     end ifend ifend if         end case         case 3             clear mark             set cur             jump to PAINT         end case         case 4             set cur             done         end case     end switch end MAIN LOOP

Advantages

Disadvantages

Vector implementations

Version 0.46 of Inkscape includes a bucket fill tool, giving output similar to ordinary bitmap operations and indeed using one: the canvas is rendered, a flood fill operation is performed on the selected area and the result is then traced back to a path. It uses the concept of a boundary condition.

See also

Related Research Articles

<span class="mw-page-title-main">Painter's algorithm</span> Algorithm for visible surface determination in 3D graphics

The painter's algorithm is an algorithm for visible surface determination in 3D computer graphics that works on a polygon-by-polygon basis rather than a pixel-by-pixel, row by row, or area by area basis of other Hidden-Surface Removal algorithms. The painter's algorithm creates images by sorting the polygons within the image by their depth and placing each polygon in order from the farthest to the closest object.

<span class="mw-page-title-main">Scanline rendering</span> 3D computer graphics image rendering method

Scanline rendering is an algorithm for visible surface determination, in 3D computer graphics, that works on a row-by-row basis rather than a polygon-by-polygon or pixel-by-pixel basis. All of the polygons to be rendered are first sorted by the top y coordinate at which they first appear, then each row or scan line of the image is computed using the intersection of a scanline with the polygons on the front of the sorted list, while the sorted list is updated to discard no-longer-visible polygons as the active scan line is advanced down the picture.

Bresenham's line algorithm is a line drawing algorithm that determines the points of an n-dimensional raster that should be selected in order to form a close approximation to a straight line between two points. It is commonly used to draw line primitives in a bitmap image, as it uses only integer addition, subtraction, and bit shifting, all of which are very cheap operations in historically common computer architectures. It is an incremental error algorithm, and one of the earliest algorithms developed in the field of computer graphics. An extension to the original algorithm called the midpoint circle algorithm may be used for drawing circles.

<span class="mw-page-title-main">Breadth-first search</span> Algorithm to search the nodes of a graph

Breadth-first search (BFS) is an algorithm for searching a tree data structure for a node that satisfies a given property. It starts at the tree root and explores all nodes at the present depth prior to moving on to the nodes at the next depth level. Extra memory, usually a queue, is needed to keep track of the child nodes that were encountered but not yet explored.

<span class="mw-page-title-main">Line drawing algorithm</span> Methods of approximating line segments for pixel displays

In computer graphics, a line drawing algorithm is an algorithm for approximating a line segment on discrete graphical media, such as pixel-based displays and printers. On such media, line drawing requires an approximation. Basic algorithms rasterize lines in one color. A better representation with multiple color gradations requires an advanced process, spatial anti-aliasing.

<span class="mw-page-title-main">Xiaolin Wu's line algorithm</span> Line algorithm with antialiasing

Xiaolin Wu's line algorithm is an algorithm for line antialiasing.

<span class="mw-page-title-main">Graham scan</span> Algorithm for computing convex hulls in a set of points

Graham's scan is a method of finding the convex hull of a finite set of points in the plane with time complexity O(n log n). It is named after Ronald Graham, who published the original algorithm in 1972. The algorithm finds all vertices of the convex hull ordered along its boundary. It uses a stack to detect and remove concavities in the boundary efficiently.

<span class="mw-page-title-main">Ray casting</span> Methodological basis for 3D CAD/CAM solid modeling and image rendering

Ray casting is the methodological basis for 3D CAD/CAM solid modeling and image rendering. It is essentially the same as ray tracing for computer graphics where virtual light rays are "cast" or "traced" on their path from the focal point of a camera through each pixel in the camera sensor to determine what is visible along the ray in the 3D scene. The term "Ray Casting" was introduced by Scott Roth while at the General Motors Research Labs from 1978–1980. His paper, "Ray Casting for Modeling Solids", describes modeled solid objects by combining primitive solids, such as blocks and cylinders, using the set operators union (+), intersection (&), and difference (-). The general idea of using these binary operators for solid modeling is largely due to Voelcker and Requicha's geometric modelling group at the University of Rochester. See solid modeling for a broad overview of solid modeling methods. This figure on the right shows a U-Joint modeled from cylinders and blocks in a binary tree using Roth's ray casting system in 1979.

<span class="mw-page-title-main">Hidden-surface determination</span> Visibility in 3D computer graphics

In 3D computer graphics, hidden-surface determination is the process of identifying what surfaces and parts of surfaces can be seen from a particular viewing angle. A hidden-surface determination algorithm is a solution to the visibility problem, which was one of the first major problems in the field of 3D computer graphics. The process of hidden-surface determination is sometimes called hiding, and such an algorithm is sometimes called a hider. When referring to line rendering it is known as hidden-line removal. Hidden-surface determination is necessary to render a scene correctly, so that one may not view features hidden behind the model itself, allowing only the naturally viewable portion of the graphic to be visible.

Java 2D is an API for drawing two-dimensional graphics using the Java programming language. Every Java 2D drawing operation can ultimately be treated as filling a shape using a paint and compositing the result onto the screen.

<span class="mw-page-title-main">Quadtree</span> Tree data structure in which each internal node has exactly four children, to partition a 2D area

A quadtree is a tree data structure in which each internal node has exactly four children. Quadtrees are the two-dimensional analog of octrees and are most often used to partition a two-dimensional space by recursively subdividing it into four quadrants or regions. The data associated with a leaf cell varies by application, but the leaf cell represents a "unit of interesting spatial information".

In computer science, tree traversal is a form of graph traversal and refers to the process of visiting each node in a tree data structure, exactly once. Such traversals are classified by the order in which the nodes are visited. The following algorithms are described for a binary tree, but they may be generalized to other trees as well.

In computer graphics, the Liang–Barsky algorithm is a line clipping algorithm. The Liang–Barsky algorithm uses the parametric equation of a line and inequalities describing the range of the clipping window to determine the intersections between the line and the clip window. With these intersections it knows which portion of the line should be drawn. So this algorithm is significantly more efficient than Cohen–Sutherland. The idea of the Liang–Barsky clipping algorithm is to do as much testing as possible before computing line intersections.

In computer graphics, image tracing, raster-to-vector conversion or raster vectorization is the conversion of raster graphics into vector graphics.

<span class="mw-page-title-main">Box blur</span> Graphic-art effect

A box blur is a spatial domain linear filter in which each pixel in the resulting image has a value equal to the average value of its neighboring pixels in the input image. It is a form of low-pass ("blurring") filter. A 3 by 3 box blur can be written as matrix

In computer science, graph traversal refers to the process of visiting each vertex in a graph. Such traversals are classified by the order in which the vertices are visited. Tree traversal is a special case of graph traversal.

Connected-component labeling (CCL), connected-component analysis (CCA), blob extraction, region labeling, blob discovery, or region extraction is an algorithmic application of graph theory, where subsets of connected components are uniquely labeled based on a given heuristic. Connected-component labeling is not to be confused with segmentation.

<span class="mw-page-title-main">Watershed (image processing)</span> Transformation defined on a grayscale image

In the study of image processing, a watershed is a transformation defined on a grayscale image. The name refers metaphorically to a geological watershed, or drainage divide, which separates adjacent drainage basins. The watershed transformation treats the image it operates upon like a topographic map, with the brightness of each point representing its height, and finds the lines that run along the tops of ridges.

In computer graphics, a digital differential analyzer (DDA) is hardware or software used for interpolation of variables over an interval between start and end point. DDAs are used for rasterization of lines, triangles and polygons. They can be extended to non linear functions, such as perspective correct texture mapping, quadratic curves, and traversing voxels.

<span class="mw-page-title-main">Maze-solving algorithm</span> Automated method for solving mazes

A maze-solving algorithm is an automated method for solving a maze. The random mouse, wall follower, Pledge, and Trémaux's algorithms are designed to be used inside the maze by a traveler with no prior knowledge of the maze, whereas the dead-end filling and shortest path algorithms are designed to be used by a person or computer program that can see the whole maze at once.

References

  1. 1 2 3 Smith, Alvy Ray (1979). Tint Fill. SIGGRAPH '79: Proceedings of the 6th annual conference on Computer graphics and interactive techniques. pp. 276–283. doi:10.1145/800249.807456.
  2. 1 2 Ackland, Bryan D; Weste, Neil H (1981). The edge flag algorithm — A fill method for raster scan displays. IEEE Transactions on Computers (Volume: C-30, Issue: 1). pp. 41–48. doi:10.1109/TC.1981.6312155.
  3. 1 2 3 4 5 6 7 8 9 10 Fishkin, Kenneth P; Barsky, Brian A (1985). An Analysis and Algorithm for Filling Propagation. Computer-Generated Images: The State of the Art Proceedings of Graphics Interface ’85. pp. 56–76. doi:10.1007/978-4-431-68033-8_6.
  4. Newman, William M; Sproull, Robert Fletcher (1979). Principles of Interactive Computer Graphics (2nd ed.). McGraw-Hill. p. 253. ISBN   978-0-07-046338-7.
  5. Pavlidis, Theo (1982). Algorithms for Graphics and Image Processing. Springer-Verlag. p. 181. ISBN   978-3-642-93210-6.
  6. 1 2 3 4 5 6 7 8 9 Levoy, Marc (1982). Area Flooding Algorithms. SIGGRAPH 1981 Two-Dimensional Computer Animation course notes.
  7. Foley, J D; van Dam, A; Feiner, S K; Hughes, S K (1990). Computer Graphics: Principles and Practice (2nd ed.). Addison–Wesley. pp. 979–982. ISBN   978-0-201-84840-3.
  8. Heckbert, Paul S (1990). "IV.10: A Seed Fill Algorithm". In Glassner, Andrew S (ed.). Graphics Gems. Academic Press. pp. 275–277. ISBN   0122861663.
  9. 1 2 Lieberman, Henry (1978). How to Color in a Coloring Book. SIGGRAPH '78: Proceedings of the 5th annual conference on Computer graphics and interactive techniques. pp. 111–116. doi:10.1145/800248.807380.
  10. 1 2 3 Shani, Uri (1980). Filling regions in binary raster images: A graph-theoretic approach. SIGGRAPH '80: Proceedings of the 7th annual conference on Computer graphics and interactive techniques. pp. 321–327. doi:10.1145/800250.807511.
  11. 1 2 Pavlidis, Theo (1981). Contour Filling in Raster Graphics. SIGGRAPH '81: Proceedings of the 8th annual conference on Computer graphics and interactive techniques. pp. 29–36. doi:10.1145/800224.806786.
  12. Henrich, Dominik (1994). Space-efficient region filling in raster graphics. The Visual Computer. pp. 205–215. doi:10.1007/BF01901287.