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.
Présentation 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.
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 mesures (par exemple, Intersection over Union, SSIM, Rand Index) peuvent être utilisées.
1. Installer les bibliothèques requises
Nous utilisons skimage pour le traitement d'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
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 de la compacité des superpixels (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 peut donner lieu à des superpixels moins sensibles aux contours 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. Paramètres 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, en particulier 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 mesure utilisée pour évaluer la qualité perçue d'une image en comparant deux images en termes de luminance, de contraste et de structure.
Pour appliquer ces métriques, nous avons besoin que la prédiction et l'image de vérité terrain aient les mêmes étiquettes. Pour calculer les étiquettes nous calculons un masque au sol et sur la prédiction attribuons un identifiant à chaque couleur trouvée sur l'image
La segmentation à l'aide de NCut peut cependant trouver plus de régions que la vérité terrain, ce qui réduira la précision.
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)
Nous calculons maintenant les scores de précision
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}")
Les coupes normalisées sont une méthode puissante pour la segmentation d'images non supervisée, mais elle présente des défis tels que la sur-segmentation et le réglage des paramètres. En incorporant des superpixels et en évaluant les performances à l'aide de mesures appropriées, NCut peut segmenter efficacement des images complexes. Les métriques IoU et Rand Index fournissent des informations significatives sur la qualité de la segmentation, bien que des affinements supplémentaires soient nécessaires pour gérer efficacement les scénarios multi-classes.
Enfin, un exemple complet est disponible dans mon carnet ici.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3