Reputation: 213
I have a set of 480 original images and 480 labels (one for each original) that have been segmented and labelled via a Watershed process. I use the labels, labels_ws
, when looking for the mean intensity of various regions in the original images, original_images
. These images form a time-series and I am looking to track the mean intensity in each labelled region of this time-series.
Finding the mean intensity of the regions in a single image is pretty easily done in scikit-image using the following code:
regions = measure.regionprops(labels_ws, intensity_image = original_image)
print(["(%s, %s)" % (r, r.mean_intensity) for r in regions])
which prints a whole lot of output that looks like this:
'(skimage.measure._regionprops._RegionProperties object at 0x000000000E5F3F98, 35.46153846153846)',
'(skimage.measure._regionprops._RegionProperties object at 0x000000000E5F3FD0, 47.0)',
'(skimage.measure._regionprops._RegionProperties object at 0x000000000E7B6048, 49.96666666666667)',
'(skimage.measure._regionprops._RegionProperties object at 0x000000000E7B6080, 23.0)',
'(skimage.measure._regionprops._RegionProperties object at 0x000000000E7B60B8, 32.1)',
Each image probably has around 100-150 regions. The regions are areas in the image where there is a neuron luminescing in a tissue sample during the time the image was taken. As the time-series goes on, the regions (neurons) luminesce in a periodic manner and thus the intensity data for each region should look like a periodic function.
The problem I am having is that in each successive image, the labels / regions are slightly different as the luminescence in each region follows its periodic behaviour. Thus, labels / regions "pop-in/out" over the duration of the time series. I also can't guarantee that the size of, let's say, Region_1 when it first luminesces will be the same size as it is when it luminesces for a second or third time (however any difference is slight, just a couple of pixels).
All of that said, is there a way to combine all of my labels in some way to form a single label that I can track? Should I combine all of the original images in some way then create a master label? How do I handle regions that will definitely overlap, but might be different shapes / sizes by a couple of pixels? Thanks!
Upvotes: 1
Views: 2040
Reputation: 1
""" Created on %(date)s
@author: %(Ahmed Islam ElManawy)s [email protected] """
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import cv2
from skimage.measure import label, regionprops
from sklearn.cluster import KMeans
import numpy as np
## import image
img=cv2.imread('E:\\Data\\Arabidopsis Thaliana HSI image\\20170508\\binarry\\AQC_RT.jpg',1)
## lablelled image
label_image = label(img[:,:,0])
## combined image center using k-means
Center=[]
Box=[]
for region in regionprops(label_image):
# take regions with large enough areas
if region.area >= 10:
# draw rectangle around segmented coins
Box.append(region.bbox)
Center.append(region.centroid)
Center=np.asarray(Center)
Box=np.asarray(Box)
kmeans=KMeans(n_clusters=12, random_state=0).fit(Center)
label=kmeans.labels_
## plot image with different area
fig, ax = plt.subplots(figsize=(10, 6))
ax.imshow(img)
for l in label:
h=np.where(label==l)
B=Box[h,:]
B=B[0,:,:]
minr, minc, maxr, maxc =np.min(B[:,0]), np.min(B[:,1]), np.max(B[:,2]), np.max(B[:,3])
# plt.imshow(img2[11:88, 2:94,:])
rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr,
fill=False, edgecolor='red', linewidth=2)
ax.add_patch(rect)
ax.set_axis_off()
plt.tight_layout()
plt.show()
Upvotes: 0
Reputation: 356
I had a similar problem where I wanted to track changing segmented regions over time. My solution is to change all the labels in every image at the center point of each segmented region. This has the effect of propagating the labels through to all the other images.
Of course, this assumes that the regions stay in roughly the same place throughout
You can see the difference in the animation: on the left the labels are constantly changing and on the right they stay consistent. It works despite the missing frames and shifting regions
Animation link: https://i.sstatic.net/0BIda.jpg (I don't have enough rep to post the image directly)
Just send your list of segmented and labelled images to standardise_labels_timeline
def standardise_labels_timeline(images_list, start_at_end = True, count_offset = 1000):
"""
Replace labels on similar images to allow tracking over time
:param images_list: a list of segmented and lablled images as numpy arrays
:param start_at_end: relabels the images beginning at the end of the list
:param count_offset: an int greater than the total number of expected labels in a single image
:returns: a list of relablled images as numpy arrays
"""
import numpy as np
images = list(images_list)
if start_at_end:
images.reverse()
# Relabel all images to ensure there are no duplicates
for image in images:
for label in np.unique(image):
if label > 0:
count_offset += 1
image[image == label] = count_offset
# Ensure labels are propagated through image timeline
for i, image in enumerate(images):
labels = get_labelled_centers(image)
# Apply labels to all subsequent images
for j in range(i, len(images)):
images[j] = replace_image_point_labels(images[j], labels)
if start_at_end:
images.reverse()
return images
def get_labelled_centers(image):
"""
Builds a list of labels and their centers
:param image: a segmented and labelled image as a numpy array
:returns: a list of label, co-ordinate tuples
"""
from skimage.measure import regionprops
# Find all labelled areas, disable caching so properties are only calculated if required
rps = regionprops(image, cache = False)
return [(r.label, r.centroid) for r in rps]
def replace_image_point_labels(image, labels):
"""
Replace the labelled at a list of points with new labels
:param image: a segmented and lablled image as a numpy array
:param labels: a list of label, co-ordinate tuples
:returns: a relabelled image as a numpy array
"""
img = image.copy()
for label, point in labels:
row, col = point
# Find the existing label at the point
index = img[int(row), int(col)]
# Replace the existing label with new, excluding background
if index > 0:
img[img == index] = label
return img
Upvotes: 1