alan-turing-institute / pixelflow

BSD 3-Clause "New" or "Revised" License
5 stars 4 forks source link

Output intensity_image for each label #36

Closed evangeline-corcoran closed 10 months ago

evangeline-corcoran commented 11 months ago

For the seed use case, it would be ideal if the intensity_image for each labelled object in a mask could be automatically saved as a numpy array, and named based on the label number to allow matching between the image + features table values. In this use case the intensity_image gives a segmented array of an individual seed which is useful for further analysis (e.g. VAE, clustering to explore factors affecting seed internal structure).

The segmented image (intensity_image) of a single seed can be created with regionprops and saved as an numpy array as below:

import numpy
import skimage

props = skimage.measure.regionprops(labels[0], img[0], cache=True)

seed_array = props[0].intensity_image
seed_array

numpy.save("/content/gdrive/MyDrive/Example CT Data/C0007864_seed4.npy", seed_array)
IFenton commented 10 months ago

At the moment you should be able to get the image_intensity numpy array by including 'image_intensity' in the features list. If you save the result, you can then access the arrays by using result.image_intensity (rather than result.features for the features dataframe). The individual arrays are not explicitly named, but they are output in the same order as the feature table and can be accessed using indexing. Does that solve your problem for the moment?

evangeline-corcoran commented 10 months ago

Hi Isabel it seems your suggestion works except I need to call result.features.intensity_image as opposed to just result.intensity_image. Also I have found for my use case it is more helpful to save the intensity images separate to the other metrics as below, otherwise it gives me the array values for each intensity_image in each features table row which is quite messy!

So to generate the features and intensity images I need I first run:

#create table of size and shape metrics
features = pixelflow(
    mask,
    img,
    features=('label', 'bbox', 'centroid', 'area', 'equivalent_diameter', 'major_axis_length', 'minor_axis_length', 'orientation', 'solidity'),
    #custom=(custom_func)
)

#generate segmented images of each individual seed in a mask
seg_seed = pixelflow(
    mask,
    img,
    features=('label', 'intensity_image')
)

*Note: 'label' must be included in the list of features or pixelflow will fail to generate the intensity images

In regards to the file names, I've found I can just save seed pod ID number from the original file name e.g. pod_name = '01_Shengliyoucai_main_A'

Then to save a single seed from the original mask/image I run:

#save single seed image
np.save(pod_name + '_seed_' + str(seg_seed.features.label[0]) + '.npy', seg_seed.features.intensity_image[0])

Or to save all individual seed images from a mask I run:

#make list of all seeds in mask, shift backwards by one to match index values
X = list(seg_seed.features.label)
for i in range(len(X)):
    X[i] -= 1

#save segmented images of all seeds within a seed pod
for file in X:
    np.save(pod_name + '_seed_' + str(seg_seed.features.label[file]) + '.npy', seg_seed.features.intensity_image[file])  

As you can see I use the label number from the features table so that the image can be easily linked to the data in the table.

We can then plot a single seed image with

#load and plot single seed image
seed_image = np.load('01_Shengliyoucai_main_A_seed_20.npy') 

fig = plt.imshow(seed_image)

I'm working on getting this working as a loop over multiple files, but otherwise this method works well for my needs.

evangeline-corcoran commented 10 months ago

If there is a way to generate all the features + intensity images with pixelflow at once but avoid the intensity_image arrays being included in the table I need to export as csv I think that would be an improvement, but keeping this separate works fine

evangeline-corcoran commented 10 months ago

A slight correction: As you suggested we can just use results.image_intensity to retrieve the images for each label rather than results.features.intensity_image as shown in the example below

#generate segmented images of each individual seed in a mask
seg_seed = pixelflow(
    mask,
    img,
    features=('label', 'image_intensity')
)

#make list of all seeds in mask, shift backwards by one to match index values
X = list(seg_seed.features.label)
for i in range(len(X)):
    X[i] -= 1

#save segmented images of all seeds within a seed pod
for file in X:
    np.save(pod_name + '_seed_' + str(seg_seed.features.label[file]) + '.npy', seg_seed.image_intensity[file])
IFenton commented 10 months ago

The latest merges mean that the image_intensity can be extracted from both 2D and 3D images as part of a list of features.