Trailer: Biobildanalyse mit Python#

In den folgenden Kapiteln werden wir uns in die Bildanalyse, maschinelles Lernen und Biostatistik mit Python vertiefen. Dieses erste Notebook dient als Vorschau auf das, was wir machen werden.

Python-Notebooks beginnen typischerweise mit den Importen der Python-Bibliotheken, die das Notebook verwenden wird. Der Leser kann zunächst überprüfen, ob all diese Bibliotheken installiert sind, bevor er das gesamte Notebook durchgeht.

import numpy as np
from skimage.io import imread, imshow
import pyclesperanto_prototype as cle
from skimage import measure
import pandas as pd
import seaborn
import apoc
import stackview

Arbeiten mit Bilddaten#

Wir beginnen mit dem Laden der interessierenden Bilddaten. In diesem Beispiel laden wir ein Bild, das ein Zebrafischauge zeigt, mit freundlicher Genehmigung von Mauricio Rocha Martins, Norden-Labor, MPI CBG Dresden.

# open an image file
multichannel_image = imread("../../data/zfish_eye.tif")

# extract a channel
single_channel_image = multichannel_image[:,:,0]

cropped_image = single_channel_image[200:600, 500:900]

stackview.insight(cropped_image)
shape(400, 400)
dtypeuint16
size312.5 kB
min9187
max57619

Bildfilterung#

Ein üblicher Schritt bei der Arbeit mit Fluoreszenz-Mikroskopiebildern ist das Subtrahieren der Hintergrundintensität, z.B. resultierend aus unfokussiertem Licht. Dies kann die Bildsegmentierungsergebnisse weiter unten im Workflow verbessern.

# subtract background using a top-hat filter
background_subtracted_image = cle.top_hat_box(cropped_image, radius_x=20, radius_y=20)

stackview.insight(background_subtracted_image)
shape(400, 400)
dtypefloat32
size625.0 kB
min0.0
max40758.0

Bildsegmentierung#

Für die Segmentierung der Zellkerne im gegebenen Bild existiert eine enorme Anzahl von Algorithmen. Hier verwenden wir einen klassischen Ansatz namens Voronoi-Otsu-Labeling, der sicherlich nicht perfekt ist.

label_image = np.asarray(cle.voronoi_otsu_labeling(background_subtracted_image, spot_sigma=4))

# show result
stackview.insight(label_image)
shape(400, 400)
dtypeuint32
size625.0 kB
min0
max113

Messungen und Merkmalsextraktion#

Nachdem das Bild segmentiert ist, können wir Eigenschaften der einzelnen Objekte messen. Diese Eigenschaften sind typischerweise beschreibende statistische Parameter, die als Merkmale bezeichnet werden. Wenn wir Messungen wie die Fläche oder die mittlere Intensität ableiten, extrahieren wir diese beiden Merkmale.

statistics = measure.regionprops_table(label_image, 
                                       intensity_image=cropped_image,
                                       properties=('area', 'mean_intensity', 'major_axis_length', 'minor_axis_length'))

Arbeiten mit Tabellen#

Das oben erstellte statistics-Objekt enthält eine Python-Datenstruktur, ein Wörterbuch von Messvektoren, was nicht am intuitivsten zu betrachten ist. Daher konvertieren wir es in eine Tabelle. Datenwissenschaftler nennen diese Tabellen oft DataFrames, die in der pandas-Bibliothek verfügbar sind.

dataframe = pd.DataFrame(statistics)

Wir können bestehende Tabellenspalten verwenden, um andere Messungen zu berechnen, wie zum Beispiel das aspect_ratio.

dataframe['aspect_ratio'] = dataframe['major_axis_length'] / dataframe['minor_axis_length']
dataframe
area mean_intensity major_axis_length minor_axis_length aspect_ratio
0 294.0 36604.625850 25.656180 18.800641 1.364644
1 91.0 37379.769231 20.821990 6.053507 3.439658
2 246.0 44895.308943 21.830827 14.916032 1.463581
3 574.0 44394.637631 37.788705 19.624761 1.925563
4 518.0 45408.903475 26.917447 24.872908 1.082199
... ... ... ... ... ...
108 568.0 48606.121479 37.357606 19.808121 1.885974
109 175.0 25552.074286 17.419031 13.675910 1.273702
110 460.0 39031.419565 26.138592 23.522578 1.111213
111 407.0 39343.292383 28.544027 19.563792 1.459023
112 31.0 29131.322581 6.892028 5.711085 1.206781

113 rows × 5 columns

Plotten#

Messungen können mithilfe von Diagrammen visualisiert werden.

seaborn.scatterplot(dataframe, x='area', y='aspect_ratio', hue='mean_intensity')
<Axes: xlabel='area', ylabel='aspect_ratio'>
../_images/71d9c84c2d15b34f1dc3efd56d1a0e3c84a014919773a42233fb8eb4e1e81e8c.png

Deskriptive Statistik#

Ausgehend von dieser Tabelle können wir Statistiken verwenden, um einen Überblick über die gemessenen Daten zu erhalten.

mean_area = np.mean(dataframe['area'])
stddev_area = np.std(dataframe['area'])

print("Die durchschnittliche Zellkernfläche beträgt", mean_area, "+-", stddev_area, "Pixel")
Mean nucleus area is 524.4247787610619 +- 231.74703195433014 pixels

Klassifizierung#

Für ein besseres Verständnis der internen Struktur von Geweben, aber auch zur Korrektur von Artefakten in Bildverarbeitungs-Workflows, können wir Zellen klassifizieren, zum Beispiel nach ihrer Größe und Form.

object_classifier = apoc.ObjectClassifier('../../data/blobs_classifier.cl')
classification_image = object_classifier.predict(label_image, cropped_image)

stackview.imshow(classification_image)
../_images/9eb932b75812af467ae3296805cf085446de849a71b945e996d3e6af2dc363dc.png