エッジベースセグメンテーションと領域ベースセグメンテーションの比較#

この例では、背景からオブジェクトをセグメント化する方法を示します。skimage.datacoins画像を使用します。この画像には、暗い背景に対して輪郭が描かれたいくつかのコインが表示されています。

import numpy as np
import matplotlib.pyplot as plt

from skimage import data
from skimage.exposure import histogram

coins = data.coins()
hist, hist_centers = histogram(coins)

fig, axes = plt.subplots(1, 2, figsize=(8, 3))
axes[0].imshow(coins, cmap=plt.cm.gray)
axes[0].set_axis_off()
axes[1].plot(hist_centers, hist, lw=2)
axes[1].set_title('histogram of gray values')
histogram of gray values
Text(0.5, 1.0, 'histogram of gray values')

閾値処理#

コインをセグメント化する簡単な方法は、グレースケール値のヒストグラムに基づいて閾値を選択することです。しかし、この画像に対して閾値処理を行うと、コインの重要な部分が欠落したり、背景の一部がコインとマージされたりする2値画像が生成されます。

fig, axes = plt.subplots(1, 2, figsize=(8, 3), sharey=True)

axes[0].imshow(coins > 100, cmap=plt.cm.gray)
axes[0].set_title('coins > 100')

axes[1].imshow(coins > 150, cmap=plt.cm.gray)
axes[1].set_title('coins > 150')

for a in axes:
    a.set_axis_off()

fig.tight_layout()
coins > 100, coins > 150

エッジベースセグメンテーション#

次に、エッジベースセグメンテーションを使用してコインの輪郭を描き出してみます。そのためには、まずCannyエッジ検出器を使用して特徴のエッジを取得します。

from skimage.feature import canny

edges = canny(coins)

fig, ax = plt.subplots(figsize=(4, 3))
ax.imshow(edges, cmap=plt.cm.gray)
ax.set_title('Canny detector')
ax.set_axis_off()
Canny detector

これらの輪郭は、数学的形態論を用いて塗りつぶされます。

from scipy import ndimage as ndi

fill_coins = ndi.binary_fill_holes(edges)

fig, ax = plt.subplots(figsize=(4, 3))
ax.imshow(fill_coins, cmap=plt.cm.gray)
ax.set_title('filling the holes')
ax.set_axis_off()
filling the holes

小さな偽のオブジェクトは、有効なオブジェクトの最小サイズを設定することで簡単に除去できます。

from skimage import morphology

coins_cleaned = morphology.remove_small_objects(fill_coins, 21)

fig, ax = plt.subplots(figsize=(4, 3))
ax.imshow(coins_cleaned, cmap=plt.cm.gray)
ax.set_title('removing small objects')
ax.set_axis_off()
removing small objects

しかし、完全に閉じられていない輪郭は正しく塗りつぶされません(上の塗りつぶされていないコインのように)、この方法はそれほど堅牢ではありません。

領域ベースセグメンテーション#

そこで、watershed変換を用いた領域ベースの方法を試してみます。まず、画像のSobel勾配を用いて標高マップを求めます。

from skimage.filters import sobel

elevation_map = sobel(coins)

fig, ax = plt.subplots(figsize=(4, 3))
ax.imshow(elevation_map, cmap=plt.cm.gray)
ax.set_title('elevation map')
ax.set_axis_off()
elevation map

次に、グレースケール値のヒストグラムの極端な部分に基づいて、背景とコインのマーカーを見つけます。

markers

最後に、watershed変換を使用して、上記で決定されたマーカーから始めて標高マップの領域を塗りつぶします。

segmentation

この最後の手法はさらに効果的で、コインを個別にセグメント化およびラベリングできます。

from skimage.color import label2rgb

segmentation_coins = ndi.binary_fill_holes(segmentation_coins - 1)
labeled_coins, _ = ndi.label(segmentation_coins)
image_label_overlay = label2rgb(labeled_coins, image=coins, bg_label=0)

fig, axes = plt.subplots(1, 2, figsize=(8, 3), sharey=True)
axes[0].imshow(coins, cmap=plt.cm.gray)
axes[0].contour(segmentation_coins, [0.5], linewidths=1.2, colors='y')
axes[1].imshow(image_label_overlay)

for a in axes:
    a.set_axis_off()

fig.tight_layout()

plt.show()
plot coins segmentation

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

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