Schwellenwertverfahren#

Schwellenwertverfahren ist eine Technik der Bildsegmentierung. Es trennt ein gegebenes Einzelkanal-Bild (oder einen Stapel) in zwei Bereiche: Pixel mit Intensität unterhalb eines gegebenen Schwellenwerts, auch “Hintergrund” genannt, und Pixel mit Intensität oberhalb eines gegebenen Schwellenwerts, “Vordergrund”. Typischerweise resultieren diese Algorithmen in Binärbildern, bei denen die Hintergrundintensität 0 und die Vordergrundintensität 1 ist. Bei der Anwendung solcher Algorithmen in ImageJ haben Vordergrundpixel den Wert 255. In scikit-image sind Hintergrundpixel False und Vordergrundpixel True.

Siehe auch

from skimage.io import imread
from pyclesperanto_prototype import imshow
import pyclesperanto_prototype as cle

from skimage import filters
from skimage.filters import try_all_threshold
from matplotlib import pyplot as plt
import napari_simpleitk_image_processing as nsitk
image = imread("../../data/blobs.tif")
imshow(image)
../_images/697332ed931701bd777704b279b47e121b548544b81f7a635c3783b21c04fb53.png

Bildsegmentierung durch Schwellenwertverfahren#

Die threshold_otsu Operation, auch bekannt als Otsu’s Methode (Otsu et al., IEEE Transactions on Systems, Man, and Cybernetics, Vol. 9 (1), 1979), liefert eine Zahl - den anzuwendenden Schwellenwert.

threshold = filters.threshold_otsu(image)

Bei der Verwendung von Methoden wie Schwellenwertverfahren in Notebooks wird empfohlen, das Ergebnis auszugeben, um zu sehen, was es tatsächlich zurückgibt. Hier verwenden wir die Methode von scikit-image, die den anzuwendenden Schwellenwert zurückgibt. Das Ausdrucken dieses Schwellenwerts kann später bei der Reproduktion des Workflows hilfreich sein, auch wenn andere den gleichen Schwellenwert auf den Datensatz in anderer Software anwenden möchten.

threshold
120

Mit numpy-Arrays können wir den Schwellenwert anwenden, indem wir den >=-Operator verwenden. Das Ergebnis wird ein Binärbild sein.

binary_image = image >= threshold

imshow(binary_image)
../_images/a7b2159f4f800a1618c3d6082c124079d4f7e3116111a1a4a4a67982e4eecc1e.png

Wir können auch bestimmen, in welchem Typ das Binärbild verarbeitet wird, indem wir Minimum und Maximum des Bildes ausgeben:

binary_image.max()
True
binary_image.min()
False

Wie bereits gezeigt, erlaubt uns matplotlib, eine Kontur auf ein mit imshow visualisiertes Bild zu zeichnen, indem wir den contour-Befehl verwenden.

# Erstelle einen neuen Plot
fig, axes = plt.subplots(1,1)

# Füge zwei Bilder hinzu
axes.imshow(image, cmap=plt.cm.gray)
axes.contour(binary_image, [0.5], linewidths=1.2, colors='r')
<matplotlib.contour.QuadContourSet at 0x2b57076dc70>
../_images/06c7022a7454d1160b496fab99037089bf65b12b028c885551cc71daf820b4ae.png

Es gibt eine Liste von Schwellenwert-Algorithmen. Es ist möglich, sie alle auf Ihre Daten anzuwenden und die Unterschiede zu sehen:

fig, ax = try_all_threshold(image, figsize=(10, 8), verbose=False)
plt.show()
../_images/a5bde9d6498b8293b645bd6971e1c424b09bc31486fc161743a8bd2a4341cf99.png

Schwellenwertverfahren mit pyclesperanto#

Darüber hinaus bieten auch andere Bibliotheken wie pyclesperanto Schwellenwert-Algorithmen an. Die Implementierung hier gibt nicht den Schwellenwert zurück, sondern direkt das Binärbild.

binary_image2 = cle.threshold_otsu(image)
imshow(binary_image2)
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png

Hier können wir auch sehen, dass verschiedene Bibliotheken Binärbilder auf unterschiedliche Weise speichern. pyclesperanto speichert zum Beispiel die positiven Pixel in Binärbildern nicht als True, sondern stattdessen mit einer 1:

binary_image2.max()
1.0
binary_image2.min()
0.0

Schwellenwertverfahren mit SimpleITK#

Auch SimpleITK bietet Schwellenwert-Algorithmen, die in der Liste der Filter zu finden sind. Für die Skript-Bequemlichkeit verwenden wir hier napari-simpleitk-image-processing, ein skriptbares napari-Plugin, das einige SimpleITK-Funktionen auf zugänglichere Weise anbietet. Wir können eine kleine Schleife programmieren, die alle Schwellenwert-Algorithmen in SimpleITK ausprobiert und uns die Ergebnisse zeigt:

threshold_algorithms = [
    nsitk.threshold_huang,
    nsitk.threshold_intermodes,
    nsitk.threshold_isodata,
    nsitk.threshold_kittler_illingworth,
    nsitk.threshold_li,
    nsitk.threshold_maximum_entropy,
    nsitk.threshold_moments,
    nsitk.threshold_otsu,
    nsitk.threshold_renyi_entropy,
    nsitk.threshold_shanbhag,
    nsitk.threshold_triangle,
    nsitk.threshold_yen
]

for algorithm in threshold_algorithms:
    # Zeige den Namen des Algorithmus über dem Bild
    print(algorithm.__name__)
    
    # Binarisiere das Bild mit dem gegebenen Algorithmus
    binary_image = algorithm(image)
    
    # Zeige das Segmentierungsergebnis
    imshow(binary_image)
threshold_huang
../_images/45e3c8efd769b88b4fc58e4d5c1a50a912d9366ec57f499833c7d4818a16d68f.png
threshold_intermodes
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_isodata
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_kittler_illingworth
../_images/8d4c59070474247eb02c19ca4d21208dca15778cc0c5e13fadd3e195e8885ce0.png
threshold_li
../_images/ea3d20faef42e8488598e1c914b90d031aefa3b733b82e7d5690f7cbfac67525.png
threshold_maximum_entropy
../_images/a7b2159f4f800a1618c3d6082c124079d4f7e3116111a1a4a4a67982e4eecc1e.png
threshold_moments
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_otsu
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png
threshold_renyi_entropy
../_images/fccedafce8680667fc01673c4f353031a8b0ce3a2762337531c13b06b405af7e.png
threshold_shanbhag
../_images/507204442c9b905ad28921ef50996a9879695302aaa3686ab31ef89b2579de14.png
threshold_triangle
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png
threshold_yen
../_images/134aa11339889cf89aba337af18d894502fe56f28ac0dc73bc0e4d0d8af43abe.png

Übung#

Segmentieren Sie blobs.tif mit dem Yen-Algorithmus. Verwenden Sie matplotlib, um eine grüne Kontur der segmentierten Objekte um die Regionen auf dem Originalbild zu zeichnen.

Segmentieren Sie das Bild mit einem berechneten Schwellenwert gemäß dieser Gleichung:

threshold = mean + 2 * standard_deviation

Visualisieren Sie das resultierende Segmentierungsergebnis mit einer roten Kontur auf dem Originalbild und der grünen Kontur von oben.

Alternativ können Sie beide Segmentierungsergebnisse in napari einfügen und dort visuell vergleichen.