Docs for 0.15.dev0
All versions

Flood Fill

Flood fill is an algorithm to identify and/or change adjacent values in an image based on their similarity to an initial seed point [1]. The conceptual analogy is the ‘paint bucket’ tool in many graphic editors.


Basic example

First, a basic example where we will change a checkerboard square from white to mid-gray.

import numpy as np
import matplotlib.pyplot as plt
from skimage import data, filters
from skimage.segmentation import flood, flood_fill

checkers = data.checkerboard()

# Fill a square near the middle with value 127, starting at index (76, 76)
filled_checkers = flood_fill(checkers, (76, 76), 127)

fig, ax = plt.subplots(ncols=2, figsize=(10, 5))

ax[0].imshow(checkers,, interpolation='none')

ax[1].imshow(filled_checkers,, interpolation='none')
ax[1].plot(76, 76, 'wo')  # seed point
ax[1].set_title('After flood fill')

Advanced example

Because standard flood filling requires the neighbors to be strictly equal, its use is limited on real-world images with color gradients and noise. The tolerance keyword argument widens the permitted range about the initial value, allowing use on real-world images.

Here we will experiment a bit on the cameraman. First, turning his coat from dark to light.

cameraman =

# Change the cameraman's coat from dark to light (255).  The seed point is
# chosen as (200, 100),
light_coat = flood_fill(cameraman, (200, 100), 255, tolerance=10)
fig, ax = plt.subplots(ncols=2, figsize=(10, 5))


ax[1].plot(100, 200, 'wo')  # seed point
ax[1].set_title('After flood fill')

Because the cameraman is dark haired it also changed his hair, as well as parts of the tripod.

Experimentation with tolerance

To get a better intuitive understanding of how the tolerance parameter works, here is a set of images progressively increasing the parameter with seed point in the upper left corner.

output = []

for i in range(8):
    tol = 5 + 20*i
    output.append(flood_fill(cameraman, (0, 0), 255, tolerance=tol))

# Initialize plot and place original image
fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(12, 12))
ax[0, 0].imshow(cameraman,
ax[0, 0].set_title('Original')
ax[0, 0].axis('off')

# Plot all eight different tolerances for comparison.
for i in range(8):
    m, n = np.unravel_index(i+1, (3, 3))
    ax[m, n].imshow(output[i],
    ax[m, n].set_title('Tolerance {0}'.format(str(5 + 20*i)))
    ax[m, n].axis('off')
    ax[m, n].plot(0, 0, 'bo')  # seed point


Flood as mask

A sister function, flood, is available which returns a mask identifying the flood rather than modifying the image itself. This is useful for segmentation purposes and more advanced analysis pipelines.

Here we segment the nose of a cat. However, multi-channel images are not supported by flood[_fill]. Instead we Sobel filter the red channel to enhance edges, then flood the nose with a tolerance.

cat = data.chelsea()
cat_sobel = filters.sobel(cat[..., 0])
cat_nose = flood(cat_sobel, (240, 265), tolerance=0.03)

fig, ax = plt.subplots(nrows=3, figsize=(10, 20))


ax[1].set_title('Sobel filtered')

ax[2].imshow(cat_nose,, alpha=0.3)
ax[2].plot(265, 240, 'wo')  # seed point
ax[2].set_title('Nose segmented with `flood`')


Total running time of the script: ( 0 minutes 0.805 seconds)

Gallery generated by Sphinx-Gallery