Matching labels

This script will compare two labelled images and convert the assigned labels in one image to resemble the labels in the first image.

[9]:
import os
import biapol_utilities as biau
from skimage import io, measure, filters
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
from functools import partial

%matplotlib notebook

Load data

First, we load the example blobs image and threshold it to create a label map.

[2]:
blobs = biau.data.blobs()
[3]:
threshold = 128
imageA = (blobs > threshold).astype(np.uint8)
imageA_labelled = measure.label(imageA)

plt.imshow(imageA_labelled)
[3]:
<matplotlib.image.AxesImage at 0x1e888c095e0>

Let’s create a second version of this image in which we shuffle the labels:

[4]:
label_shuffle = np.arange(1, imageA_labelled.max()+1, 1)
np.random.shuffle(label_shuffle)
label_shuffle = np.append(np.asarray([0]), label_shuffle)  # append 0 at start of array - we don't want to shuffle background

imageB_labelled = label_shuffle[imageA_labelled]

Both images are not identical!

[5]:
fig, axes = plt.subplots(ncols=2, sharex=True, sharey=True)
axes[0].imshow(imageA_labelled)
axes[0].set_title('Reference image')
axes[1].imshow(imageB_labelled)
axes[1].set_title('Shuffled image')

print(f'Number of labels in imageA: {imageA_labelled.max()}')
print(f'Number of labels in imageB: {imageB_labelled.max()}')
Number of labels in imageA: 63
Number of labels in imageB: 63

Label-matching

Next, we can run the label matching. Biapol-utilities divides this process in three steps: - Calculating the similarity between labels in the form of a similarity matrix M - Filtering entries in M - Matching labels from two images based on the remaining entries in M

Default behaviour

Biapol utilites uses the following default approaches for these steps: - Calculating similarity: Intersection over union between all labels - Filtering entries in M: All entries between a default threshold (0.25) are set to zero. - Matching labels: Labels with maximal similarity are matched.

The default procedure can be called using:

[12]:
output = biau.label.match_labels(imageA_labelled, imageB_labelled)

Custom behaviour

Next, we specify the methods used for each step:

[13]:
metric_method = biau.label.intersection_over_union_matrix
filter_method = biau.label.suppressed_similarity
matching_method = biau.label.max_similarity

Now, these functions can be passed as arguments to the label matching function:

[14]:
output = biau.label.match_labels(imageA_labelled, imageB_labelled,
                                metric_method=metric_method,
                                filter_method=filter_method,
                                matching_method=matching_method)

Note: Some of these argument functions have optional keyword arguments. For instance, suppressed_similarity will - as the name suggests - suppress entries in the similarity matrix M that fall below a certain threshold, that defaults to 0.25. This may not be appropriate for some problems. In order to change the default behaviour, you can customize the suppression function as follows:

[15]:
customized_filter_method = partial(biau.label.suppressed_similarity, threshold=0.1)

# Pass the new function to match_labels():
output = biau.label.match_labels(imageA_labelled, imageB_labelled,
                                metric_method=metric_method,
                                filter_method=customized_filter_method,
                                matching_method=matching_method)

Visualize the result:

[16]:
fig, axes = plt.subplots(ncols=2, sharex=True, sharey=True)
axes[0].imshow(imageA_labelled)
axes[0].set_title('Reference image')
axes[1].imshow(output)
axes[1].set_title('Relabelled image')
[16]:
Text(0.5, 1.0, 'Relabelled image')