Auswahl von Merkmalen#
Bei der Auswahl der richtigen Merkmale gibt es einige Faustregeln, die man berücksichtigen kann. Zum Beispiel sollten kleine Radius- / Sigma-Werte verwendet werden, wenn man Objekte sehr präzise segmentieren möchte. Wenn eine grobe Kontur ausreicht oder einzelne Pixel an den Objektgrenzen eliminiert werden sollen, ist es sinnvoll, größere Radius- und Sigma-Werte zu verwenden. Dieses Thema kann jedoch auch mit Hilfe von Statistiken angegangen werden.
from skimage.io import imread, imsave
import pyclesperanto_prototype as cle
import numpy as np
import apoc
import matplotlib.pyplot as plt
import pandas as pd
image = imread('../../data/blobs.tif')
manual_annotation = imread('../../data/blobs_annotations.tif')
fig, axs = plt.subplots(1,2)
cle.imshow(image, plot=axs[0])
cle.imshow(manual_annotation, labels=True, plot=axs[1])
Training - mit zu vielen Merkmalen#
Wir trainieren jetzt einen Objektsegmentierer und stellen viele Merkmale zur Verfügung. Wir müssen auch Parameter angeben, um tiefe Entscheidungsbäume und viele Bäume zu konfigurieren. Dies ist notwendig, damit die nächsten Schritte, die Ableitung von Statistiken, genügend statistische Aussagekraft haben. Anschließend werfen wir einen Blick auf das Ergebnis für eine schnelle Plausibilitätsprüfung.
# define features
features = apoc.PredefinedFeatureSet.small_dog_log.value + " " + \
apoc.PredefinedFeatureSet.medium_dog_log.value + " " + \
apoc.PredefinedFeatureSet.large_dog_log.value
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter2.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=5,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
Klassifikatorstatistiken#
Nach dem Training können wir einige Statistiken des Klassifikators ausgeben. Es gibt uns eine Tabelle der verwendeten Merkmale und wie wichtig die Merkmale für die Entscheidung der Pixelklassifikation waren.
shares, counts = classifier.statistics()
def colorize(styler):
styler.background_gradient(axis=None, cmap="rainbow")
return styler
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
original | 0.138000 | 0.046423 | 0.042312 | 0.037281 | 0.062112 |
gaussian_blur=1 | 0.228000 | 0.092846 | 0.074303 | 0.105263 | 0.055901 |
difference_of_gaussian=1 | 0.000000 | 0.108828 | 0.095975 | 0.074561 | 0.086957 |
laplace_box_of_gaussian_blur=1 | 0.000000 | 0.105784 | 0.089783 | 0.081140 | 0.099379 |
gaussian_blur=5 | 0.096000 | 0.064688 | 0.118679 | 0.096491 | 0.130435 |
difference_of_gaussian=5 | 0.254000 | 0.182648 | 0.112487 | 0.120614 | 0.118012 |
laplace_box_of_gaussian_blur=5 | 0.209000 | 0.194064 | 0.121775 | 0.118421 | 0.124224 |
gaussian_blur=25 | 0.004000 | 0.061644 | 0.113519 | 0.127193 | 0.080745 |
difference_of_gaussian=25 | 0.032000 | 0.072298 | 0.122807 | 0.127193 | 0.130435 |
laplace_box_of_gaussian_blur=25 | 0.039000 | 0.070776 | 0.108359 | 0.111842 | 0.111801 |
In dieser Visualisierung sehen Sie, dass die Merkmale gaussian_blur=1
, difference_of_gaussian=5
und laplace_box_of_gaussian_blur=5
etwa 65% der Entscheidung ausmachen. Auf der ersten Ebene (Ebene 0
). Wenn diese drei Merkmale entscheidend sind, können wir einen weiteren Klassifikator trainieren, der nur diese Merkmale berücksichtigt. Außerdem sehen wir, dass der Anteil der Merkmale auf den oberen drei Tiefenebenen gleichmäßiger verteilt ist. Diese Ebenen machen möglicherweise keinen großen Unterschied bei der Klassifizierung von Pixeln. Den nächsten Klassifikator, den wir trainieren, können wir mit niedrigerem max_depth
trainieren.
# define features
features = "gaussian_blur=1 difference_of_gaussian=5 laplace_box_of_gaussian_blur=5"
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter3.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=3,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
Der neue Klassifikator produziert immer noch ein sehr ähnliches Ergebnis. Er berücksichtigt weniger Merkmale, was ihn schneller macht, aber möglicherweise auch weniger robust gegenüber Unterschieden zwischen Bildern und Aufnahmebedingungen. Wir werfen noch einen Blick auf die Klassifikatorstatistiken:
shares, counts = classifier.statistics()
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
0 | 1 | 2 | |
---|---|---|---|
gaussian_blur=1 | 0.331000 | 0.349194 | 0.344620 |
difference_of_gaussian=5 | 0.356000 | 0.329839 | 0.337096 |
laplace_box_of_gaussian_blur=5 | 0.313000 | 0.320968 | 0.318284 |
Zu Demonstrationszwecken werden wir nun einen weiteren Klassifikator mit sehr ähnlichen Merkmalen trainieren.
# define features
features = "gaussian_blur=1 difference_of_gaussian=2 difference_of_gaussian=3 difference_of_gaussian=4 difference_of_gaussian=5 difference_of_gaussian=6 laplace_box_of_gaussian_blur=5"
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter3.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=3,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
Auch hier sieht das Segmentierungsergebnis sehr ähnlich aus, aber die Klassifikatorstatistik ist anders.
shares, counts = classifier.statistics()
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
0 | 1 | 2 | |
---|---|---|---|
gaussian_blur=1 | 0.200000 | 0.093750 | 0.162829 |
difference_of_gaussian=2 | 0.000000 | 0.120888 | 0.148026 |
difference_of_gaussian=3 | 0.053000 | 0.064967 | 0.125000 |
difference_of_gaussian=4 | 0.236000 | 0.162829 | 0.097039 |
difference_of_gaussian=5 | 0.178000 | 0.222862 | 0.125822 |
difference_of_gaussian=6 | 0.134000 | 0.120066 | 0.194901 |
laplace_box_of_gaussian_blur=5 | 0.199000 | 0.214638 | 0.146382 |
Auf diese Weise kann man auch die Radius- und Sigma-Parameter, die man für die angegebenen Merkmale verwenden muss, feinjustieren.
Die in diesem Abschnitt gegebenen Hinweise sind keine festen Regeln für die Auswahl der richtigen Merkmale. Die bereitgestellten Tools können jedoch helfen, etwas hinter die Merkmale zu blicken und den Einfluss der bereitgestellten Merkmalslisten und Parameter zu messen.