# Quantitative image analysis#

After segmenting and labeling objects in an image, we can measure properties of these objects.

Before we can do measurements, we need an image and a corresponding label_image. Therefore, we recapitulate filtering, thresholding and labeling:

from skimage.io import imread
from skimage import filters

from skimage import measure
from pyclesperanto_prototype import imshow

# load image

# denoising
blurred_image = filters.gaussian(image, sigma=1)

# binarization
threshold = filters.threshold_otsu(blurred_image)
thresholded_image = blurred_image >= threshold

# labeling
label_image = measure.label(thresholded_image)

# visualization
imshow(label_image, labels=True)


# Measurements / region properties#

To read out properties from regions, we use the regionprops function:

# analyse objects
properties = measure.regionprops(label_image, intensity_image=image)


The results are stored as RegionProps objects, which are not very informative:

properties[0:5]

[<skimage.measure._regionprops.RegionProperties at 0x195f1e6a0>,
<skimage.measure._regionprops.RegionProperties at 0x1961f61c0>,
<skimage.measure._regionprops.RegionProperties at 0x1961f6040>,
<skimage.measure._regionprops.RegionProperties at 0x1961f60a0>,
<skimage.measure._regionprops.RegionProperties at 0x110c69310>]


We can reorganize the measurements into a dictionary containing arrays. We introduced them earlier as tables:

statistics = {
'area':       [p.area               for p in properties],
'mean':       [p.mean_intensity     for p in properties],
'major_axis': [p.major_axis_length  for p in properties]
}

statistics

{'area': [429,
183,
658,
433,
472,
280,
75,
271,
227,
27,
494,
649,
96,
225,
448,
397,
513,
423,
268,
349,
158,
406,
422,
254,
503,
282,
675,
176,
358,
542,
599,
7,
635,
192,
594,
19,
264,
896,
473,
239,
166,
408,
413,
239,
374,
647,
378,
577,
66,
169,
467,
612,
539,
203,
556,
850,
278,
213,
79,
88,
52,
48],
'mean': [191.44055944055944,
179.84699453551912,
205.6048632218845,
217.5150115473441,
213.03389830508473,
205.65714285714284,
164.16,
176.0590405904059,
189.53303964757708,
149.33333333333334,
190.0080971659919,
172.42526964560864,
166.41666666666666,
196.8,
209.03571428571428,
180.0705289672544,
194.86939571150097,
196.27423167848698,
200.77611940298507,
190.64756446991404,
183.69620253164558,
187.21182266009853,
202.54028436018956,
180.5984251968504,
198.6958250497018,
189.33333333333334,
199.07555555555555,
195.3181818181818,
197.7877094972067,
198.760147601476,
190.85141903171953,
146.28571428571428,
193.22204724409448,
181.83333333333334,
210.45117845117846,
150.31578947368422,
189.93939393939394,
198.59821428571428,
205.5137420718816,
191.59832635983264,
184.09638554216866,
179.80392156862746,
199.94188861985472,
188.21757322175733,
195.76470588235293,
200.70479134466768,
208.23280423280423,
201.01213171577123,
188.36363636363637,
181.53846153846155,
167.58886509635974,
220.0261437908497,
189.5213358070501,
199.96059113300493,
216.93525179856115,
197.9294117647059,
190.44604316546761,
184.52582159624413,
184.81012658227849,
182.72727272727272,
189.53846153846155,
173.83333333333334],
'major_axis': [34.77923003414236,
20.950530036869296,
30.19848422590625,
24.508790749585156,
31.08476574192099,
20.456703267018653,
10.455950805204104,
22.270013595805494,
18.204772873013326,
12.678548278670085,
26.121885258285065,
33.385906778814366,
12.546653692400314,
18.35737770149141,
26.27274937409412,
35.8698551687111,
27.860019629951697,
28.010713581438814,
21.468307192278967,
22.917689441728474,
15.666167580602863,
23.865287484124742,
32.6668803721007,
19.57228408508096,
33.24776088170501,
20.24089328396192,
36.442424525819675,
20.498286890054775,
23.711197998545444,
29.20849759104235,
47.75343594118352,
3.0237157840738176,
40.67149576429511,
16.77158509151243,
28.811758210746788,
6.09093638927516,
20.588317981737514,
54.585718360111564,
32.95587965343868,
19.25126182233261,
16.687880082810175,
26.756617235381256,
25.62619404615955,
18.831258251302966,
24.783530938010692,
30.43602504101513,
23.49797787654461,
27.804675105924606,
16.651155953717765,
17.042194757272345,
35.316994908476254,
32.401948630679065,
30.13681620111402,
24.67233590691917,
27.47945909705002,
41.32954022794983,
21.637743417307323,
18.753879494637765,
18.287488895428375,
21.673692014391232,
14.33510391276191,
16.925659950161798]}


You can also add custom columns by computing your own metric, for example the aspect_ratio:

statistics['aspect_ratio'] = [p.major_axis_length / p.minor_axis_length for p in properties]


Reading those dictionaries of arrays is not very convenient. Thus, we use the pandas library which is a common asset for data scientists.

import pandas as pd

dataframe = pd.DataFrame(statistics)
dataframe

area mean major_axis aspect_ratio
0 429 191.440559 34.779230 2.088249
1 183 179.846995 20.950530 1.782168
2 658 205.604863 30.198484 1.067734
3 433 217.515012 24.508791 1.061942
4 472 213.033898 31.084766 1.579415
... ... ... ... ...
57 213 184.525822 18.753879 1.296143
58 79 184.810127 18.287489 3.173540
59 88 182.727273 21.673692 4.021193
60 52 189.538462 14.335104 2.839825
61 48 173.833333 16.925660 4.417297

62 rows × 4 columns

Those dataframes can be saved to disk conveniently:

dataframe.to_csv("blobs_analysis.csv")


Furthermore, one can measure properties from our statistics table using numpy. For example the mean area:

import numpy as np

# measure mean area
np.mean(statistics['area'])

355.3709677419355


# Exercises#

Analyse the loaded blobs image.

• How many objects are in it?

• How large is the largest object?

• What are mean and standard deviation of the image?

• What are mean and standard deviation of the area of the segmented objects?