Simple shapes

Simple shapes#

In this notebook we will exercise the imageruler algorithm with some simple shapes.

import numpy as np

from imageruler import imageruler
from matplotlib import pyplot as plt

# Import functions that generate regular shapes.
from imageruler.regular_shapes import disc, rounded_square, stripe

Examples based on regular 2d shapes are as follows.

resolution = 1  # number of pixels per unit length
phys_size = (200, 200)  # physical size of the entire image
declared_mls = 50  # declared minimum length scale

image = rounded_square(
    resolution, phys_size, declared_mls, angle=20
)  # generate a rounded square

plt.figure()
plt.imshow(image)
plt.show()

solid_mls, _ = imageruler.minimum_length_scale(
    image
)  # estimate the minimum length scale of the solid region
print("Declared minimum length scale of the solid region: ", declared_mls)
print("Estimated minimum length scale of the solid region: ", solid_mls)
../_images/0ba5d41acf174011f20eb0c1a4bcc0d86e810695ac626df77ff08c7734db22cb.png
Declared minimum length scale of the solid region:  50
Estimated minimum length scale of the solid region:  49
diameter = 50
image = disc(resolution, phys_size, diameter)  # generate a disc

plt.figure()
plt.imshow(image)
plt.show()

# estimate the minimum length scale of the solid region
solid_mls = imageruler.minimum_length_scale_solid(image)
print("Declared minimum length scale of the solid region: ", diameter)
print("Estimated minimum length scale of the solid region: ", solid_mls)
../_images/b2160b6d669b27c8b0750daf4329aa97a18185d6ab84a9f9710ca0cc01062d1e.png
Declared minimum length scale of the solid region:  50
Estimated minimum length scale of the solid region:  50
outer_diameter, inner_diameter = 120, 50
declared_solid_mls, declared_void_mls = (
    outer_diameter - inner_diameter
) / 2, inner_diameter

solid_disc = disc(resolution, phys_size, diameter=outer_diameter)
void_disc = disc(resolution, phys_size, diameter=inner_diameter)
image = solid_disc ^ void_disc  # ring

plt.figure()
plt.imshow(image)
plt.show()

solid_mls, void_mls = imageruler.minimum_length_scale(image)
mls = min(solid_mls, void_mls)

print(
    f"Declared minimum length scale: {declared_solid_mls} (solid), "
    f"{declared_void_mls} (void)"
)
print(
    f"Estimated minimum length scale: {solid_mls} (solid), {void_mls} "
    f"(void), {mls} (minimum)"
)
../_images/d448ffcf8e3e41c0fee9b564805125cd084f54531ec8d9833415144d1584a1be.png
Declared minimum length scale: 35.0 (solid), 50 (void)
Estimated minimum length scale: 34 (solid), 50 (void), 34 (minimum)
resolution = 1  # number of pixels per unit length
phys_size = (400, 400)  # physical size of the entire image

outer_diameter, middle_diameter, inner_diameter = 300, 200, 100
declared_solid_mls, declared_void_mls = (
    outer_diameter - inner_diameter
) / 2, inner_diameter

outer_solid_disc = disc(resolution, phys_size, diameter=outer_diameter, center=(0, 0))
void_disc = disc(resolution, phys_size, diameter=middle_diameter, center=(-20, 0))
inner_solid_disc = disc(resolution, phys_size, diameter=inner_diameter, center=(-10, 0))
image = outer_solid_disc ^ void_disc ^ inner_solid_disc

plt.figure()
plt.imshow(image)
plt.show()

solid_mls, void_mls = imageruler.minimum_length_scale(image)
mls = min(solid_mls, void_mls)

print(f"Declared minimum length scale: {30} (solid), {40} (void)")
print(
    f"Estimated minimum length scale: {solid_mls} (solid), {void_mls} "
    f"(void), {mls} (minimum)"
)
../_images/fe2a5cba76eaa48708de18193482921c9726545ee75dff15540751c078e85747.png
Declared minimum length scale: 30 (solid), 40 (void)
Estimated minimum length scale: 30 (solid), 40 (void), 30 (minimum)

The images that illustrate the areas of violation at various probe diameters are shown as follows. The three rows from top to bottom show violations at solid, void, and either region.

diameters = [31, 41, 61, 71, 101]
nd = len(diameters)
plt.figure(figsize=(20, 12))

for idx in range(nd):
    plt.subplot(3, nd, idx + 1)
    ax = plt.gca()
    ax.set_axis_off()
    image_violation_solid = imageruler.length_scale_violations_solid(
        image, length_scale=diameters[idx]
    )
    plt.imshow(image_violation_solid)
    plt.title("probe diameter = " + str(diameters[idx]))

    plt.subplot(3, nd, nd + idx + 1)
    ax = plt.gca()
    ax.set_axis_off()
    image_violation_void = imageruler.length_scale_violations_solid(
        ~image, length_scale=diameters[idx]
    )
    plt.imshow(image_violation_void)

    plt.subplot(3, nd, 2 * nd + idx + 1)
    ax = plt.gca()
    ax.set_axis_off()
    image_violation = image_violation_solid | image_violation_void
    plt.imshow(image_violation)
../_images/c75d4807aeb4f16ebb437eb7afdd66c75bb4b898a5758851ea7afbb413b4288d.png
resolution = 50
width, height = 6, 4  # size of the binary image
phys_size = (width, height)

stripe_width = 0.8
image = stripe(resolution, phys_size, stripe_width)

plt.figure()
plt.imshow(
    image,
    extent=[-phys_size[1] / 2, phys_size[1] / 2, -phys_size[0] / 2, phys_size[0] / 2],
)
plt.show()

solid_mls = imageruler.minimum_length_scale_solid(image)

print(f"Declared minimum length scale of the solid region: {stripe_width}")
print(f"Estimated minimum length scale of the solid region: {solid_mls / resolution}")
../_images/bdcf1f46346c1891d1aa977d002d935ed4da6d572e025c19ca4e2e724c89e97f.png
Declared minimum length scale of the solid region: 0.8
Estimated minimum length scale of the solid region: 0.8
image = stripe(resolution, phys_size, stripe_width, center=(0, -2)) | stripe(
    resolution, phys_size, stripe_width, center=(0, 2)
)

plt.figure()
plt.imshow(
    image,
    extent=[-phys_size[1] / 2, phys_size[1] / 2, -phys_size[0] / 2, phys_size[0] / 2],
)
plt.show()

# Assume this image is periodic along the horizontal direction, which corresponds to the axis 1.
solid_mls = imageruler.minimum_length_scale_solid(image, periodic=(False, True))

print(f"Declared minimum length scale of the solid region: {stripe_width}")
print(f"Estimated minimum length scale of the solid region: {solid_mls / resolution}")
../_images/5bfcfc3c3cf5e02390a3253aef4d30f0863552a03924c0cb111c7d1483a73f8f.png
Declared minimum length scale of the solid region: 0.8
Estimated minimum length scale of the solid region: 0.8
stripe_width, intercept, angle = 1, 1 / np.sqrt(2), 0.25 * np.pi
image = stripe(resolution, phys_size, stripe_width, center=(intercept, 0), angle=135)

plt.figure()
plt.imshow(
    image,
    extent=[-phys_size[1] / 2, phys_size[1] / 2, -phys_size[0] / 2, phys_size[0] / 2],
)
plt.show()

solid_mls = imageruler.minimum_length_scale_solid(image)

print(f"Declared minimum length scale of the solid region: {stripe_width}")
print(f"Estimated minimum length scale of the solid region: {solid_mls / resolution}")
../_images/520b5e3ab0c97ccd8282afac2ef457dee28d324d9fe70ff3622f23b6d7c5e64d.png
Declared minimum length scale of the solid region: 1
Estimated minimum length scale of the solid region: 0.98

Some tests based on 1d images are as follows.

phys_size = 10.1
image = np.sin(np.linspace(0, 100, 101) / 5) > 0.5
image = image[:, np.newaxis]
resolution = image.size / phys_size

plt.plot(np.linspace(-phys_size / 2, phys_size / 2, len(image)), image)

solid_mls, void_mls = imageruler.minimum_length_scale(image, periodic=(True, True))
print(
    f"Estimated minimum length scales: {solid_mls / resolution} (solid), "
    f"{void_mls / resolution} (void)"
)

# disregard the short void and solid regions at both ends
solid_mls, void_mls = imageruler.minimum_length_scale(image)
print(
    f"Estimated minimum length scales with some end regions disregarded: "
    f"{solid_mls / resolution} (solid), {void_mls / resolution} (void)"
)
Estimated minimum length scales: 0.4 (solid), 0.3 (void)
Estimated minimum length scales with some end regions disregarded: 1.0 (solid), 2.1 (void)
../_images/c28dc376b582a8524bc82ffb487713555687aafb68d5daa843f55d957fb555f1.png

This package can also be used via the command line, which allows you to invoke the function minimimum_length_scale. The syntax is “imageruler file”, where “file” is a string of the path of the text file that contains the array of the input image. All other arguments of the function take default options.