Un aperçu des méthodes de segmentation d'images dans la bibliothèque d'images scikit

Seuillage


C'est le moyen le plus simple de séparer les objets de l'arrière-plan en sélectionnant des pixels au-dessus ou en dessous d'un certain seuil. Ceci est généralement utile lorsque nous allons segmenter des objets en fonction de leur arrière-plan. Vous pouvez en savoir plus sur le seuil ici .

Les gens familiers avec le film Terminator conviendront probablement que c'était le plus grand film de science-fiction de l'époque. Dans le film, James Cameron a introduit un concept intéressant d'effets visuels, qui a permis aux téléspectateurs de se cacher derrière les yeux d'un cyborg appelé Terminator. Cet effet est devenu connu sous le nom de "Terminator Vision" (English Terminator Vision). Dans un sens, il a séparé les silhouettes des gens de l'arrière-plan. Cela peut sembler tout à fait inapproprié alors, mais la segmentation d'image est aujourd'hui un élément important de nombreuses techniques de traitement d'image.

Segmentation d'image


Il existe un certain nombre de bibliothèques écrites pour l'analyse d'images. Dans cet article, nous discuterons en détail de scikit-image, une bibliothèque de traitement d'images Python.

Scikit-image


image

Scikit-image est une bibliothèque Python pour le traitement d'images.

L'installation


scikit-image est installé comme suit:

pip install -U scikit-image(Linux and OSX) pip install scikit-image(Windows) # For Conda-based distributions conda install scikit-image 



Présentation de l'image Python


Avant de passer aux aspects techniques de la segmentation d'images, il est important de se familiariser un peu avec l'écosystème d'images Scikit et la façon dont il traite les images.

Importer une image GrayScale de la bibliothèque skimage


Le module de données skimage contient plusieurs exemples intégrés d'ensembles de données, qui sont généralement stockés au format jpeg ou png.

 from skimage import data import numpy as np import matplotlib.pyplot as plt image = data.binary_blobs() plt.imshow(image, cmap='gray') 

Importer une image couleur de la bibliothèque skimage


 from skimage import data import numpy as np import matplotlib.pyplot as plt image = data.astronaut() plt.imshow(image) 



Importer une image depuis une source externe


 # The I/O module is used for importing the image from skimage import data import numpy as np import matplotlib.pyplot as plt from skimage import io image = io.imread('skimage_logo.png') plt.imshow(image); 



Téléchargez plusieurs images


 images = io.ImageCollection('../images/*.png:../images/*.jpg') print('Type:', type(images)) images.files Out[]: Type: <class 'skimage.io.collection.ImageCollection'> 

Enregistrement d'images


 #Saving file as 'logo.png' io.imsave('logo.png', logo) 

Segmentation d'image


Maintenant que nous avons une idée de scikit-image, nous proposons de considérer les détails de la segmentation de l'image. La segmentation d'image est le processus de division d'une image numérique en plusieurs segments afin de simplifier et / ou de changer la représentation de l'image en quelque chose de plus significatif et plus facile à analyser.

Dans cet article, nous considérerons les algorithmes pour les modèles enseignés à la fois avec un enseignant (supervisé) et sans enseignant (non supervisé).


Certains algorithmes de segmentation sont disponibles dans la bibliothèque d'images de scikit.

Segmentation avec un enseignant: certaines connaissances préliminaires, peut-être issues de contributions humaines, sont utilisées pour guider l'algorithme.

Segmentation sans enseignant: aucune connaissance préalable n'est requise. Ces algorithmes tentent de diviser automatiquement les images en zones significatives. L'utilisateur peut toujours configurer certains paramètres pour obtenir les résultats souhaités.

Essayons cela sur une image de didacticiel fournie avec un jeu de données d'image scikit prédéfini.

Importation régulière


 import numpy as np import matplotlib.pyplot as plt import skimage.data as data import skimage.segmentation as seg import skimage.filters as filters import skimage.draw as draw import skimage.color as color 

Fonction d'imagerie simple

 def image_show(image, nrows=1, ncols=1, cmap='gray'): fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14)) ax.imshow(image, cmap='gray') ax.axis('off') return fig, ax 

Image


 text = data.page() image_show(text) 



Cette image est un peu plus sombre, mais peut-être que nous pouvons toujours choisir une valeur qui nous donnera une segmentation raisonnable sans algorithmes compliqués. Maintenant, pour nous aider à choisir cette valeur, nous allons utiliser un histogramme.

Dans ce cas, l'histogramme montre le nombre de pixels dans l'image avec différentes intensités trouvées dans cette image. Autrement dit, un histogramme est un graphique dans lequel l'axe X montre toutes les valeurs qui sont dans l'image, et l'axe Y montre la fréquence de ces valeurs.

 fig, ax = plt.subplots(1, 1) ax.hist(text.ravel(), bins=32, range=[0, 256]) ax.set_xlim(0, 256); 



Notre exemple s'est avéré être une image 8 bits, nous avons donc 256 valeurs possibles le long de l'axe X. L'histogramme montre qu'il y a une concentration de pixels assez lumineux (0: noir, 255: blanc). C'est très probablement notre joli fond de texte clair, mais le reste est un peu flou. Un histogramme de segmentation idéal serait bimodal afin que nous puissions sélectionner un nombre en plein milieu. Essayons maintenant de créer des images segmentées basées sur une valeur de seuil simple.

Seuil contrôlé


Puisque nous choisissons nous-mêmes une valeur seuil, nous l'appelons une valeur seuil contrôlée.

 text_segmented = text > (value concluded from histogram ie 50,70,120 ) image_show(text_segmented); 


Gauche: texte> 50 | Milieu: texte> 70 | Droite: texte> 120

Nous n'avons pas obtenu de résultats parfaits, car l'ombre de gauche crée des problèmes. Essayons avec le seuil sans surveillance maintenant.

Seuil incontrôlé


Seuil non contrôlé Scikit-image dispose d'un certain nombre de méthodes de détermination automatique de seuil qui ne nécessitent pas d'entrée lors du choix du seuil optimal. Voici quelques-unes des méthodes: otsu, li, local.

 text_threshold = filters.threshold_ # Hit tab with the cursor after the underscore to get all the methods. image_show(text < text_threshold); 


Otsu gauche || Droite: li

Dans le cas de local, nous devons également spécifier block_size. Le décalage permet d'ajuster l'image pour de meilleurs résultats.

 text_threshold = filters.threshold_local(text,block_size=51, offset=10) image_show(text > text_threshold); 



Cette méthode donne un assez bon effet. Dans une large mesure, on peut se débarrasser des régions bruyantes.

Segmentation avec un algorithme pour un modèle avec un enseignant


Le seuillage est un processus de segmentation très simple, et il ne fonctionnera pas correctement sur une image à contraste élevé, pour laquelle nous aurons besoin d'outils plus avancés.

Dans cette section, nous allons utiliser un exemple d'image disponible gratuitement et essayer de segmenter la partie tête en utilisant des méthodes avec l'enseignant.

 # import the image from skimage import io image = io.imread('girl.jpg') plt.imshow(image); 



Avant d'effectuer une segmentation d'image, il est recommandé d'en supprimer le bruit à l'aide de certains filtres.

Cependant, dans notre cas, l'image n'a pas de bruit significatif, nous l'accepterons telle quelle. L'étape suivante consiste à convertir l'image en niveaux de gris à l'aide de rgb2gray.

 image_gray = color.rgb2gray(image) image_show(image_gray); 



Nous utiliserons deux méthodes de segmentation qui fonctionnent sur des principes complètement différents.

Segmentation active des contours


La segmentation du chemin actif est également appelée serpent et est initialisée à l'aide d'un chemin ou d'une ligne défini par l'utilisateur autour d'une région d'intérêt, puis ce chemin est lentement compressé et attiré ou repoussé par la lumière et les bords.

Pour notre exemple d'image, dessinons un cercle autour de la tête humaine pour initialiser le serpent.

 def circle_points(resolution, center, radius): """ Generate points which define a circle on an image.Centre refers to the centre of the circle """ radians = np.linspace(0, 2*np.pi, resolution) c = center[1] + radius*np.cos(radians)#polar co-ordinates r = center[0] + radius*np.sin(radians) return np.array([c, r]).T # Exclude last point because a closed path should not have duplicate points points = circle_points(200, [80, 250], 80)[:-1] 

Les calculs ci-dessus calculent les coordonnées x et y des points à la périphérie du cercle. Puisque nous avons donné une résolution de 200, il calculera 200 de ces points.

 fig, ax = image_show(image) ax.plot(points[:, 0], points[:, 1], '--r', lw=3) 



L’algorithme segmente ensuite le visage de la personne du reste de l’image, en ajustant une courbe fermée aux bords du visage.



Nous pouvons configurer des paramètres appelés alpha et bêta. Des valeurs alpha plus élevées accélèrent la contraction de la courbe, tandis que la bêta rend la courbe plus lisse.

 snake = seg.active_contour(image_gray, points,alpha=0.06,beta=0.3) fig, ax = image_show(image) ax.plot(points[:, 0], points[:, 1], '--r', lw=3) ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3); 



Segmentation aléatoire des marcheurs


Dans cette méthode, la segmentation est effectuée à l'aide d'un étiquetage interactif, appelé étiquettes. En dessinant chaque pixel sur l'étiquette pour laquelle la probabilité la plus élevée est calculée, vous pouvez obtenir une segmentation d'image de haute qualité. Plus de détails sur cette méthode peuvent être trouvés dans cet ouvrage.

Ensuite, nous utiliserons à nouveau les valeurs précédentes de notre exemple. Nous aurions pu faire différentes initialisations, mais pour plus de simplicité, restons-en au principe des cercles.

 image_labels = np.zeros(image_gray.shape, dtype=np.uint8) 

L'algorithme de passage aléatoire accepte les étiquettes en entrée. Ainsi, nous aurons un grand cercle couvrant tout le visage de la personne et un autre petit cercle près du milieu du visage.

 indices = draw.circle_perimeter(80, 250,20)#from here image_labels[indices] = 1 image_labels[points[:, 1].astype(np.int), points[:, 0].astype(np.int)] = 2 image_show(image_labels); 


Maintenant, utilisons Random Walker et voyons ce qui se passe.

 image_segmented = seg.random_walker(image_gray, image_labels) # Check our results fig, ax = image_show(image_gray) ax.imshow(image_segmented == 1, alpha=0.3); 



Le résultat n'est pas le meilleur, les bords du visage sont restés intacts. Pour corriger cette situation, nous pouvons ajuster le paramètre de passage jusqu'à obtenir le résultat souhaité. Après plusieurs tentatives, nous avons défini la valeur sur 3000, ce qui fonctionne assez bien.

 image_segmented = seg.random_walker(image_gray, image_labels, beta = 3000) # Check our results fig, ax = image_show(image_gray) ax.imshow(image_segmented == 1, alpha=0.3); 



C'est tout pour la segmentation avec l'enseignant, où nous devions fournir certaines données d'entrée, ainsi que configurer certains paramètres. Cependant, il n'est pas toujours possible pour une personne de regarder l'image, puis de décider quelle contribution apporter et par où commencer. Heureusement, pour de telles situations, nous avons des méthodes de segmentation incontrôlées.

Segmentation sans enseignant


La segmentation sans enseignant ne nécessite pas de connaissances préalables. Considérez une image si grande qu'il est impossible de voir tous les pixels à la fois. Ainsi, dans de tels cas, la segmentation sans enseignant peut diviser l'image en plusieurs sous-régions, donc au lieu de millions de pixels, vous avez des dizaines ou des centaines de zones. Regardons deux de ces algorithmes:

Regroupement itératif linéaire simple


La méthode (English Simple Linear Iterative Clustering ou SLIC) utilise un algorithme d'apprentissage automatique appelé K-Means. Il prend toutes les valeurs de pixels de l'image et essaie de les diviser en un nombre donné de sous-domaines. Lisez ce travail pour des informations détaillées.

SLIC fonctionne avec différentes couleurs, nous allons donc utiliser l'image d'origine.

 image_slic = seg.slic(image,n_segments=155) 

Tout ce que nous devons faire est simplement de définir une valeur moyenne pour chaque segment que nous trouvons, ce qui le fait ressembler davantage à une image.

 # label2rgb replaces each discrete label with the average interior color image_show(color.label2rgb(image_slic, image, kind='avg')); 



Nous avons réduit cette image de 512 * 512 = 262 000 pixels à 155 segments.

Felzenszwalb


Cette méthode utilise également un algorithme d'apprentissage automatique appelé clustering d'arbre couvrant un minimum. Felzenszwaib ne nous dit pas le nombre exact de clusters dans lesquels l'image sera divisée. Il générera autant de clusters qu'il le jugera bon.

 image_felzenszwalb = seg.felzenszwalb(image) image_show(image_felzenszwalb); 



Il y a trop de régions dans l'image. Comptons le nombre de segments uniques.

 np.unique(image_felzenszwalb).size 3368 

Maintenant, recolorons-les en utilisant la valeur moyenne sur le segment, comme nous l'avons fait dans l'algorithme SLIC.

 image_felzenszwalb_colored = color.label2rgb(image_felzenszwalb, image, kind='avg') image_show(image_felzenszwalb_colored); 

Maintenant, nous obtenons moins de segments. Si nous voulions encore moins de segments, nous pourrions changer le paramètre d'échelle. Cette approche est parfois appelée sur-segmentation.



Cela ressemble plus à une image postérisée, qui n'est essentiellement qu'une réduction du nombre de couleurs. Pour les combiner à nouveau (RAG).

Conclusion


La segmentation d'image est une étape très importante dans le traitement d'image. Il s'agit d'un domaine de recherche actif avec une variété d'applications, allant de la vision par ordinateur aux images médicales, au trafic et à la vidéosurveillance. Python fournit une bibliothèque d'images scikit robuste avec un grand nombre d'algorithmes de traitement d'image. Il est disponible gratuitement et sans restrictions, soutenu par une communauté active. Je vous recommande de lire leur documentation. L'article original se trouve ici .

Source: https://habr.com/ru/post/fr441006/


All Articles