分解扁平足迹(结构元素)#

许多足迹(结构元素)可以分解成一系列等效的较小结构元素。术语“扁平”指的是仅包含 0 或 1 值的足迹(即,skimage.morphology.footprints 中的所有方法)。二元膨胀操作具有结合性和分配性,通常允许分解成一系列等效的较小足迹。大多数情况下,这样做是为了提高性能。

作为一个具体的例子,使用形状为 (15, 15) 的方形足迹进行膨胀等效于使用形状为 (15, 1) 的矩形进行膨胀,然后使用形状为 (1, 15) 的矩形进行另一次膨胀。它也等效于使用形状为 (3, 3) 的方形足迹进行 7 次连续膨胀。

存在许多可能的分解,哪种分解性能最佳可能取决于体系结构。

scikit-image 目前提供两种形式的自动分解。对于 squarerectanglecube 足迹的情况,可以选择“可分离”分解(一次仅沿一个轴大小 > 1)。

对于某些其他对称凸形,例如 diamondoctahedronoctagon,不存在可分离分解成 1D 操作。但是,可以提供基于一系列形状为 (3,) * ndim 的小足迹的“序列”分解。

为了实现简单,下面显示的所有分解仅使用奇数大小的足迹,其原点位于足迹的中心。

  • square(11) (composite), element 1 of 2 (1 iteration), element 2 of 2 (1 iteration)
  • square(11) (composite), element 1 of 1 (5 iterations)
  • rectangle(7, 11) (composite), element 1 of 2 (1 iteration), element 2 of 2 (1 iteration)
  • rectangle(7, 11) (composite), element 1 of 2 (3 iterations), element 2 of 2 (1 iteration)
  • diamond(5) (composite), element 1 of 1 (5 iterations)
  • disk(7, strict_radius=False) (decomposition=None), disk(7, strict_radius=False) (composite), element 1 of 6 (1 iteration), element 2 of 6 (1 iteration), element 3 of 6 (1 iteration), element 4 of 6 (1 iteration), element 5 of 6 (2 iterations), element 6 of 6 (1 iteration)
  • disk(7, strict_radius=True) (decomposition=None), disk(7, strict_radius=True) (composite), element 1 of 3 (1 iteration), element 2 of 3 (3 iterations), element 3 of 3 (1 iteration)
  • ellipse(4, 9) (decomposition=None), ellipse(4, 9) (composite), element 1 of 3 (1 iteration), element 2 of 3 (2 iterations), element 3 of 3 (1 iteration)
  • disk(20) (decomposition=None), disk(20) (composite), element 1 of 6 (3 iterations), element 2 of 6 (3 iterations), element 3 of 6 (3 iterations), element 4 of 6 (3 iterations), element 5 of 6 (6 iterations), element 6 of 6 (2 iterations)
  • octagon(7, 4) (composite), element 1 of 2 (3 iterations), element 2 of 2 (4 iterations)
  • cube(11) (composite), element 1 of 3 (1 iteration), element 2 of 3 (1 iteration), element 3 of 3 (1 iteration)
  • cube(11) (composite), element 1 of 1 (5 iterations)
  • octahedron(7) (composite), element 1 of 1 (7 iterations)
  • ball(9) (decomposition=None), ball(9) (composite), element 1 of 7 (1 iteration), element 2 of 7 (1 iteration), element 3 of 7 (1 iteration), element 4 of 7 (1 iteration), element 5 of 7 (1 iteration), element 6 of 7 (1 iteration), element 7 of 7 (3 iterations)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
from mpl_toolkits.mplot3d import Axes3D

from skimage.morphology import (
    ball,
    cube,
    diamond,
    disk,
    ellipse,
    octagon,
    octahedron,
    rectangle,
    square,
)
from skimage.morphology.footprints import footprint_from_sequence


# Generate 2D and 3D structuring elements.
footprint_dict = {
    "square(11) (separable)": (
        square(11, decomposition=None),
        square(11, decomposition="separable"),
    ),
    "square(11) (sequence)": (
        square(11, decomposition=None),
        square(11, decomposition="sequence"),
    ),
    "rectangle(7, 11) (separable)": (
        rectangle(7, 11, decomposition=None),
        rectangle(7, 11, decomposition="separable"),
    ),
    "rectangle(7, 11) (sequence)": (
        rectangle(7, 11, decomposition=None),
        rectangle(7, 11, decomposition="sequence"),
    ),
    "diamond(5) (sequence)": (
        diamond(5, decomposition=None),
        diamond(5, decomposition="sequence"),
    ),
    "disk(7, strict_radius=False) (sequence)": (
        disk(7, strict_radius=False, decomposition=None),
        disk(7, strict_radius=False, decomposition="sequence"),
    ),
    "disk(7, strict_radius=True) (crosses)": (
        disk(7, strict_radius=True, decomposition=None),
        disk(7, strict_radius=True, decomposition="crosses"),
    ),
    "ellipse(4, 9) (crosses)": (
        ellipse(4, 9, decomposition=None),
        ellipse(4, 9, decomposition="crosses"),
    ),
    "disk(20) (sequence)": (
        disk(20, strict_radius=False, decomposition=None),
        disk(20, strict_radius=False, decomposition="sequence"),
    ),
    "octagon(7, 4) (sequence)": (
        octagon(7, 4, decomposition=None),
        octagon(7, 4, decomposition="sequence"),
    ),
    "cube(11) (separable)": (
        cube(11, decomposition=None),
        cube(11, decomposition="separable"),
    ),
    "cube(11) (sequence)": (
        cube(11, decomposition=None),
        cube(11, decomposition="sequence"),
    ),
    "octahedron(7) (sequence)": (
        octahedron(7, decomposition=None),
        octahedron(7, decomposition="sequence"),
    ),
    "ball(9) (sequence)": (
        ball(9, strict_radius=False, decomposition=None),
        ball(9, strict_radius=False, decomposition="sequence"),
    ),
}

# Visualize the elements

# binary white / blue colormap
cmap = colors.ListedColormap(['white', (0.1216, 0.4706, 0.70588)])

fontdict = dict(fontsize=16, fontweight='bold')
for title, (footprint, footprint_sequence) in footprint_dict.items():
    ndim = footprint.ndim
    num_seq = len(footprint_sequence)
    approximate_decomposition = 'ball' in title or 'disk' in title or 'ellipse' in title
    if approximate_decomposition:
        # Two extra plot in approximate cases to show both:
        # 1.) decomposition=None idea footprint
        # 2.) actual composite footprint corresponding to the sequence
        num_subplots = num_seq + 2
    else:
        # composite and decomposition=None are identical so only 1 extra plot
        num_subplots = num_seq + 1
    fig = plt.figure(figsize=(4 * num_subplots, 5))
    if ndim == 2:
        ax = fig.add_subplot(1, num_subplots, num_subplots)
        ax.imshow(footprint, cmap=cmap, vmin=0, vmax=1)
        if approximate_decomposition:
            ax2 = fig.add_subplot(1, num_subplots, num_subplots - 1)
            footprint_composite = footprint_from_sequence(footprint_sequence)
            ax2.imshow(footprint_composite, cmap=cmap, vmin=0, vmax=1)

    else:
        ax = fig.add_subplot(1, num_subplots, num_subplots, projection=Axes3D.name)
        ax.voxels(footprint, cmap=cmap)
        if approximate_decomposition:
            ax2 = fig.add_subplot(
                1, num_subplots, num_subplots - 1, projection=Axes3D.name
            )
            footprint_composite = footprint_from_sequence(footprint_sequence)
            ax2.voxels(footprint_composite, cmap=cmap)

    title1 = title.split(' (')[0]
    if approximate_decomposition:
        # plot decomposition=None on a separate axis from the composite
        title = title1 + '\n(decomposition=None)'
    else:
        # for exact cases composite and decomposition=None are identical
        title = title1 + '\n(composite)'
    ax.set_title(title, fontdict=fontdict)
    ax.set_axis_off()
    if approximate_decomposition:
        ax2.set_title(title1 + '\n(composite)', fontdict=fontdict)
        ax2.set_axis_off()

    for n, (fp, num_reps) in enumerate(footprint_sequence):
        npad = [((footprint.shape[d] - fp.shape[d]) // 2,) * 2 for d in range(ndim)]
        fp = np.pad(fp, npad, mode='constant')
        if ndim == 2:
            ax = fig.add_subplot(1, num_subplots, n + 1)
            ax.imshow(fp, cmap=cmap, vmin=0, vmax=1)
        else:
            ax = fig.add_subplot(1, num_subplots, n + 1, projection=Axes3D.name)
            ax.voxels(fp, cmap=cmap)
        title = f"element {n + 1} of {num_seq}\n({num_reps} iteration"
        title += "s)" if num_reps > 1 else ")"
        ax.set_title(title, fontdict=fontdict)
        ax.set_axis_off()
        ax.set_xlabel(f'num_reps = {num_reps}')
    fig.tight_layout()

    # draw a line separating the sequence elements from the composite
    line_pos = num_seq / num_subplots
    line = plt.Line2D([line_pos, line_pos], [0, 1], color="black")
    fig.add_artist(line)

plt.show()

脚本的总运行时间:(0 分钟 9.517 秒)

由 Sphinx-Gallery 生成的图库