Analysis of bitmap images under periodic boundary conditions¶

This tutorial explains how to analyze bitmap images under periodic boundary conditions.

A file named periodic-binary-image.png is saved in the same directory as this notebook. We will perform the analysis on this image.

The following cells displays the image.

In [2]:
from IPython.display import display, Image
In [3]:
display(Image("periodic-binary-image.png"))
No description has been provided for this image

When the upper and lower boundaries are connected periodically, you can see that the structure forms a white circle.

Loading images¶

Use imageio to load images.

In [4]:
import imageio
In [5]:
image = imageio.v3.imread("periodic-binary-image.png", mode="L")

Check the image size and the histogram of pixel values.

In [6]:
image.shape
Out[6]:
(128, 128)
In [7]:
import matplotlib.pyplot as plt
import numpy as np
In [8]:
plt.hist(np.ravel(image), range=(0,256), bins=256); None
No description has been provided for this image

In this tutorial, let's focus on the black areas.

Extract pixels less than 128.

In [9]:
bitmap = image < 128

When periodic boundary condition is not used¶

First, we compute the persistence diagrams without considering periodic boundary conditions. The process is the same as in the binary image tutorial.

The computed persistence diagram is saved in a file named bitmap.idiagram.

In [10]:
import homcloud.interface as hc
In [11]:
hc.PDList.from_bitmap_levelset(hc.distance_transform(bitmap, signed=True), save_to="bitmap.pdgm")
Out[11]:
PDList(path=bitmap.pdgm)

Visualization of Persistence Diagrams¶

Displays the persistence diagram without periodic boundary condition. In this tutorial, we will analyze 1-dimensional persistence diagrams, focusing on “holes.” Here, we focus on the white holes (one-dimensional features) that appear in the black background.

By not specifying periodic boundary conditions, we can confirm how the structures that appear at the edges of the image affect the analysis.

In [12]:
pdlist = hc.PDList("bitmap.pdgm")
pd1 = pdlist.dth_diagram(1)
pd1.histogram(x_bins=28).plot(colorbar={"type":"log"})
No description has been provided for this image

There is a pair at (-6, 26).

In [13]:
pd1.pairs()
Out[13]:
[Pair(-6.0, 26.0)]

Perform inverse analysis to confirm the structure corresponding to this pair. Use a death pixel to display the positions of corresponding features.

In [14]:
death_pixel_image = hc.draw_birthdeath_pixels_2d(
    pd1.pairs(), image, draw_death=True
)
display(death_pixel_image)
No description has been provided for this image

You can see that this pair corresponds to the white hole in the center.

When periodic boundary condition is used¶

Next, we calculate the persistence diagram with periodic boundary conditions.

The periodicity parameter is used to specify periodic boundaries. This parameter is an array with the same length as the number of dimensions of the image, and specifies whether to connect periodically for each axis with True (periodic) or False (non-periodic).

In this tutorial, the target image is two-dimensional, so we pass a two-element array to periodicity. In this case, we specify [True, False] because we want the image to be periodically connected only in the Y direction (up and down). Note that when representing images using NumPy two-dimensional arrays, the coordinate order is Y, X.

This periodicity information is necessary for both distance transformation and persistence diagram calculation. Therefore, the periodicity argument must be passed in both the distance_transform function and the PDList.from_bitmap_levelset function.

The pbc in the file name to be saved stands for Periodic Boundary Condition.

In [15]:
periodicity=[True, False]

hc.PDList.from_bitmap_levelset(
    hc.distance_transform(bitmap, signed=True, periodicity=periodicity), 
    periodicity=periodicity, 
    save_to="bitmap_pbc.pdgm"
)
Out[15]:
PDList(path=bitmap_pbc.pdgm)
In [16]:
pdlist_pbc = hc.PDList("bitmap_pbc.pdgm")
pd1_pbc = pdlist_pbc.dth_diagram(1)

Display the 1D persistence diagram under periodic boundary condition for Y-axis.

In [17]:
pd1_pbc.histogram(x_bins=28).plot(colorbar={"type":"log"})
No description has been provided for this image
In [18]:
pd1_pbc.pairs()
Out[18]:
[Pair(-6.0, 25.0), Pair(-37.0, 26.0)]

When no periodic boundary was specified, only one pair (-6, 26) appeared in the persistence diagram. However, when periodic boundaries are specified, the number of pairs increases to two.

This means that another hole appears by periodically connecting the top and bottom of the image. In other words, by considering periodic boundaries, this image is recognized as a structure with two independent holes.

Now, let's use inverse analysis to confirm the locations of each hole in the image.

In [19]:
death_pixel_image = hc.draw_birthdeath_pixels_2d(
    pd1_pbc.pairs(), image, draw_death=True
)
display(death_pixel_image)
No description has been provided for this image

This tutorial ends here.