Skip to content
Snippets Groups Projects
Commit b4a11dea authored by marieanselmet's avatar marieanselmet
Browse files

Update notebook

parent b41a0504
Branches
No related tags found
No related merge requests found
Pipeline #141269 passed
%% Cell type:markdown id: tags:
# Feature extraction
%% Cell type:markdown id: tags:
## Region properties
%% Cell type:markdown id: tags:
Once you have segmented an image you usually want to gather information on the objects that you "discovered". Instead of painstakingly do this manually, skimage offers a simplified way to do this with its ```regionprops_table``` tool.
%% Cell type:code id: tags:
``` python
import numpy as np
import pandas as pd
import math
import matplotlib.pyplot as plt
import skimage
import skimage.io
import skimage.morphology
import scipy.ndimage as ndi
import stackview
```
%% Cell type:markdown id: tags:
Let's first create a mask of the nuclei and clean it up with morphological operations:
%% Cell type:code id: tags:
``` python
image_stack = skimage.io.imread('https://github.com/guiwitz/PyImageCourse_beginner/raw/master/images/46658_784_B12_1.tif')
image_nuclei = image_stack[:,:,2] #blue channel in RGB
image_signal = image_stack[:,:,1] #green channel in RGB
# filter image
image_nuclei = skimage.filters.median(image_nuclei, skimage.morphology.disk(5))
# create mask and clean-up
mask_nuclei = image_nuclei > skimage.filters.threshold_otsu(image_nuclei)
mask_nuclei = skimage.morphology.binary_closing(mask_nuclei, footprint=skimage.morphology.disk(5))
mask_nuclei = ndi.binary_fill_holes(mask_nuclei, skimage.morphology.disk(5))
```
%% Cell type:code id: tags:
``` python
plt.subplots(figsize=(10,10))
plt.imshow(mask_nuclei, cmap = 'gray');
```
%% Cell type:markdown id: tags:
## Labelling
%% Cell type:markdown id: tags:
In order to measure objects in the image separately, we first need to label them individually. For that we can just use the ```skimage.morphology.label()``` function which looks for independent groups of white pixels and assigns them integer numbers:
%% Cell type:code id: tags:
``` python
my_labels = skimage.morphology.label(mask_nuclei)
```
%% Cell type:markdown id: tags:
The label map shows that numbers are assigned from top to bottom in the image:
%% Cell type:code id: tags:
``` python
plt.subplots(figsize=(10,10))
plt.imshow(my_labels);
```
%% Cell type:markdown id: tags:
## Region properties
%% Cell type:markdown id: tags:
Now that we have each region labeled with a different number we can use the ```skimage.measure.regionprops_table()``` function, which takes such a label map and analyzes some properties of each region. We have to specify which ```properties``` we want to use.
The list of available ```properties``` can be found in the documentation of the function [here](https://scikit-image.org/docs/stable/api/skimage.measure.html#skimage.measure.regionprops).
Let's start by adding some of morphological properties in our list of properties and provide some explainations.
%% Cell type:markdown id: tags:
- ```label```
The label of the region. It allows us to indentify each segmented object corretly.
%% Cell type:markdown id: tags:
- ```area``` and ```perimeter```
Area and perimeter of the region.
Note that the pixel ```spacing``` along each axis of the image can be provided as argument to the function ```skimage.measure.regionprops_table()```. If provided, these properties will be returned in calibrated units. Otherwise, in number of pixels. Even if you did not feed the pixel spacing to the ```skimage.measure.regionprops_table()``` method, you can still convert the results to calibrated units later (as long as you have the spacing information from your image metadata) by a simple multiplication. We will see that later.
%% Cell type:markdown id: tags:
Now let's try to call the function with these three properties.
%% Cell type:code id: tags:
``` python
my_regions = skimage.measure.regionprops_table(my_labels, properties=('label','area','perimeter'))
```
%% Cell type:markdown id: tags:
The output is a dictionary of all properties that we asked to get out:
%% Cell type:code id: tags:
``` python
my_regions
```
%% Cell type:markdown id: tags:
### Dictionaries
Until now, in terms of data structures, we have briefly seen lists ```mylist = [5, 4, 2]``` and Numpy arrays via the images. However Python offers additional types of data structures and dictionaries are one of them. As you can see in the output above, they are defined with curly parentheses ```{}``` and contain pairs of elements: keys like ```label``` and ```area``` and a *content* for each key, here two Numpy arrays. To better understand let's just create a simple one:
%% Cell type:code id: tags:
``` python
my_dict = {'fruit name': 'apple', 'weigth': 50, 'types': ['golden', 'gala', 'breaburn']}
my_dict
```
%% Cell type:markdown id: tags:
As you can see these dictionaries can contain all types of variables: strings, numbers, lists etc. They are for this reason ideal to hold information of various types and useful to describe entities thanks to the dictionary keys. Each entry in the dictionary can then be recovered via its key:
%% Cell type:code id: tags:
``` python
my_dict['weigth']
```
%% Cell type:markdown id: tags:
## Recovering image intensity information
%% Cell type:markdown id: tags:
In what we did above, we only recovered information about our mask. However often we want to obtain information on pixel values of the **original** image. For example, "what is the average intensity of each nucleus?"
Luckily ```regionprops_table``` allows us to pass as additional argument ```intensity_image``` the image we want to use to quantify intensity. Then we can for example add a property to extract the ```mean_intensity```:
%% Cell type:code id: tags:
``` python
my_regions = skimage.measure.regionprops_table(
my_labels,intensity_image=image_signal, properties=('label','area','perimeter','mean_intensity'))
```
%% Cell type:code id: tags:
``` python
my_regions
```
%% Cell type:markdown id: tags:
Additionnal properties as the ```intensity_max```, ```intensity_min```, ```intensity_std``` for max, min and std of intensity values in the region, respectively, can also be computed. In some contexts, adding these features and not just looking at mean intensity may be relevant.
%% Cell type:markdown id: tags:
Now that we have this information, we can of course, plot it. For example we can produce a histogram of mean nuclei intensities:
%% Cell type:code id: tags:
``` python
plt.hist(my_regions['mean_intensity']);
```
%% Cell type:markdown id: tags:
## Filtering information
Obviously, we had some "bad segmentations", i.e. some fragments remaining from the processing that are not actual nuclei. We can easily filter those out for example based on size using Numpy logical indexing:
%% Cell type:code id: tags:
``` python
my_regions['area']
```
%% Cell type:markdown id: tags:
We create a logical array by setting a condition on one dictionary entry:
%% Cell type:code id: tags:
``` python
selected = my_regions['area'] > 100
selected
```
%% Cell type:markdown id: tags:
And then use it for logical indexing:
%% Cell type:code id: tags:
``` python
my_regions['mean_intensity'][selected]
```
%% Cell type:markdown id: tags:
## One step further: Pandas
In the above example, if we wanted to use one measurement to filter all other measurements, we would have to repeat the selection multiple times. Ideally, we would put all the measured properties into a table, one column per property, and then do typical database operations to sub-select parts of the data. This can be done using yet another data structure called a DataFrame. These structures are provided by the Pandas library, the main data science library in Python. We here give a very brief insight into that library. First we import it:
%% Cell type:code id: tags:
``` python
import pandas as pd
```
%% Cell type:markdown id: tags:
To understand what a DataFrame is, let's transform a plain Numpy array into a DataFrame:
%% Cell type:code id: tags:
``` python
np.random.seed(42)
my_array = np.random.randint(0,100, (3,5))
my_array
```
%% Cell type:markdown id: tags:
We can simply turn this array into a DataFrame by using:
%% Cell type:code id: tags:
``` python
pd.DataFrame(my_array)
```
%% Cell type:markdown id: tags:
We see that the array content is still there but in addition now we have column and row names, currently just indices. We could however give specific column names:
%% Cell type:code id: tags:
``` python
my_df = pd.DataFrame(my_array, columns=['a', 'b', 'c', 'd', 'e'])
my_df
```
%% Cell type:markdown id: tags:
The difference with Numpy arrays is that DataFrames can contain different types of information (text, numbers etc.) and that they should really be seen as "organized" data. So for example we can recover a column of the table without resorting to the type of indexing we did before:
%% Cell type:code id: tags:
``` python
my_df['c']
```
%% Cell type:markdown id: tags:
Now how can such a structure help us to do the sort of data filtering we have mentioned before? Just like with arrays, we can use some constraining tests. For example we can ask: are there data points in column ```c``` which are smaller than 50?
%% Cell type:code id: tags:
``` python
my_df['c'] < 50
```
%% Cell type:markdown id: tags:
Similarly to what happened with arrays, we get a new column that is boolean. And again similarly to what we did with arrays we can use it for logical indexing using square parentheses:
%% Cell type:code id: tags:
``` python
my_df[my_df['c'] < 50]
```
%% Cell type:markdown id: tags:
What happened here is that we kept only those entries in the table where the values in the ```c``` column were smaller than 50: we filtered all the properties (columns) in our table in one go!
%% Cell type:markdown id: tags:
### Back to our problem
In our analysis we ended up with a dictionary:
%% Cell type:code id: tags:
``` python
my_regions
```
%% Cell type:markdown id: tags:
We can also easily turn this dictionary into a DataFrame:
%% Cell type:code id: tags:
``` python
my_regions_df = pd.DataFrame(my_regions)
my_regions_df
```
%% Cell type:markdown id: tags:
And now we can use what we have just learned: let's remove tiny regions with an area smaller than 100:
%% Cell type:code id: tags:
``` python
my_regions_df[my_regions_df['area'] > 100]
```
%% Cell type:markdown id: tags:
We see that we indeed removed two elements in that table, indices 4 and 16.
%% Cell type:markdown id: tags:
Imagine we forgot to provide the pixel spacing information to ```regionprops_table()``` method but you know this information from your metadata. You can still convert the results to physical units by multiplying the columns concerned by the pixel spacing value as follows:
%% Cell type:code id: tags:
``` python
pixel_spacing = 0.06 # Let's say that 1 pixel corresponds to 0.06 um in our case
my_regions_df['perimeter um'] = my_regions_df['perimeter'] * pixel_spacing
my_regions_df['area um2'] = my_regions_df['area'] * pixel_spacing**2
my_regions_df
```
%% Cell type:markdown id: tags:
Pandas is a very powerful library and in this course we can't offer more than this brief insight into how it can be useful for data post-processing. To learn more you can also visit this other course: https://guiwitz.github.io/DAVPy/Readme.html
%% Cell type:markdown id: tags:
## Exercise 1
%% Cell type:markdown id: tags:
1. Load blobs image from the images folder and vizualise it
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
image_ex_1 = skimage.io.imread('images/blobs.tif')
plt.subplots(figsize=(10,10))
plt.imshow(image_ex_1, cmap = 'gray');
```
%% Cell type:markdown id: tags:
2. Segment the blobs and find a way to filter out all the blobs that have elongated shapes (do not split them for now)
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution cell 1
mask_blobs = image_ex_1 > skimage.filters.threshold_otsu(image_ex_1)
label_blobs = skimage.morphology.label(mask_blobs)
plt.subplots(figsize=(10,10))
plt.imshow(label_blobs);
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
results = skimage.measure.regionprops_table(label_blobs, properties=('label', 'axis_major_length', 'axis_minor_length'))
results_df = pd.DataFrame(results)
results_df.head()
```
%% Cell type:code id: tags:
``` python
# Solution cell 3
results_df['aspect ratio'] = results_df['axis_major_length'] / results_df['axis_minor_length']
results_df.head()
```
%% Cell type:code id: tags:
``` python
# Solution cell 4
results_elongated_removed = results_df[results_df['aspect ratio'] < 1.5]
results_elongated_removed.head()
```
%% Cell type:markdown id: tags:
3. Plot the label image without the elongated shapes
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution cell 1
# Create a mask of only the non-elongated blobs
filtered_labels = np.isin(label_blobs, results_elongated_removed['label'])
# Relabel the filtered mask for visualization
filtered_labels_relabel = skimage.segmentation.relabel_sequential(filtered_labels * label_blobs)[0]
plt.subplots(figsize=(10,10))
plt.imshow(filtered_labels_relabel);
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
stackview.curtain(label_blobs, filtered_labels_relabel)
```
%% Cell type:code id: tags:
``` python
# Solution cell 3
# Option 2 to keep the same label values as before
filtered_labels = np.where(np.isin(label_blobs, results_elongated_removed['label']), label_blobs, 0)
plt.subplots(figsize=(10,10))
plt.imshow(filtered_labels);
```
%% Cell type:code id: tags:
``` python
# Solution cell 4
stackview.curtain(label_blobs, filtered_labels)
```
%% Cell type:markdown id: tags:
4. From your initial segmentation, split the most elongated objects
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
# Solution cell 1
# compute distance transform from masks
distance = ndi.distance_transform_edt(mask_blobs)
# blur helps reduce the noise and minor irregularities in the distance values
blurred_distance = skimage.filters.gaussian(distance, sigma=2)
fp = np.ones((3,) * mask_blobs.ndim)
fp = np.ones((3,3))
# compute local max of blurred distance map
coords = skimage.feature.peak_local_max(blurred_distance, footprint=fp, labels=mask_blobs)
# create an array with labeled markers
mask = np.zeros(distance.shape, dtype=bool)
mask[tuple(coords.T)] = True
markers = skimage.measure.label(mask)
# apply the watershed algorithm
labels = skimage.segmentation.watershed(-blurred_distance, markers, mask=mask_blobs)
plt.subplots(figsize=(10,10))
plt.imshow(labels)
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
# now if you really want to "split" the objects, you can do the following
# first detect edges from the labels after watershed
edges = skimage.filters.sobel(labels)
# then detect edges from the mask_blobs before watershed
edges2 = skimage.filters.sobel(mask_blobs)
almost = np.logical_not(np.logical_xor(edges != 0, edges2 != 0)) * mask_blobs
output = skimage.morphology.binary_opening(almost)
fig, ax = plt.subplots(1, 2, figsize=(10,10))
ax[0].imshow(edges)
ax[1].imshow(edges2)
ax[0].set_title('Edges of labels after watershed');
ax[1].set_title('Edges of masks before watershed');
```
%% Cell type:code id: tags:
``` python
# Solution cell 3
almost = np.logical_not(np.logical_xor(edges != 0, edges2 != 0)) * mask_blobs # XOR = exclusive OR
output = skimage.morphology.binary_opening(almost)
split_labels_ex_1 = skimage.morphology.label(output)
plt.subplots(figsize=(10,10))
plt.imshow(split_labels_ex_1)
fig, ax = plt.subplots(2, 2, figsize=(10,10))
ax[0, 0].imshow(np.logical_xor(edges != 0, edges2 != 0))
ax[0, 1].imshow(almost)
ax[1, 0].imshow(output)
ax[1, 1].imshow(split_labels_ex_1);
```
%% Cell type:markdown id: tags:
## Computing distances between objects
%% Cell type:markdown id: tags:
In some projects, you might be interested in computing distances between different objects. For example, to filter out objects that are far away from an other set of objects. An efficient approach is based on distance maps, and we will see an example of usage along with ```skimage.measure.regionprops_table()``` method in the exercise 2 below. We give before a little theory reminder about distance maps.
%% Cell type:markdown id: tags:
Distance transforms have many applications, we can for example use them to quantify how a structure of interest is away from object boundaries or other structures as just mentionned. They are also used to characterize the morphology of an object in 2D and 3D, find its center, dimensions, etc.. Distance transforms can also be used as a pre-processing step to improve the segmentation results and split touching objects. Distance maps may use different distance metrics, as the Euclidian or the Manhattan one for example.
%% Cell type:markdown id: tags:
<img src="illustrations/distance_maps.png" alt="drawing" width="80%" class="center"/>
Image [source](https://neubias.github.io/training-resources/distance_transform/index.html#:~:text=We%20use%20distance%20transform%20to,center%2C%20dimensions%2C%20etc..)
%% Cell type:markdown id: tags:
## Exercise 2
%% Cell type:markdown id: tags:
1. Open hela cells image and visualize the different channels
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solutions cell 1
hela_cells = skimage.io.imread('images/hela-cells.tif')
chan_1 = hela_cells[:,:,0] # red channel in RGB
chan_2 = hela_cells[:,:,1] # green channel in RGB
chan_3 = hela_cells[:,:,2] # blue channel in RGB
fig, ax = plt.subplots(1, 3, figsize=(10,10))
ax[0].imshow(chan_1, cmap='gray')
ax[1].imshow(chan_2, cmap='gray')
ax[2].imshow(chan_3, cmap='gray')
ax[0].set_title('Lysosomes');
ax[1].set_title('Mitochondria');
ax[2].set_title('Nuclei');
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
stackview.switch(
{"lysosomes": hela_cells[:,:,0],
"mitochondria":hela_cells[:,:,1],
"nuclei": hela_cells[:,:,2]
},
colormap=["pure_magenta", "pure_green", "pure_blue"],
toggleable=True
)
```
%% Cell type:markdown id: tags:
2. Segment nuclei on the last channel
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
chan_3_blurred = skimage.filters.gaussian(chan_3, sigma=2)
mask_nuclei = chan_3_blurred > skimage.filters.threshold_otsu(chan_3_blurred)
mask_nuclei = skimage.morphology.binary_closing(mask_nuclei, footprint=skimage.morphology.disk(20))
mask_nuclei = skimage.morphology.remove_small_objects(ndi.binary_fill_holes(mask_nuclei, skimage.morphology.disk(5)))
label_nuclei = skimage.morphology.label(mask_nuclei)
plt.subplots(figsize=(10,10))
plt.imshow(label_nuclei);
```
%% Cell type:markdown id: tags:
3. Detect lysosomes on the first channel and convert them as labels
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution cell 1
blobs_dog = skimage.feature.blob_dog(chan_1.astype(float), min_sigma=1, max_sigma=6, threshold_rel=0.1)
blobs_dog[:, 2] = blobs_dog[:, 2] * math.sqrt(2) # store radii in third column
fig, axes = plt.subplots(1, 2, figsize=(10, 10), sharex=True, sharey=True)
ax = axes.ravel()
ax[0].imshow(chan_1, cmap='gray')
ax[0].set_title('Lysosomes')
ax[1].imshow(chan_1, cmap='gray')
for blob in blobs_dog:
y, x, r = blob
c = plt.Circle((x, y), r, color='green', linewidth=2, fill=False)
ax[1].add_patch(c)
ax[1].set_axis_off()
ax[1].set_title('DoG detections')
plt.tight_layout()
plt.show()
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
label_lysosomes = np.zeros(chan_1.shape, dtype=np.int32)
for i, lysosome in enumerate(blobs_dog, 1): # Start labeling from 1
y, x, r = lysosome
rr, cc = skimage.draw.disk((y, x), r)
if(((y+r) < chan_1.shape[0]) and ((x+r) < chan_1.shape[1])):
label_lysosomes[rr, cc] = i
fig, ax = plt.subplots(1, 2, figsize=(10,10), sharex=True, sharey=True)
ax[0].imshow(chan_1, cmap='gray');
ax[0].set_title('Lysosomes');
ax[1].imshow(label_lysosomes);
ax[1].set_title('Labeled lysosomes');
plt.show()
```
%% Cell type:code id: tags:
``` python
# Solution cell 3
stackview.curtain(label_lysosomes, chan_1)
```
%% Cell type:markdown id: tags:
4. Compute distance map and inverse distance map of nuclei. Hint [here](https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.distance_transform_edt.html)
%% Cell type:code id: tags:
``` python
# Solution cell 1
distance_map_nuclei = ndi.distance_transform_edt(mask_nuclei)
inv_distance_map_nuclei = ndi.distance_transform_edt(1 - mask_nuclei)
fig, ax = plt.subplots(1, 3, figsize=(10,10))
ax[0].imshow(mask_nuclei, cmap='gray');
ax[0].set_title('Mask nuclei');
ax[1].imshow(distance_map_nuclei, cmap = 'gray');
ax[1].set_title('Distance map from nuclei');
ax[2].imshow(inv_distance_map_nuclei, cmap = 'gray');
ax[2].set_title('Inverse distance map from nuclei');
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
stackview.picker(distance_map_nuclei)
```
%% Cell type:code id: tags:
``` python
# Solution cell 3
stackview.picker(inv_distance_map_nuclei)
```
%% Cell type:markdown id: tags:
5. Compute distances from lysosomes to closest nuclei. Hint: you can use ```regionprops```
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution cell 1
# compute mean intensity value of distance map image from lysosomes label image
results = skimage.measure.regionprops_table(label_lysosomes, inv_distance_map_nuclei, properties=('label','area', 'mean_intensity'))
results_df = pd.DataFrame(results)
plt.hist(results_df['mean_intensity'])
plt.title("Distance to closest nuclei");
```
%% Cell type:markdown id: tags:
Note that as for ```skimage.measure.regionprops_table()``` method, you can provide a pixel spacing to the ```scipy.ndimage.
distance_transform_edt()``` method so that the returned distances are in calibrated units.
%% Cell type:code id: tags:
``` python
# Solution cell 2
stackview.clusterplot(image=chan_3,
labels=label_lysosomes,
df=results_df,
column_x="label",
column_y="mean_intensity",
zoom_factor=0.8,
alpha=0.7)
```
%% Cell type:markdown id: tags:
## [OPTIONAL] Exercise 3
%% Cell type:markdown id: tags:
1. Import the image from http://wiki.cmci.info/sampleimages/4color_cells.tif and visualize the 3rd channel
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
image_ex_3 = skimage.io.imread('http://wiki.cmci.info/sampleimages/4color_cells.tif')
chan_3 = image_ex_3[:,:,2]
plt.subplots(figsize=(10,10))
plt.imshow(chan_3, cmap = 'gray');
```
%% Cell type:markdown id: tags:
2. Create a mask using the third channel and label objects
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution cell 1
# filter image and create mask
chan_3 = skimage.filters.median(chan_3, skimage.morphology.disk(3))
masks = chan_3 > skimage.filters.threshold_otsu(chan_3)
plt.subplots(figsize=(10,10))
plt.subplots(figsize=(8,8))
plt.imshow(masks);
```
%% Cell type:code id: tags:
``` python
# Solution cell 2
distance = ndi.distance_transform_edt(masks)
blurred_distance = skimage.filters.gaussian(distance, sigma=2)
fp = np.ones((3,) * masks.ndim)
fp = np.ones((3,3))
coords = skimage.feature.peak_local_max(blurred_distance, footprint=fp, labels=masks)
mask = np.zeros(distance.shape, dtype=bool)
mask = np.zeros(blurred_distance.shape, dtype=bool)
mask[tuple(coords.T)] = True
markers = skimage.measure.label(mask)
labels = skimage.segmentation.watershed(-blurred_distance, markers, mask=masks)
edges = skimage.filters.sobel(labels)
edges2 = skimage.filters.sobel(masks)
labels_ex_3 = skimage.segmentation.watershed(-blurred_distance, markers, mask=masks)
almost = np.logical_not(np.logical_xor(edges != 0, edges2 != 0)) * masks
output = skimage.morphology.binary_opening(almost)
split_labels_ex_3 = skimage.morphology.label(output)
plt.subplots(figsize=(10,10))
plt.imshow(split_labels_ex_3);
stackview.picker(labels_ex_3)
```
%% Cell type:markdown id: tags:
3. Measure the region properties using this labeled image and use the fourth channel as intensity image
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
results = skimage.measure.regionprops_table(split_labels_ex_3, image_ex_3[:,:,3], properties=('label','mean_intensity'))
results = skimage.measure.regionprops_table(labels_ex_3, image_ex_3[:,:,3], properties=('label','mean_intensity'))
```
%% Cell type:markdown id: tags:
4. Extract the mean_intensity property from the dictionary and plot an histogram of these intensities
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
results_df = pd.DataFrame(results)
results_df['mean_intensity'].hist();
```
%% Cell type:markdown id: tags:
5. What do you observe in this histogram ? Plot the fourth channel and see if the histogram makes sense
%% Cell type:code id: tags:
``` python
# Write your code here
```
%% Cell type:code id: tags:
``` python
# Solution
stackview.picker(image_ex_3[:,:,3])
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment