Eine Übersicht über Bildsegmentierungsmethoden in der Scikit-Bildbibliothek

Schwellenwert


Dies ist der einfachste Weg, um Objekte vom Hintergrund zu trennen, indem Sie Pixel über oder unter einem bestimmten Schwellenwert auswählen. Dies ist normalerweise nützlich, wenn wir Objekte nach ihrem Hintergrund segmentieren. Weitere Informationen zum Schwellenwert finden Sie hier .

Leute, die mit dem Film Terminator vertraut sind, werden wahrscheinlich zustimmen, dass es der größte Science-Fiction-Film der Ära war. In dem Film stellte James Cameron ein interessantes Konzept visueller Effekte vor, das es den Zuschauern ermöglichte, sich hinter den Augen eines Cyborgs namens Terminator zu verstecken. Dieser Effekt wurde als "Terminator Vision" (englische Terminator Vision) bekannt. In gewisser Weise trennte er die Silhouetten von Menschen vom Hintergrund. Das mag damals völlig unangemessen klingen, aber die Bildsegmentierung ist heute ein wichtiger Bestandteil vieler Bildverarbeitungstechniken.

Bildsegmentierung


Es gibt eine Reihe von Bibliotheken, die für die Bildanalyse geschrieben wurden. In diesem Artikel werden wir scikit-image, eine Python-Bildverarbeitungsbibliothek, ausführlich behandeln.

Scikit-Bild


Bild

Scikit-image ist eine Python-Bibliothek für die Bildverarbeitung.

Installation


scikit-image wird wie folgt installiert:

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



Python-Bildübersicht


Bevor wir uns mit den technischen Aspekten der Bildsegmentierung befassen, ist es wichtig, sich mit dem Scikit-Bildökosystem und dessen Verarbeitung vertraut zu machen.

Importieren Sie GrayScale Image aus der Skimage-Bibliothek


Das Skimage-Datenmodul enthält mehrere integrierte Beispiele für Datensätze, die normalerweise im JPEG- oder PNG-Format gespeichert sind.

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

Importieren Sie ein Farbbild aus der Skimage-Bibliothek


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



Importieren Sie ein Bild von einer externen Quelle


 # 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); 



Laden Sie mehrere Bilder herunter


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

Bilder speichern


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

Bildsegmentierung


Nachdem wir eine Vorstellung von Scikit-Image haben, bieten wir an, die Details der Bildsegmentierung zu berücksichtigen. Bei der Bildsegmentierung wird ein digitales Bild in mehrere Segmente unterteilt, um die Bilddarstellung zu vereinfachen und / oder in etwas aussagekräftigeres und leichter zu analysierendes zu ändern.

In diesem Artikel werden Algorithmen für Modelle betrachtet, die sowohl mit einem Lehrer (überwacht) als auch ohne Lehrer (unbeaufsichtigt) unterrichtet werden.


Einige der Segmentierungsalgorithmen sind in der Scikit-Bildbibliothek verfügbar.

Segmentierung mit einem Lehrer: Einige vorläufige Kenntnisse, möglicherweise aus menschlichen Eingaben, werden verwendet, um den Algorithmus zu steuern.

Segmentierung ohne Lehrer: Vorkenntnisse sind nicht erforderlich. Diese Algorithmen versuchen, die Bilder automatisch in signifikante Bereiche zu unterteilen. Der Benutzer kann weiterhin bestimmte Parameter konfigurieren, um die gewünschten Ergebnisse zu erzielen.

Versuchen wir dies an einem Tutorial-Bild, das mit einem vordefinierten Scikit-Bild-Dataset geliefert wird.

Regelmäßiger Import


 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 

Einfache Bildgebungsfunktion

 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 

Bild


 text = data.page() image_show(text) 



Dieses Bild ist etwas dunkler, aber vielleicht können wir trotzdem einen Wert auswählen, der uns eine vernünftige Segmentierung ohne komplizierte Algorithmen ermöglicht. Um uns bei der Auswahl dieses Werts zu helfen, verwenden wir ein Histogramm.

In diesem Fall zeigt das Histogramm die Anzahl der Pixel im Bild mit unterschiedlichen Intensitäten, die in diesem Bild gefunden wurden. Einfach ausgedrückt ist ein Histogramm ein Diagramm, in dem die X-Achse alle Werte im Bild und die Y-Achse die Häufigkeit dieser Werte anzeigt.

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



Unser Beispiel stellte sich als 8-Bit-Bild heraus, sodass wir 256 mögliche Werte entlang der X-Achse haben. Das Histogramm zeigt, dass eine Konzentration von ziemlich hellen Pixeln vorliegt (0: Schwarz, 255: Weiß). Dies ist höchstwahrscheinlich unser ziemlich heller Texthintergrund, aber der Rest ist etwas verschwommen. Ein ideales Segmentierungshistogramm wäre bimodal, sodass wir eine Zahl genau in der Mitte auswählen können. Versuchen wir nun, einige segmentierte Bilder basierend auf einem einfachen Schwellenwert zu erstellen.

Kontrollierte Schwelle


Da wir selbst einen Schwellenwert wählen, nennen wir ihn einen kontrollierten Schwellenwert.

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


Links: Text> 50 | Mitte: Text> 70 | Rechts: Text> 120

Wir haben keine perfekten Ergebnisse erzielt, da der Schatten links Probleme verursacht. Versuchen wir es jetzt mit der unbeaufsichtigten Schwelle.

Unkontrollierte Schwelle


Unkontrollierter Schwellenwert Scikit-image verfügt über eine Reihe automatischer Schwellenwertbestimmungsmethoden, die bei der Auswahl des optimalen Schwellenwerts keine Eingabe erfordern. Hier sind einige der Methoden: 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); 


Links otsu || Richtig: li

Im Fall von local müssen wir auch block_size angeben. Der Versatz hilft, das Bild für bessere Ergebnisse anzupassen.

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



Diese Methode ergibt einen ziemlich guten Effekt. Zu einem großen Teil kann man die lauten Regionen loswerden.

Segmentierung mit einem Algorithmus für ein Modell mit einem Lehrer


Thresholding ist ein sehr einfacher Segmentierungsprozess, der bei kontrastreichen Bildern, für die wir erweiterte Tools benötigen, nicht ordnungsgemäß funktioniert.

In diesem Abschnitt verwenden wir ein Beispielbild, das frei verfügbar ist, und versuchen, den Kopfteil mithilfe von Methoden mit dem Lehrer zu segmentieren.

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



Bevor Sie eine Bildsegmentierung durchführen, wird empfohlen, mit einigen Filtern Rauschen zu entfernen.

In unserem Fall weist das Bild jedoch kein signifikantes Rauschen auf, sodass wir es so akzeptieren, wie es ist. Der nächste Schritt besteht darin, das Bild mit rgb2gray in Graustufen zu konvertieren.

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



Wir werden zwei Segmentierungsmethoden verwenden, die nach völlig unterschiedlichen Prinzipien arbeiten.

Aktive Kontursegmentierung


Die Segmentierung des aktiven Pfads wird auch als Schlange bezeichnet und mithilfe eines benutzerdefinierten Pfads oder einer benutzerdefinierten Linie um einen interessierenden Bereich initialisiert. Anschließend wird dieser Pfad langsam komprimiert und durch Licht und Kanten angezogen oder abgestoßen.

Zeichnen wir für unser Beispielbild einen Kreis um den menschlichen Kopf, um die Schlange zu initialisieren.

 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] 

Die obigen Berechnungen berechnen die x- und y-Koordinaten der Punkte am Umfang des Kreises. Da wir eine Auflösung von 200 angegeben haben, werden 200 solcher Punkte berechnet.

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



Der Algorithmus segmentiert dann das Gesicht der Person vom Rest des Bildes und passt eine geschlossene Kurve an die Ränder des Gesichts an.



Wir können Parameter namens Alpha und Beta konfigurieren. Höhere Alpha-Werte führen dazu, dass sich die Kurve schneller zusammenzieht, während Beta die Kurve glatter macht.

 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); 



Random Walker Segmentierung


Bei dieser Methode erfolgt die Segmentierung mithilfe einer interaktiven Beschriftung, die als Beschriftungen bezeichnet wird. Indem Sie jedes Pixel auf das Etikett zeichnen, für das die höchste Wahrscheinlichkeit berechnet wird, erhalten Sie eine qualitativ hochwertige Bildsegmentierung. Weitere Details zu dieser Methode finden Sie in dieser Arbeit.

Als nächstes werden wir wieder die vorherigen Werte aus unserem Beispiel verwenden. Wir hätten verschiedene Initialisierungen durchführen können, aber der Einfachheit halber bleiben wir beim Prinzip der Kreise.

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

Der Random-Pass-Algorithmus akzeptiert Beschriftungen als Eingabe. Somit haben wir einen großen Kreis, der das gesamte Gesicht der Person bedeckt, und einen weiteren kleineren Kreis nahe der Mitte des Gesichts.

 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); 


Verwenden wir nun Random Walker und sehen, was passiert.

 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); 



Das Ergebnis ist nicht das beste, die Ränder des Gesichts blieben unerreicht. Um diese Situation zu korrigieren, können wir den Durchgangsparameter anpassen, bis wir das gewünschte Ergebnis erhalten. Nach mehreren Versuchen haben wir den Wert auf 3000 gesetzt, was recht gut funktioniert.

 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); 



Dies ist alles für die Segmentierung mit dem Lehrer, wo wir bestimmte Eingabedaten bereitstellen und einige Parameter konfigurieren mussten. Es ist jedoch nicht immer möglich, dass eine Person das Bild betrachtet und dann entscheidet, welchen Beitrag sie leisten soll und wo sie anfangen soll. Glücklicherweise haben wir für solche Situationen unkontrollierte Segmentierungsmethoden.

Segmentierung ohne Lehrer


Für die Segmentierung ohne Lehrer sind keine Vorkenntnisse erforderlich. Stellen Sie sich ein Bild vor, das so groß ist, dass nicht alle Pixel gleichzeitig angezeigt werden können. In solchen Fällen kann die Segmentierung ohne Lehrer das Bild in mehrere Unterregionen aufteilen, sodass Sie anstelle von Millionen von Pixeln Dutzende oder Hunderte von Bereichen haben. Schauen wir uns zwei solcher Algorithmen an:

Einfaches lineares iteratives Clustering


Die Methode (English Simple Linear Iterative Clustering oder SLIC) verwendet einen Algorithmus für maschinelles Lernen namens K-Means. Es nimmt alle Pixelwerte des Bildes und versucht, sie in eine bestimmte Anzahl von Subdomänen zu unterteilen. Lesen Sie diese Arbeit für detaillierte Informationen.

SLIC arbeitet mit verschiedenen Farben, daher verwenden wir das Originalbild.

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

Alles, was wir tun müssen, ist einfach einen Durchschnittswert für jedes Segment festzulegen, das wir finden, wodurch es eher wie ein Bild aussieht.

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



Wir haben dieses Bild von 512 * 512 = 262.000 Pixel auf 155 Segmente reduziert.

Felzenszwalb


Diese Methode verwendet auch einen Algorithmus für maschinelles Lernen, der als Minimum-Spanning-Tree-Clustering bezeichnet wird. Felzenszwaib gibt nicht die genaue Anzahl der Cluster an, in die das Bild unterteilt wird. Er wird so viele Cluster generieren, wie er dafür für richtig hält.

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



Es gibt zu viele Regionen im Bild. Zählen wir die Anzahl der eindeutigen Segmente.

 np.unique(image_felzenszwalb).size 3368 

Lassen Sie uns sie nun mit dem Durchschnittswert über dem Segment neu einfärben, wie wir es im SLIC-Algorithmus getan haben.

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

Jetzt bekommen wir weniger Segmente. Wenn wir noch weniger Segmente wollen, können wir den Skalierungsparameter ändern. Dieser Ansatz wird manchmal als Über-Segmentierung bezeichnet.



Dies ähnelt eher einem posterisierten Bild, bei dem es sich im Wesentlichen nur um eine Verringerung der Anzahl der Farben handelt. Um sie wieder zu kombinieren (RAG).

Fazit


Die Bildsegmentierung ist ein sehr wichtiger Schritt in der Bildverarbeitung. Dies ist ein aktives Forschungsgebiet mit einer Vielzahl von Anwendungen, die von Computer Vision über medizinische Bilder bis hin zu Verkehrs- und Videoüberwachung reichen. Python bietet eine robuste Scikit-Bildbibliothek mit einer Vielzahl von Bildverarbeitungsalgorithmen. Es ist kostenlos und ohne Einschränkungen verfügbar und wird von einer aktiven Community unterstützt. Ich empfehle Ihnen, die Dokumentation zu lesen. Den Originalartikel finden Sie hier .

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


All Articles