塗りつぶし#

塗りつぶしは、初期シード点との類似性に基づいて、画像内の隣接する値を識別および/または変更するアルゴリズムです[1]。概念的なアナロジーは、多くのグラフィックエディタにある「ペイントバケット」ツールです。

基本的な例#

まず、チェッカーボードの正方形を白からミッドグレーに変更する基本的な例を示します。

import numpy as np
import matplotlib.pyplot as plt
from skimage import data, filters, color, morphology
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, cmap=plt.cm.gray)
ax[0].set_title('Original')

ax[1].imshow(filled_checkers, cmap=plt.cm.gray)
ax[1].plot(76, 76, 'wo')  # seed point
ax[1].set_title('After flood fill')

plt.show()
Original, After flood fill

高度な例#

標準の塗りつぶしでは、隣接ピクセルが厳密に等しい必要があるため、カラーグラデーションとノイズのある現実世界の画像では使用が制限されます。 toleranceキーワード引数は、初期値を中心とした許容範囲を広げ、現実世界の画像で使用できるようにします。

ここでは、カメラマンで少し実験してみましょう。 まず、彼のコートを暗から明に変えます。

cameraman = data.camera()

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

ax[0].imshow(cameraman, cmap=plt.cm.gray)
ax[0].set_title('Original')
ax[0].axis('off')

ax[1].imshow(light_coat, cmap=plt.cm.gray)
ax[1].plot(150, 155, 'ro')  # seed point
ax[1].set_title('After flood fill')
ax[1].axis('off')

plt.show()
Original, After flood fill

カメラマンのコートはさまざまなグレースケールです。 シード値に近いシェードと一致するコートの部分のみが変更されます。

許容範囲の実験#

許容範囲パラメータの動作をより直感的に理解するために、左上隅のシード点でパラメータを progressivement 増やす一連の画像を次に示します。

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, cmap=plt.cm.gray)
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], cmap=plt.cm.gray)
    ax[m, n].set_title(f'Tolerance {5 + 20 * i}')
    ax[m, n].axis('off')
    ax[m, n].plot(0, 0, 'bo')  # seed point

fig.tight_layout()
plt.show()
Original, Tolerance 5, Tolerance 25, Tolerance 45, Tolerance 65, Tolerance 85, Tolerance 105, Tolerance 125, Tolerance 145

マスクとしての塗りつぶし#

姉妹関数であるfloodは、画像自体を変更するのではなく、塗りつぶしを識別するマスクを返します。 これは、セグメンテーションの目的とより高度な分析パイプラインに役立ちます。

ここでは、猫の鼻をセグメント化します。 ただし、マルチチャネル画像はflood[_fill]ではサポートされていません。 代わりに、赤チャネルにSobelフィルターを適用してエッジを強調し、許容範囲で鼻を塗りつぶします。

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[0].imshow(cat)
ax[0].set_title('Original')
ax[0].axis('off')

ax[1].imshow(cat_sobel)
ax[1].set_title('Sobel filtered')
ax[1].axis('off')

ax[2].imshow(cat)
ax[2].imshow(cat_nose, cmap=plt.cm.gray, alpha=0.3)
ax[2].plot(265, 240, 'wo')  # seed point
ax[2].set_title('Nose segmented with `flood`')
ax[2].axis('off')

fig.tight_layout()
plt.show()
Original, Sobel filtered, Nose segmented with `flood`

HSV空間での塗りつぶしとマスクの後処理#

塗りつぶしは単一チャネル画像で動作するため、ここでは画像をHSV(色相彩度値)空間に変換して、類似した色相のピクセルを塗りつぶします。

この例では、skimage.segmentation.flood()によって返されるバイナリマスクを、skimage.morphologyの関数のおかげで後処理できることも示しています。

img = data.astronaut()
img_hsv = color.rgb2hsv(img)
img_hsv_copy = np.copy(img_hsv)

# flood function returns a mask of flooded pixels
mask = flood(img_hsv[..., 0], (313, 160), tolerance=0.016)
# Set pixels of mask to new value for hue channel
img_hsv[mask, 0] = 0.5
# Post-processing in order to improve the result
# Remove white pixels from flag, using saturation channel
mask_postprocessed = np.logical_and(mask, img_hsv_copy[..., 1] > 0.4)
# Remove thin structures with binary opening
mask_postprocessed = morphology.binary_opening(mask_postprocessed, np.ones((3, 3)))
# Fill small holes with binary closing
mask_postprocessed = morphology.binary_closing(mask_postprocessed, morphology.disk(20))
img_hsv_copy[mask_postprocessed, 0] = 0.5

fig, ax = plt.subplots(1, 2, figsize=(8, 4))
ax[0].imshow(color.hsv2rgb(img_hsv))
ax[0].axis('off')
ax[0].set_title('After flood fill')
ax[1].imshow(color.hsv2rgb(img_hsv_copy))
ax[1].axis('off')
ax[1].set_title('After flood fill and post-processing')

fig.tight_layout()
plt.show()
After flood fill, After flood fill and post-processing

スクリプトの合計実行時間:(0分12.429秒)

Sphinx-Galleryによって生成されたギャラリー