La segmentación de imágenes desempeña un papel vital en la comprensión y el análisis de datos visuales, y los cortes normalizados (NCut) son un método ampliamente utilizado para la segmentación basada en gráficos. En este artículo, exploraremos cómo aplicar NCut para la segmentación de imágenes no supervisadas en Python usando un conjunto de datos de Microsoft Research, con un enfoque en mejorar la calidad de la segmentación usando superpíxeles.
Descripción general del conjunto de datos
El conjunto de datos utilizado para esta tarea se puede descargar desde el siguiente enlace: Base de datos de imágenes de categoría de objetos MSRC. Este conjunto de datos contiene imágenes originales, así como su segmentación semántica en nueve clases de objetos (indicadas por archivos de imagen que terminan en "_GT"). Estas imágenes se agrupan en subconjuntos temáticos, donde el primer número del nombre del archivo se refiere a un subconjunto de clase. Este conjunto de datos es perfecto para experimentar con tareas de segmentación.
Realizamos segmentación de imágenes en una imagen del conjunto de datos utilizando el algoritmo NCut. La segmentación a nivel de píxeles es computacionalmente costosa y, a menudo, ruidosa. Para superar esto, utilizamos SLIC (Simple Linear Iterative Clustering) para generar superpíxeles, que agrupa píxeles similares y reduce el tamaño del problema. Para evaluar la precisión de la segmentación se pueden utilizar diferentes métricas (por ejemplo, Intersección sobre Unión, SSIM, Índice Rand).
1. Instalar bibliotecas necesarias
Usamos skimage para el procesamiento de imágenes, numpy para cálculos numéricos y matplotlib para visualización.
pip install numpy matplotlib pip install scikit-image==0.24.0 **2. Load and Preprocess the Dataset**
Después de descargar y extraer el conjunto de datos, cargue las imágenes y la segmentación real del terreno:
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
Ahora estamos listos para comenzar a codificar.
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. Genere superpíxeles usando SLIC y cree un gráfico de adyacencia de región
Utilizamos el algoritmo SLIC para calcular superpíxeles antes de aplicar NCut. Utilizando los superpíxeles generados, construimos un gráfico de adyacencia de región (RAG) basado en la similitud de color media:
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
compacidad controla el equilibrio entre la similitud de color y la proximidad espacial de los píxeles al formar superpíxeles. Determina cuánto énfasis se pone en mantener los superpíxeles compactos (más cerca en términos espaciales) versus garantizar que estén agrupados de manera más homogénea por color.
Valores más altos: un valor de compacidad más alto hace que el algoritmo dé prioridad a la creación de superpíxeles espacialmente ajustados y de tamaño uniforme, con menos atención a la similitud de color. Esto podría dar como resultado superpíxeles que son menos sensibles a los bordes o degradados de color.
Valores más bajos: un valor de compacidad más bajo permite que los superpíxeles varíen más en tamaño espacial para respetar las diferencias de color con mayor precisión. Esto normalmente da como resultado superpíxeles que siguen más de cerca los límites de los objetos en la imagen.
n_segments controla el número de superpíxeles (o segmentos) que el algoritmo SLIC intenta generar en la imagen. Básicamente, establece la resolución de la segmentación.
Valores más altos: un valor de n_segments más alto crea más superpíxeles, lo que significa que cada superpíxel será más pequeño y la segmentación será más detallada. Esto puede resultar útil cuando la imagen tiene texturas complejas u objetos pequeños.
Valores más bajos: un valor de n_segmentos más bajo produce menos superpíxeles y más grandes. Esto es útil cuando desea una segmentación aproximada de la imagen, agrupando áreas más grandes en superpíxeles individuales.
4. Aplique cortes normalizados (NCut) y visualice el resultado
# 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étricas de evaluación
El desafío clave en la segmentación no supervisada es que NCut no sabe el número exacto de clases en la imagen. La cantidad de segmentos encontrados por NCut puede exceder la cantidad real de regiones reales del terreno. Como resultado, necesitamos métricas sólidas para evaluar la calidad de la segmentación.
Intersección sobre unión (IoU) es una métrica ampliamente utilizada para evaluar tareas de segmentación, particularmente en visión por computadora. Mide la superposición entre las regiones segmentadas previstas y las regiones reales del terreno. Específicamente, IoU calcula la relación entre el área de superposición entre la segmentación predicha y la verdad fundamental y el área de su unión.
Índice de similitud estructural (SSIM) es una métrica utilizada para evaluar la calidad percibida de una imagen comparando dos imágenes en términos de luminancia, contraste y estructura.
Para aplicar estas métricas necesitamos que la predicción y la imagen de verdad fundamental tengan las mismas etiquetas. Para calcular las etiquetas calculamos una máscara en el terreno y en la predicción asignamos una ID a cada color que se encuentra en la imagen
Sin embargo, la segmentación mediante NCut puede encontrar más regiones que la verdad básica, lo que reducirá la precisión.
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)
Ahora calculamos las puntuaciones de precisión
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}")
Los cortes normalizados son un método poderoso para la segmentación de imágenes sin supervisión, pero presenta desafíos como la sobresegmentación y el ajuste de parámetros. Al incorporar superpíxeles y evaluar el rendimiento utilizando métricas adecuadas, NCut puede segmentar eficazmente imágenes complejas. Las métricas del índice IoU y Rand brindan información significativa sobre la calidad de la segmentación, aunque se necesita un mayor refinamiento para manejar escenarios de múltiples clases de manera efectiva.
Finalmente, un ejemplo completo está disponible en mi cuaderno aquí.
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3