Maison  >  Article  >  développement back-end  >  Un guide sur la segmentation d'images non supervisée à l'aide de coupes normalisées (NCut) en Python

Un guide sur la segmentation d'images non supervisée à l'aide de coupes normalisées (NCut) en Python

Barbara Streisand
Barbara Streisandoriginal
2024-09-24 06:20:15470parcourir

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

Introduction

La segmentation d'images joue un rôle essentiel dans la compréhension et l'analyse des données visuelles, et les coupes normalisées (NCut) sont une méthode largement utilisée pour la segmentation basée sur des graphiques. Dans cet article, nous explorerons comment appliquer NCut pour la segmentation d'images non supervisée en Python à l'aide d'un ensemble de données de Microsoft Research, en mettant l'accent sur l'amélioration de la qualité de la segmentation à l'aide de superpixels.
Aperçu de l'ensemble de données
L'ensemble de données utilisé pour cette tâche peut être téléchargé à partir du lien suivant : MSRC Object Category Image Database. Cet ensemble de données contient des images originales ainsi que leur segmentation sémantique en neuf classes d'objets (indiquées par des fichiers images se terminant par « _GT »). Ces images sont regroupées en sous-ensembles thématiques, où le premier numéro du nom du fichier fait référence à un sous-ensemble de classe. Cet ensemble de données est parfait pour expérimenter des tâches de segmentation.

Énoncé du problème

Nous effectuons une segmentation d'image sur une image de l'ensemble de données à l'aide de l'algorithme NCut. La segmentation au niveau des pixels est coûteuse en calcul et souvent bruyante. Pour surmonter ce problème, nous utilisons SLIC (Simple Linear Iterative Clustering) pour générer des superpixels, qui regroupent les pixels similaires et réduisent la taille du problème. Pour évaluer l'exactitude de la segmentation, différentes métriques (par exemple, Intersection over Union, SSIM, Rand Index) peuvent être utilisées.

Mise en œuvre

1. Installer les bibliothèques requises
Nous utilisons skimage pour le traitement des images, numpy pour les calculs numériques et matplotlib pour la visualisation.

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

Après avoir téléchargé et extrait l'ensemble de données, chargez les images et la segmentation de la vérité terrain :

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

Nous sommes maintenant prêts à commencer à coder.

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. Générez des superpixels à l'aide de SLIC et créez un graphique de contiguïté de région

Nous utilisons l'algorithme SLIC pour calculer les superpixels avant d'appliquer NCut. À l'aide des superpixels générés, nous construisons un graphique de contiguïté de région (RAG) basé sur la similarité moyenne des couleurs :

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
La

compacité contrôle l'équilibre entre la similarité des couleurs et la proximité spatiale des pixels lors de la formation des superpixels. Il détermine dans quelle mesure l'accent est mis sur le maintien des superpixels compacts (plus proches en termes spatiaux) plutôt que sur la garantie qu'ils sont regroupés de manière plus homogène par couleur.
Valeurs plus élevées : une valeur de compacité plus élevée amène l'algorithme à donner la priorité à la création de superpixels spatialement restreints et de taille uniforme, avec moins d'attention à la similarité des couleurs. Cela pourrait donner des superpixels moins sensibles aux bords ou aux dégradés de couleurs.
Valeurs inférieures : Une valeur de compacité inférieure permet aux superpixels de varier davantage en taille spatiale afin de respecter plus précisément les différences de couleur. Cela se traduit généralement par des superpixels qui suivent de plus près les limites des objets dans l'image.

n_segments contrôle le nombre de superpixels (ou segments) que l'algorithme SLIC tente de générer dans l'image. Essentiellement, il définit la résolution de la segmentation.
Valeurs plus élevées : une valeur n_segments plus élevée crée plus de superpixels, ce qui signifie que chaque superpixel sera plus petit et que la segmentation sera plus fine. Cela peut être utile lorsque l'image comporte des textures complexes ou de petits objets.
Valeurs inférieures : une valeur n_segments inférieure produit des superpixels moins nombreux et plus grands. Ceci est utile lorsque vous souhaitez une segmentation grossière de l'image, regroupant des zones plus grandes en superpixels uniques.

4. Appliquez des coupes normalisées (NCut) et visualisez le résultat

# 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. Métriques d'évaluation
Le principal défi de la segmentation non supervisée est que NCut ne connaît pas le nombre exact de classes dans l'image. Le nombre de segments trouvés par NCut peut dépasser le nombre réel de régions de vérité terrain. Par conséquent, nous avons besoin de mesures robustes pour évaluer la qualité de la segmentation.

Intersection over Union (IoU) est une métrique largement utilisée pour évaluer les tâches de segmentation, notamment en vision par ordinateur. Il mesure le chevauchement entre les régions segmentées prédites et les régions de vérité terrain. Plus précisément, IoU calcule le rapport entre la zone de chevauchement entre la segmentation prédite et la vérité terrain et la zone de leur union.

L'indice de similarité structurelle (SSIM) est une métrique utilisée pour évaluer la qualité perçue d'une image en comparant deux images en termes de luminance, de contraste et de structure.

To apply these metrics we need that the prediction and the ground truth image have the same labels. To compute the labels we compute a mask on the ground and on the prediction assign an ID to each color found on the image
Segmentation using NCut however may find more regions than ground truth, this will lower the accuracy.

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)

Now we compute the accuracy scores

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}")

Conclusion

Normalized Cuts is a powerful method for unsupervised image segmentation, but it comes with challenges such as over-segmentation and tuning parameters. By incorporating superpixels and evaluating the performance using appropriate metrics, NCut can effectively segment complex images. The IoU and Rand Index metrics provide meaningful insights into the quality of segmentation, though further refinement is needed to handle multi-class scenarios effectively.
Finally, a complete example is available in my notebook here.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn