A segmentação de imagens desempenha um papel vital na compreensão e análise de dados visuais, e Cortes Normalizados (NCut) é um método amplamente utilizado para segmentação baseada em gráficos. Neste artigo, exploraremos como aplicar NCut para segmentação de imagens não supervisionadas em Python usando um conjunto de dados da Microsoft Research, com foco em melhorar a qualidade da segmentação usando superpixels.
Visão geral do conjunto de dados
O conjunto de dados usado para esta tarefa pode ser baixado no seguinte link: Banco de dados de imagens de categoria de objeto MSRC. Este conjunto de dados contém imagens originais, bem como sua segmentação semântica em nove classes de objetos (indicadas por arquivos de imagem terminados em “_GT”). Essas imagens são agrupadas em subconjuntos temáticos, onde o primeiro número no nome do arquivo refere-se a um subconjunto de classe. Este conjunto de dados é perfeito para experimentar tarefas de segmentação.
Realizamos segmentação de imagem em uma imagem no conjunto de dados usando o algoritmo NCut. A segmentação no nível do pixel é computacionalmente cara e muitas vezes barulhenta. Para superar isso, usamos SLIC (Simple Linear Iterative Clustering) para gerar superpixels, que agrupa pixels semelhantes e reduz o tamanho do problema. Para avaliar a precisão da segmentação, diferentes métricas (por exemplo, Intersecção sobre União, SSIM, Índice Rand) podem ser usadas.
1. Instale as bibliotecas necessárias
Usamos skimage para processamento de imagem, numpy para cálculos numéricos e matplotlib para visualização.
pip install numpy matplotlib pip install scikit-image==0.24.0 **2. Load and Preprocess the Dataset**
Depois de baixar e extrair o conjunto de dados, carregue as imagens e a segmentação da verdade:
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
Agora estamos prontos para começar 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. Gere superpixels usando SLIC e crie um gráfico de adjacência de região
Usamos o algoritmo SLIC para calcular superpixels antes de aplicar o NCut. Usando os superpixels gerados, construímos um Gráfico de Adjacência de Região (RAG) com base na similaridade média de cores:
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
compactação controla o equilíbrio entre a similaridade de cores e a proximidade espacial dos pixels ao formar superpixels. Ele determina quanta ênfase é colocada em manter os superpixels compactos (mais próximos em termos espaciais) em vez de garantir que eles sejam agrupados de forma mais homogênea por cor.
Valores mais altos: Um valor de compactação mais alto faz com que o algoritmo priorize a criação de superpixels que sejam espacialmente compactos e de tamanho uniforme, com menos atenção à semelhança de cores. Isso pode resultar em superpixels menos sensíveis a bordas ou gradientes de cores.
Valores mais baixos: Um valor de compacidade mais baixo permite que os superpixels variem mais no tamanho espacial para respeitar as diferenças de cores com mais precisão. Isso normalmente resulta em superpixels que seguem mais de perto os limites dos objetos na imagem.
n_segments controla o número de superpixels (ou segmentos) que o algoritmo SLIC tenta gerar na imagem. Essencialmente, ele define a resolução da segmentação.
Valores mais altos: um valor mais alto de n_segments cria mais superpixels, o que significa que cada superpixel será menor e a segmentação será mais refinada. Isso pode ser útil quando a imagem tem texturas complexas ou objetos pequenos.
Valores mais baixos: um valor mais baixo de n_segments produz menos superpixels maiores. Isso é útil quando você deseja uma segmentação grosseira da imagem, agrupando áreas maiores em superpixels únicos.
4. Aplique cortes normalizados (NCut) e visualize o 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 avaliação
O principal desafio na segmentação não supervisionada é que o NCut não sabe o número exato de classes na imagem. O número de segmentos encontrados pelo NCut pode exceder o número real de regiões de verdade. Como resultado, precisamos de métricas robustas para avaliar a qualidade da segmentação.
Intersection over Union (IoU) é uma métrica amplamente utilizada para avaliar tarefas de segmentação, particularmente em visão computacional. Ele mede a sobreposição entre as regiões segmentadas previstas e as regiões de verdade. Especificamente, IoU calcula a proporção da área de sobreposição entre a segmentação prevista e a verdade básica para a área de sua união.
Índice de Similaridade Estrutural (SSIM) é uma métrica usada para avaliar a qualidade percebida de uma imagem comparando duas imagens em termos de luminância, contraste e estrutura.
Para aplicar essas métricas, precisamos que a previsão e a imagem da verdade tenham os mesmos rótulos. Para calcular os rótulos calculamos uma máscara no solo e na previsão atribuímos um ID para cada cor encontrada na imagem
A segmentação usando NCut, no entanto, pode encontrar mais regiões do que a verdade básica, o que diminuirá a precisão.
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)
Agora calculamos as pontuações de precisão
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}")
Cortes normalizados é um método poderoso para segmentação de imagem não supervisionada, mas apresenta desafios como segmentação excessiva e parâmetros de ajuste. Ao incorporar superpixels e avaliar o desempenho usando métricas apropriadas, o NCut pode segmentar imagens complexas com eficácia. As métricas IoU e Rand Index fornecem insights significativos sobre a qualidade da segmentação, embora seja necessário refinamento adicional para lidar com cenários multiclasse de forma eficaz.
Por fim, um exemplo completo está disponível em meu notebook aqui.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3