[1]:
%load_ext autoreload
%autoreload 2
%config InlineBackend.rc = {'figure.figsize': (10,6)}
%matplotlib inline

Examine nanopore properties

This notebook serves as a demonstration to examine the nanopore properties of a slice through a crystal. It shows how to use scikit-image regionprops to describe the size and shape of the pores.

[2]:
from nanomesh import Image
import numpy as np

plane_orig = Image.load('x500.npy')

# rotate to make better use of space
plane_orig = plane_orig.apply(np.rot90)

# smooth image for better segmentation
plane = plane_orig.gaussian(sigma=5)
plane.show()
Jupyter environment detected. Enabling Open3D WebVisualizer.
[Open3D INFO] WebRTC GUI backend enabled.
[Open3D INFO] WebRTCWindowSystem: HTTP handshake server disabled.
[2]:
<AxesSubplot:xlabel='x', ylabel='y'>

Image segmentation

The image has a slight gradient from top to bottom, therefore we need to apply local thresholding. This has been described in another notebook.

[3]:
from skimage.filters import threshold_local

offset = 150
block_size = 101

local_thresh = plane.threshold('local', block_size=block_size, offset=offset)
seg_local = plane.image > local_thresh.image

# invert contrast for object detection
seg = Image(1 - seg_local)
seg.show()
[3]:
<AxesSubplot:xlabel='x', ylabel='y'>

Obtain regionprops

First the segmented image must be labeled. This means that all the objects in the above image are given a different label. The regionprops function then calculates the properties for each label. The original image is passed so that the contrast can be used for intensity calculations (if needed).

[4]:
from skimage import measure

labels = measure.label(seg.image)

props = measure.regionprops(labels, plane_orig.image)

Have a look at the documentation for the available properties.

Below are the properties we are interested in for the plots.

[5]:
properties = ['area', 'eccentricity', 'perimeter', 'mean_intensity']

Plots

The example below is adapted from the the scikit-image gallery. It interactively plots the selected objects on the source image, so that the properties of each can be explored. This example requires plotly and pandas to be installed (pip install plotly pandas).

[6]:
import plotly
import plotly.express as px
import plotly.graph_objects as go

fig = px.imshow(plane_orig.image, binary_string=True)
fig.update_traces(hoverinfo='skip')  # hover is only for label info

# For each label, add a filled scatter trace for its contour,
# and display the properties of the label in the hover of this trace.
for index in range(1, labels.max()):
    label_i = props[index].label
    contour = measure.find_contours(labels == label_i, 0.5)[0]
    y, x = contour.T
    hoverinfo = ''
    for prop_name in properties:
        hoverinfo += f'<b>{prop_name}: {getattr(props[index], prop_name):.2f}</b><br>'
    fig.add_trace(
        go.Scatter(x=x,
                   y=y,
                   name=label_i,
                   mode='lines',
                   fill='toself',
                   showlegend=False,
                   hovertemplate=hoverinfo,
                   hoveron='points+fills'))

plotly.io.show(fig)