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
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.
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.
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=0La
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}")
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!