0

I am looking to measure the minimum and maximum diameter of multiple particles (groups) in a TIFF image.

This is my current code:

from PIL import Image
import numpy as np
from skimage import measure
import os 
import pandas as pd
import warnings; warnings.filterwarnings(action='once')

dirname1 = path
final1 = []

for fname in os.listdir(dirname1):
    im = Image.open(os.path.join(dirname1, fname))
    imarray = np.array(im)
    final1.append(imarray) 

final1 = np.asarray(final1)

groups, group_count = measure.label(final1 == 0, return_num = True, connectivity = 2)

print('Groups: \n', groups)
print(f'Number of particles: {group_count}')
 
df1 = (pd.DataFrame(dict(zip(['Particle #', 'Size [pixel #]'],
                            np.unique(groups, return_counts=True))))
        .loc[lambda d: d['Particle #'].ne(0)] 
     )
df1.index -= 1

props = measure.regionprops_table(groups, properties = ['label', 'equivalent_diameter'])
df1_new = pd.DataFrame(props)

My TIFF image looks like this: Image example (I normally work with multiple TIFF images)

In my code, I have used skimage to calculate the equivalent diameter. However, I need the min/max Feret diameter in the df1 DataFrame as well.

Thank you.

Claudio
  • 7,474
  • 3
  • 18
  • 48
Frede
  • 3
  • 2

1 Answers1

0

If you change the last two lines in your code to:

props = measure.regionprops_table(groups[0], properties = ['label', 'equivalent_diameter', 'axis_major_length', 'axis_minor_length' ])
props['equiv_dia'] = props['equivalent_diameter'] ; props.pop('equivalent_diameter')
props['min_feret'] = props['axis_minor_length'  ] ; props.pop('axis_minor_length'  )
props['max_feret'] = props['axis_major_length'  ] ; props.pop('axis_major_length'  )
df1_new = pd.DataFrame(props)
print(df1_new)

You will get for the following image:

Particles

as output:

   label  equiv_dia  min_feret  max_feret
0      1   2.580762   0.000000   3.651484
1      2  10.802272   3.651484  26.226566
2      3   3.059832   2.000000   3.651484
3      4   3.578801   3.096570   4.195087
4      5   5.497605   3.651484   8.032033

The changes to your code are solving following issues:

  • Error message because of bad array shapes
  • Lack of columns for feret values in the dataframe

The measure.regionprops_table() method comes with 'axis_major_length', 'axis_minor_length' options for the calculated properties which seem to be be equivalent to the min/max Feret values.

If you are not satisfied with the values this properties provide (I'm not) I suggest to decide which other tool you want to use for this calculation to obtain the values satisfying your needs what is maybe worth to ask another question about calculating Feret values.

As I created the tag feret-values you can use it along with python in a new question about differences in the values of min/max Feret calculated by different Python scripts/modules.

I have myself checked out 'RegionProperties' object has no attribute 'feret_diameter_max' , but the Feret property in scikit throws an Error.

Claudio
  • 7,474
  • 3
  • 18
  • 48
  • Thank you for your response. With your code, I still only get the equivalent diameter, and I was looking for the Feret diameter (minimum and maximum diameter of each group) printed alongside the equivalent diameter. – Frede Sep 06 '22 at 12:23
  • I have updated my answer adding columns with Feret values to the pandas table. – Claudio Sep 06 '22 at 20:33
  • Thank you for your help. I'll look further into the Feret calculations. – Frede Sep 07 '22 at 11:08
  • I have looked already a bit into calculations of Feret values. It appears to be a mess with the advice to extract only one particle from the array and use the `feret` module which currently doesn't work on images with multiple objects to calculate the values. It;s just a loop over setting all other label values except one to zero and probably worth it if it is true that the feret module is the only solution giving reasonable results like max. Feret near the circle diameter and the min Feret value as expected by looking at the particle contour. – Claudio Sep 07 '22 at 12:46