segmentation de l'image RVB par K signifie clustering en python

8

Je veux segmenter les images RVB pour la couverture terrestre en utilisant k signifie un regroupement de telle manière que les différentes régions de l'image sont marquées par des couleurs différentes et si possible des limites sont créées séparant les différentes régions. Je veux quelque chose comme:

entrez la description de l'image ici

de cela:

entrez la description de l'image ici

Est-il possible d'y parvenir par le clustering K-means? J'ai cherché partout sur Internet et de nombreux didacticiels le font par k moyens de clustering, mais uniquement après avoir converti l'image en échelle de gris. Je veux le faire avec une image RVB uniquement. Y a-t-il une source qui pourrait m'aider à commencer? Veuillez suggérer quelque chose.

rach
la source
Salut, essayez ce lien. Je l'ai essayé il y a quelque temps, mais je n'ai eu qu'un succès limité. Vous pouvez peut-être le faire fonctionner un peu mieux. Bonne chance. opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/…
Jcstay
Salut, merci pour votre suggestion @Jcstay mais j'ai déjà essayé le lien et cela n'a pas aidé. Merci quand même.
rach
3
Je voudrais souligner que l'algorithme K-means, comme toutes les autres méthodes de clustering, a besoin et l'ajustement optimal de k. Étant donné que tout dans les données de référence se verra attribuer une classe, si k n'est pas optimisé, les résultats peuvent être erronés sans prise en charge d'une classe résultante. Dans ces cas, une classe donnée ne peut rien représenter d'autre que du bruit ou un effet marginal dans les données. Généralement, les valeurs de silhouette de marge sont utilisées pour sélectionner un k optimal.
Jeffrey Evans

Réponses:

9

J'ai piraté ensemble une solution pour cela et j'ai écrit un article de blog il y a quelque temps sur un sujet très similaire, que je résumerai ici. Le script est destiné à extraire une rivière d'une image NAIP à 4 bandes en utilisant une approche de segmentation et de classification d'images.

  1. Convertir l'image en un tableau numpy
  2. Effectuer une segmentation rapide de décalage (Image 2)
  3. Convertir des segments au format raster
  4. Calculer NDVI
  5. Effectuer des statistiques zonales moyennes en utilisant des segments et NDVI pour transférer des valeurs NDVI vers des segments (Image 3)
  6. Classer les segments en fonction des valeurs NDVI
  7. Évaluez les résultats (Image 4)

Cet exemple segmente une image en utilisant le clustering quickshift dans l'espace couleur (x, y) avec 4 bandes (rouge, vert, bleu, NIR) plutôt qu'en utilisant le clustering K-means. La segmentation de l'image a été effectuée à l'aide du package scikit-image . Plus de détails sur une variété d'algorithmes de segmentation d'image dans scikit-image ici . Pour des raisons de commodité, je faisais une arcpygrande partie du travail SIG, bien que cela devrait être assez facile à transférer vers GDAL.


entrez la description de l'image ici


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
la source
2
C'est une solution fantastique et évite certains des problèmes avec k-means et la recherche d'un k optimal.
Jeffrey Evans
C'est très beau, excellent travail !!
Jcstay
7

Vous pouvez regarder le clustering dans scikit-learn . Vous devrez lire les données dans des tableaux numpy (je suggérerais rasterio ) et à partir de là, vous pouvez manipuler les données afin que chaque bande soit une variable de classification. Par exemple, en supposant que vous avez les trois bandes lu en python comme red, greenet les bluetableaux 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()

Notez que le clustering KMeans ne prend pas en compte la connectivité au sein de l'ensemble de données.

om_henners
la source
+1 Excellente réponse. Il serait particulièrement agréable de montrer un exemple de conversion d'images couleur en tableaux numpy en utilisant rasterio;)
Aaron
1
@Aaron Merci! J'ai publié un exemple un peu plus long, y compris la lecture de données en utilisant rasterio.
om_henners
@om_henners votre solution est merveilleuse mais j'ai une question. L'image segmentée renvoyée par votre programme en utilisant k signifie que le clustering est 2D. Maintenant, je dois calculer le coefficient de similitude des dés entre l'image d'origine (image 3D avant de se diviser en bandes R, G, B) et l'image segmentée, mais qui a besoin des deux pour avoir les mêmes dimensions. Comment résoudre ce problème?
rach