.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/numpy_operations/plot_footprint_decompositions.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_numpy_operations_plot_footprint_decompositions.py: ================================================ Decompose flat footprints (structuring elements) ================================================ Many footprints (structuring elements) can be decomposed into an equivalent series of smaller structuring elements. The term "flat" refers to footprints that only contain values of 0 or 1 (i.e., all methods in ``skimage.morphology.footprints``). Binary dilation operations have an associative and distributive property that often allows decomposition into an equivalent series of smaller footprints. Most often this is done to provide a performance benefit. As a concrete example, dilation with a square footprint of shape (15, 15) is equivalent to dilation with a rectangle of shape (15, 1) followed by another dilation with a rectangle of shape (1, 15). It is also equivalent to 7 consecutive dilations with a square footprint of shape (3, 3). There are many possible decompositions and which one performs best may be architecture-dependent. scikit-image currently provides two forms of automated decomposition. For the cases of ``square``, ``rectangle`` and ``cube`` footprints, there is an option for a "separable" decomposition (size > 1 along only one axis at a time). There is no separable decomposition into 1D operations for some other symmetric convex shapes, e.g., ``diamond``, ``octahedron`` and ``octagon``. However, it is possible to provide a "sequence" decomposition based on a series of small footprints of shape ``(3,) * ndim``. For simplicity of implementation, all decompositions shown below use only odd-sized footprints with their origin located at the center of the footprint. .. GENERATED FROM PYTHON SOURCE LINES 34-186 .. rst-class:: sphx-glr-horizontal * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_001.png :alt: square(11) (composite), element 1 of 2 (1 iteration), element 2 of 2 (1 iteration) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_001.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_002.png :alt: square(11) (composite), element 1 of 1 (5 iterations) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_002.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_003.png :alt: rectangle(7, 11) (composite), element 1 of 2 (1 iteration), element 2 of 2 (1 iteration) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_003.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_004.png :alt: rectangle(7, 11) (composite), element 1 of 2 (3 iterations), element 2 of 2 (1 iteration) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_004.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_005.png :alt: diamond(5) (composite), element 1 of 1 (5 iterations) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_005.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_006.png :alt: 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) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_006.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_007.png :alt: 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) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_007.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_008.png :alt: 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) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_008.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_009.png :alt: 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) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_009.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_010.png :alt: octagon(7, 4) (composite), element 1 of 2 (3 iterations), element 2 of 2 (4 iterations) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_010.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_011.png :alt: cube(11) (composite), element 1 of 3 (1 iteration), element 2 of 3 (1 iteration), element 3 of 3 (1 iteration) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_011.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_012.png :alt: cube(11) (composite), element 1 of 1 (5 iterations) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_012.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_013.png :alt: octahedron(7) (composite), element 1 of 1 (7 iterations) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_013.png :class: sphx-glr-multi-img * .. image-sg:: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_014.png :alt: 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) :srcset: /auto_examples/numpy_operations/images/sphx_glr_plot_footprint_decompositions_014.png :class: sphx-glr-multi-img .. code-block:: Python 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() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 10.229 seconds) .. _sphx_glr_download_auto_examples_numpy_operations_plot_footprint_decompositions.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/scikit-image/scikit-image/v0.23.2?filepath=notebooks/auto_examples/numpy_operations/plot_footprint_decompositions.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_footprint_decompositions.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_footprint_decompositions.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_