はじめに
画像処理において、重なり合ったオブジェクトを個別に識別することは重要な課題です。scikit-imageライブラリのwatershedアルゴリズムは、この問題を効果的に解決するためのツールを提供しています。本記事では、watershedセグメンテーションの基本概念から実装方法まで詳しく解説します。
コード

解説
モジュールのインポート
データの生成
重なり合った3つの円の画像を生成します。
np.indices((60, 60))を使用して、各ピクセルの座標を要素とする配列を生成します。
mask_circle1 = (x – x1)**2 + (y – y1)2 < r12 という式で、座標(x1, y1)を中心とする半径r1の円内部がTrueとなるブール配列を作成します。
np.logical_or(mask_circle1, mask_circle2)で配列の各要素に対して論理和演算を行い、2つの円が合体した形状を作ります。
さらに、np.logical_or(image, mask_circle3)を適用して3つの円を合体させます。この結果は以下のような画像になります。

ndi.distance_transform_edt(image)は画像内の各ピクセルから背景までの距離を計算します。円の中心部ほど背景からの距離が大きくなるため、距離マップ上ではその値も大きくなります。
局所的極大値を求める
局所的極大値を求めるskimage.feature peak_local_maxについては下記で解説しました。

local_maxiは極大値の部分がTrueとなる配列です。この配列のsumが3になることから、3つの円の極大値を正しく検出できていることがわかります。
極大値のラベリング
ndi.labelを使用して局所的極大値をラベリングします。markersでは極大値のTrue部分が1、2、3とラベル付けされるため、合計値(sum)は6になります。
watershedの適用
-distanceとすることで極大値を極小値として反転させます。この-distanceを3Dグラフで表示すると以下のような形状になります。

これが、watershedアルゴリズムの基本原理です。画像内の「窪み」に水が徐々に溜まっていく過程をシミュレーションし、オブジェクトを分離します。実装では、markersをマーカーとして指定し、mask=imageパラメータを設定することで、効果的にセグメント化された結果配列が得られます。
画像の表示
左に元画像、中央に背景からの距離を負に変換した画像、右にwatershedでセグメント化した結果を示しています。
コードをダウンロード(.pyファイル) コードをダウンロード(.ipynbファイル)まとめ
scikit-imageのwatershedアルゴリズムは、重なり合ったオブジェクトを効果的に分離するための強力なツールです。適切なマーカー設定と前処理を組み合わせることで、様々な画像処理タスクに応用できます。特に物体検出や画像セグメンテーションのパイプラインの一部として、高い実用性を持っています。
参考

コメント