「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Python で正規化カット (NCut) を使用した教師なし画像セグメンテーションのガイド

Python で正規化カット (NCut) を使用した教師なし画像セグメンテーションのガイド

2024 年 11 月 8 日に公開
ブラウズ:554

A Guide to Unsupervised Image Segmentation using Normalized Cuts (NCut) in Python

導入

画像セグメンテーションは視覚データの理解と分析において重要な役割を果たしており、正規化カット (NCut) はグラフベースのセグメンテーションに広く使用されている方法です。この記事では、スーパーピクセルを使用したセグメンテーション品質の向上に重点を置き、Microsoft Research のデータセットを使用して、Python で教師なし画像セグメンテーションに NCut を適用する方法を検討します。
データセットの概要
このタスクに使用されるデータセットは、MSRC オブジェクト カテゴリ画像データベースのリンクからダウンロードできます。このデータセットには、元の画像と、その 9 つのオブジェクト クラスへのセマンティック セグメンテーションが含まれています (「_GT」で終わる画像ファイルで示されます)。これらの画像はテーマ別のサブセットにグループ化されており、ファイル名の最初の数字はクラス サブセットを表します。このデータセットは、セグメンテーション タスクを実験するのに最適です。

問題提起

NCut アルゴリズムを使用して、データセット内の画像に対して画像セグメンテーションを実行します。ピクセルレベルでのセグメンテーションは計算コストが高く、多くの場合ノイズが発生します。これを克服するために、SLIC (単純線形反復クラスタリング) を使用してスーパーピクセルを生成します。これにより、類似したピクセルがグループ化され、問題のサイズが小さくなります。セグメンテーションの精度を評価するために、さまざまな指標 (例: Intersection over Union、SSIM、Rand Index) を使用できます。

実装

1.必要なライブラリをインストールする
画像処理には skimage を、数値計算には numpy を、視覚化には matplotlib を使用します。

pip install numpy matplotlib
pip install scikit-image==0.24.0
**2. Load and Preprocess the Dataset**

データセットをダウンロードして抽出した後、画像とグラウンド トゥルース セグメンテーションをロードします:

wget http://download.microsoft.com/download/A/1/1/A116CD80-5B79-407E-B5CE-3D5C6ED8B0D5/msrc_objcategimagedatabase_v1.zip -O msrc_objcategimagedatabase_v1.zip
unzip msrc_objcategimagedatabase_v1.zip
rm msrc_objcategimagedatabase_v1.zip

これでコーディングを開始する準備が整いました。

from skimage import io, segmentation, color, measure
from skimage import graph
import numpy as np
import matplotlib.pyplot as plt

# Load the image and its ground truth
image = io.imread('/content/MSRC_ObjCategImageDatabase_v1/1_16_s.bmp')
ground_truth = io.imread('/content/MSRC_ObjCategImageDatabase_v1/1_16_s_GT.bmp')

# show images side by side
fig, ax = plt.subplots(1, 2, figsize=(10, 5))
ax[0].imshow(image)
ax[0].set_title('Image')
ax[1].imshow(ground_truth)
ax[1].set_title('Ground Truth')
plt.show()

3. SLIC を使用してスーパーピクセルを生成し、領域隣接グラフを作成します

NCut を適用する前に、SLIC アルゴリズムを使用してスーパーピクセルを計算します。生成されたスーパーピクセルを使用して、平均色の類似性に基づいて領域隣接グラフ (RAG) を構築します。

from skimage.util import img_as_ubyte, img_as_float, img_as_uint, img_as_float64

compactness=30 
n_segments=100 
labels = segmentation.slic(image, compactness=compactness, n_segments=n_segments, enforce_connectivity=True)
image_with_boundaries = segmentation.mark_boundaries(image, labels, color=(0, 0, 0))
image_with_boundaries = img_as_ubyte(image_with_boundaries)
pixel_labels = color.label2rgb(labels, image_with_boundaries, kind='avg', bg_label=0

コンパクトネスは、スーパーピクセルを形成する際のピクセルの色の類似性と空間的近接性の間のバランスを制御します。これは、スーパーピクセルを色別により均一にグループ化することと比較して、スーパーピクセルをコンパクトに(空間的に近くに)保つことにどの程度重点を置くかを決定します。
より高い値: コンパクトネスの値が高いほど、アルゴリズムは色の類似性をあまり重視せず、空間的にタイトでサイズが均一なスーパーピクセルの作成を優先します。これにより、スーパーピクセルがエッジやカラー グラデーションの影響を受けにくくなる可能性があります。
低い値: コンパクトネスの値が低いほど、色の違いをより正確に考慮するために、スーパーピクセルの空間サイズをより多く変化させることができます。これにより、通常、画像内のオブジェクトの境界をより厳密にたどるスーパーピクセルが生成されます。

n_segments は、SLIC アルゴリズムが画像内に生成しようとするスーパーピクセル (またはセグメント) の数を制御します。基本的に、セグメンテーションの解像度を設定します。
値が大きい: n_segments 値が大きいほど、より多くのスーパーピクセルが作成されます。つまり、各スーパーピクセルが小さくなり、セグメンテーションがより細かくなります。これは、画像に複雑なテクスチャや小さなオブジェクトが含まれている場合に便利です。
低い値: n_segments の値が低いほど、より少ない、より大きなスーパーピクセルが生成されます。これは、画像を粗くセグメンテーションして、より大きな領域を単一のスーパーピクセルにグループ化する場合に便利です。

4.正規化カット (NCut) を適用し、結果を視覚化する

# using the labels found with the superpixeled image
# compute the Region Adjacency Graph using mean colors
g = graph.rag_mean_color(image, labels, mode='similarity')

# perform Normalized Graph cut on the Region Adjacency Graph
labels2 = graph.cut_normalized(labels, g)
segmented_image = color.label2rgb(labels2, image, kind='avg')
f, axarr = plt.subplots(nrows=1, ncols=4, figsize=(25, 20))

axarr[0].imshow(image)
axarr[0].set_title("Original")

#plot boundaries
axarr[1].imshow(image_with_boundaries)
axarr[1].set_title("Superpixels Boundaries")

#plot labels
axarr[2].imshow(pixel_labels)
axarr[2].set_title('Superpixel Labels')

#compute segmentation
axarr[3].imshow(segmented_image)
axarr[3].set_title('Segmented image (normalized cut)')

5.評価指標
教師なしセグメンテーションにおける主な課題は、NCut が画像内のクラスの正確な数を知らないことです。 NCut によって検出されたセグメントの数は、実際のグラウンド トゥルース領域の数を超える場合があります。その結果、セグメンテーションの品質を評価するための堅牢な指標が必要になります。

Intersection over Union (IoU) は、特にコンピューター ビジョンでセグメンテーション タスクを評価するために広く使用されているメトリックです。これは、予測されたセグメント化された領域とグランド トゥルース領域の間の重複を測定します。具体的には、IoU は、予測されたセグメンテーションとグランド トゥルースの間の重複領域の、結合領域に対する比率を計算します。

構造類似性指数 (SSIM) は、輝度、コントラスト、構造の点で 2 つの画像を比較することによって、画像の知覚品質を評価するために使用される指標です。

これらのメトリクスを適用するには、予測とグラウンド トゥルース画像が同じラベルを持つ必要があります。ラベルを計算するために、地面と予測でマスクを計算し、画像上で見つかった各色に ID を割り当てます
ただし、NCut を使用したセグメンテーションでは、グラウンド トゥルースよりも多くの領域が見つかる可能性があり、精度が低下します。

def compute_mask(image):
  color_dict = {}

  # Get the shape of the image
  height,width,_ = image.shape

  # Create an empty array for labels
  labels = np.zeros((height,width),dtype=int)
  id=0
  # Loop over each pixel
  for i in range(height):
      for j in range(width):
          # Get the color of the pixel
          color = tuple(image[i,j])
          # Check if it is in the dictionary
          if color in color_dict:
              # Assign the label from the dictionary
              labels[i,j] = color_dict[color]
          else:
              color_dict[color]=id
              labels[i,j] = id
              id =1

  return(labels)
def show_img(prediction, groundtruth):
  f, axarr = plt.subplots(nrows=1, ncols=2, figsize=(15, 10))

  axarr[0].imshow(groundtruth)
  axarr[0].set_title("groundtruth")
  axarr[1].imshow(prediction)
  axarr[1].set_title(f"prediction")
prediction_mask = compute_mask(segmented_image)
groundtruth_mask = compute_mask(ground_truth)

#usign the original image as baseline to convert from labels to color
prediction_img = color.label2rgb(prediction_mask, image, kind='avg', bg_label=0)
groundtruth_img = color.label2rgb(groundtruth_mask, image, kind='avg', bg_label=0)

show_img(prediction_img, groundtruth_img)

次に、精度スコアを計算します

from sklearn.metrics import jaccard_score
from skimage.metrics import structural_similarity as ssim

ssim_score = ssim(prediction_img, groundtruth_img, channel_axis=2)
print(f"SSIM SCORE: {ssim_score}")

jac = jaccard_score(y_true=np.asarray(groundtruth_mask).flatten(),
                        y_pred=np.asarray(prediction_mask).flatten(),
                        average = None)

# compute mean IoU score across all classes
mean_iou = np.mean(jac)
print(f"Mean IoU: {mean_iou}")

結論

正規化カットは教師なし画像セグメンテーションの強力な方法ですが、過剰なセグメンテーションやパラメータの調整などの課題が伴います。スーパーピクセルを組み込み、適切なメトリクスを使用してパフォーマンスを評価することにより、NCut は複雑な画像を効果的にセグメント化できます。 IoU および Rand Index メトリクスは、セグメンテーションの品質に関する有意義な洞察を提供しますが、マルチクラス シナリオを効果的に処理するにはさらに改良する必要があります。
最後に、完全な例が私のノートブックにあります。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/sopralapanca/a-guide-to-unsupervised-image-segmentation-using-normalized-cuts-ncut-in-python-13pk?1 侵害がある場合は、 Study_golang@163 .comdelete に連絡してください
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3