Segmenter une image en k-means
en langage python
L'essentiel de cette page
Voici quelques explications pour segmenter une image avec opencv. L'installation de ce module peut être délicate, mais fera gagner beaucoup de temps de traitement.
Se référer à la page traitement d'image pour voir comment charger l'image en amont du traitement.
Il existe plusieurs méthode de k-means pour catégoriser automatiquement les points et les segmenter mais problème ! C'est en général tellement lourd que ça plante.
On pourrait très bien faire un k-means classique sur le tableau de composantes rgb de l'exemple ci-dessus (partie 2) mais la fonction de k-means a toutes les chances de planter à cause de la taille de la dataframe.
L'idéeal est d'utiliser opencv, ce module permet d'implémenter de nombreuses fonctions très rapide de traitement d'images.
1- Installer opencv (module cv2)
Taper un des codes suivant dans la console windows (il faut avoir installer PIP) :
python -m pip install --user cv2
run pip install opencv-python
On peut aussi faire une installation manuelle en suivant ces instructions :
2- Charger l'image et la convertir au format numpy
import numpy as np
import cv2
import easygui
image_ref = cv2.imread(easygui.fileopenbox())
Z = image_ref.reshape((-1,3))
# convert to np.float32
Z = np.float32(Z)
cv2.imshow("Image d'origine",image_ref)
3- Réaliser une segmentation avec la fonction k-means d'opencv
Appliquer le k-means
# definir : criteria, nombre de catégories (K) et faire le kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) # Paramétrage
K = 10
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
Afficher l'image segmentée
center = np.uint8(center)
resultat = center[label.flatten()]
resultat = resultat .reshape((image_ref.shape))
cv2.imshow('Résultat de la segmentation',resultat ) # Affichage avec cv 2
import matplotlib.pyplot as plt
# Reconversion pour affichage correcte
image_reconvertie=cv2.cvtColor(resultat,cv2.COLOR_BGR2RGB)
plt.imshow(image_reconvertie) ; plt.show()
# Affichage avec matplotlib.pyplot
# groupes créés
print(np.unique(label.flatten()))
Image segmentée
4- Extraire les catégories intéressantes (par exemple, les prairies)
def extraction(img,label,criteria,centers) :
for i in range(len(label)) :
if label[i] not in criteria :
label[i] = 0
criteria = set(criteria)
indices_center = set(range(len(centers)))
indices_center = indices_center-criteria
indices_center = list(indices_center)
centerss = centers.copy()
centerss[indices_center] = [0,0,0]
new_img = centerss[label]
new_img = new_img.reshape((img.shape))
return(new_img)
resultat_prairie = extraction(image_ref,label.flatten(),[0,1,2,4],center)
image_reconvertie=cv2.cvtColor(resultat_prairie,cv2.COLOR_BGR2RGB) # Reconversion pour affichage correcte
import matplotlib.pyplot as plt
plt.imshow(image_reconvertie) ; plt.show() # Affichage avec matplotlib.pyplot
#cv2.imshow('Affichage de la composante prairie des résultats',resultat_prairie)
5- Utiliser les critères de l'image précédente (d'apprentissage) pour segmenter de nouvelles images
# Ouvrir la nouvelle image
nouvelle_image = cv2.imread(easygui.fileopenbox())
Z2 = nouvelle_image.reshape((-1,3)) ; Z2 = np.float32(Z2)
criteria = (cv2.TERM_CRITERIA_MAX_ITER, 0, 0) # Paramétrage pour que l'arrêt se fasse à une itération
K = 10
ret2,label2,center2=cv2.kmeans(Z2,K,center,criteria,10,cv2.KMEANS_USE_INITIAL_LABELS)
criteria = (cv2.TERM_CRITERIA_MAX_ITER, 1, 1)
ret2,label2,center2=cv2.kmeans(Z2,K,center,criteria, 1, cv2.KMEANS_USE_INITIAL_LABELS, center)
# Conversion en image
center2 = np.uint8(center2)
sortie = center2[label2.flatten()]
sortie= sortie.reshape((nouvelle_image.shape))
plt.imshow(sortie) ; plt.show() # Résultat de la segmentation
# il ne reste qu'à copier coller la partie 3.4 pour extraire les prairies de cette nouvelle image
resultat_prairie = extraction(sortie,label2.flatten(),[0,1,2,4],center)
A ce stade, l'apprentissage ne semble pas bien fonctionner : center2 et center sont différents ce qui prouve que l'apprentissage n'a pas pu fixer des centres et que les prairies seront donc segmentées avec des critères variables...
A développer :
Regrouper des lignes de pixel en niveau de gris et en couleur
Récupérer la position d'un pixel
Afficher l'image
Superposer 3 images r, g, b