segmentación de imagen de imagen RGB por K significa agrupación en python

8

Quiero segmentar las imágenes RGB para la cobertura del suelo usando k significa agrupar de tal manera que las diferentes regiones de la imagen estén marcadas con diferentes colores y, si es posible, se crean límites que separen las diferentes regiones. Quiero algo como:

ingrese la descripción de la imagen aquí

de esto :

ingrese la descripción de la imagen aquí

¿Es posible lograr esto mediante la agrupación de K-means? He estado buscando en todo Internet y muchos tutoriales lo hacen por medio de clusters, pero solo después de convertir la imagen a escala de grises. Quiero hacerlo solo con una imagen RGB. ¿Hay alguna fuente que pueda ayudarme a comenzar con esto? Por favor sugiera algo.

rach
fuente
Hola, prueba este enlace. Lo intenté hace algún tiempo, pero solo tuve un éxito limitado. Quizás puedas hacer que funcione un poco mejor. Buena suerte. opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/…
Jcstay
Hola, gracias por su sugerencia @Jcstay, pero ya he probado el enlace y no me ayudó. Gracias de cualquier forma.
rach 01 de
3
Señalaría que el algoritmo K-means, como todos los demás métodos de agrupamiento, necesidades y ajuste óptimo de k. Dado que todo en los datos de referencia se le asignará una clase, si k no está optimizado, los resultados pueden ser erróneos sin soporte para una clase resultante. En estos casos, una clase dada puede representar nada más que ruido o efecto marginal en los datos. Comúnmente, los valores de silueta de margen se utilizan para seleccionar una k óptima.
Jeffrey Evans

Respuestas:

9

Hackeé una solución para esto y escribí un artículo de blog hace un tiempo sobre un tema muy similar, que resumiré aquí. El guión está destinado a extraer un río de una imagen NAIP de 4 bandas mediante un enfoque de segmentación y clasificación de imágenes.

  1. Convierta la imagen en una matriz numpy
  2. Realizar una segmentación de turno rápido (Imagen 2)
  3. Convertir segmentos a formato ráster
  4. Calcular NDVI
  5. Realice estadísticas zonales medias usando segmentos y NDVI para transferir valores NDVI a segmentos (Imagen 3)
  6. Clasificar segmentos basados ​​en valores NDVI
  7. Evaluar resultados (Imagen 4)

Este ejemplo segmenta una imagen usando la agrupación de cambio rápido en el espacio de color (x, y) con 4 bandas (rojo, verde, azul, NIR) en lugar de usar la agrupación K-means. La segmentación de la imagen se realizó utilizando el paquete scikit-image . Más detalles sobre una variedad de algoritmos de segmentación de imágenes en scikit-image aquí . Por conveniencia, solía arcpyhacer gran parte del trabajo de SIG, aunque esto debería ser bastante fácil de transferir a GDAL.


ingrese la descripción de la imagen aquí


from __future__ import print_function

import arcpy
arcpy.CheckOutExtension("Spatial")

import matplotlib.pyplot as plt
import numpy as np
from skimage import io
from skimage.segmentation import quickshift

# The input 4-band NAIP image
river = r'C:\path\to\naip_image.tif'

# Convert image to numpy array
img = io.imread(river)

# Run the quick shift segmentation
segments = quickshift(img, kernel_size=3, convert2lab=False, max_dist=6, ratio=0.5)
print("Quickshift number of segments: %d" % len(np.unique(segments)))

# View the segments via Python
plt.imshow(segments)

# Get raster metrics for coordinate info
myRaster = arcpy.sa.Raster(river)

# Lower left coordinate of block (in map units)
mx = myRaster.extent.XMin
my = myRaster.extent.YMin
sr = myRaster.spatialReference

# Note the use of arcpy to convert numpy array to raster
seg = arcpy.NumPyArrayToRaster(segments, arcpy.Point(mx, my),
                               myRaster.meanCellWidth,
                               myRaster.meanCellHeight)

outRaster = r'C:\path\to\segments.tif'
seg_temp = seg.save(outRaster)
arcpy.DefineProjection_management(outRaster, sr)

# Calculate NDVI from bands 4 and 3
b4 = arcpy.sa.Raster(r'C:\path\to\naip_image.tif\Band_4')
b3 = arcpy.sa.Raster(r'C:\path\to\naip_image.tif\Band_3')
ndvi = arcpy.sa.Float(b4-b3) / arcpy.sa.Float(b4+b3)

# Extract NDVI values based on image object boundaries
zones = arcpy.sa.ZonalStatistics(outRaster, "VALUE", ndvi, "MEAN")
zones.save(r'C:\path\to\zones.tif')

# Classify the segments based on NDVI values
binary = arcpy.sa.Con(zones < 20, 1, 0)
binary.save(r'C:\path\to\classified_image_objects.tif')
Aaron
fuente
2
Esta es una solución fantástica y evita algunos de los problemas con k-means y encontrar una k óptima.
Jeffrey Evans
¡Esto es muy lindo, gran trabajo!
Jcstay
7

Podrías ver la agrupación en scikit-learn . Tendrá que leer los datos en matrices numpy (sugeriría rasterio ) y desde allí puede manipular los datos para que cada banda sea una variable para la clasificación. Por ejemplo, suponiendo que tiene las tres bandas leen en Python como red, greeny bluematrices numpy:

import numpy as np
import sklearn.cluster

original_shape = red.shape # so we can reshape the labels later

samples = np.column_stack([red.flatten(), green.flatten(), blue.flatten()])

clf = sklearn.cluster.KMeans(n_clusters=5)
labels = clf.fit_predict(samples).reshape(original_shape)

import matplotlib.pyplot as plt

plt.imshow(labels)
plt.show()

Tenga en cuenta que la agrupación de KMeans no tiene en cuenta la conectividad dentro del conjunto de datos.

om_henners
fuente
+1 Gran respuesta. Sería especialmente bueno mostrar un ejemplo de conversión de imágenes en color a matrices con numpy usando rasterio;)
Aaron
1
@ Aaron Gracias! He publicado un ejemplo un poco más largo que incluye la lectura de datos usando rasterio.
om_henners
@om_henners su solución es maravillosa pero tengo una pregunta. La imagen segmentada que devuelve su programa usando k significa que la agrupación es 2D. Ahora necesito calcular el coeficiente de similitud de dados entre la imagen original (imagen 3D antes de dividir en bandas R, G, B) y la imagen segmentada, pero eso necesita que las dos tengan las mismas dimensiones. ¿Cómo resuelvo este problema?
rach