Skip to content

Morphology

Morphological operations for volumetric data.

qim3d.morphology.black_tophat

black_tophat(volume, kernel, method='scipy.ndimage', **kwargs)

Performs the black top-hat transform on a 3D volume.

The black top-hat transform is defined as the difference between the morphological closing of the volume and the original volume (Closing - Input). It is used to extract dark features and valleys that are smaller than the structuring element (kernel) from a brighter background. This is particularly effective for background correction or isolating small dark structures in a non-uniformly lit image.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
bothat_vol ndarray

The processed volume containing the extracted dark features.

Example
import qim3d
import numpy as np

# Generate tubular synthetic blob
vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

# Visualize synthetic volume
qim3d.viz.volumetric(vol)
# Apply the black top-hat to extract dark details
vol_black = qim3d.morphology.black_tophat(vol, kernel=(10,10,10), method='scipy.ndimage')

qim3d.viz.volumetric(vol_black)
Source code in qim3d/morphology/_common_morphologies.py
def black_tophat(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs the black top-hat transform on a 3D volume.

    The black top-hat transform is defined as the difference between the morphological closing of the volume and the original volume (Closing - Input). It is used to extract dark features and valleys that are smaller than the structuring element (kernel) from a brighter background. This is particularly effective for background correction or isolating small dark structures in a non-uniformly lit image.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        bothat_vol (np.ndarray):
            The processed volume containing the extracted dark features.

    Example:
        <!-- k3d-example: black-tophat -->

        ```python
        import qim3d
        import numpy as np

        # Generate tubular synthetic blob
        vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

        # Visualize synthetic volume
        qim3d.viz.volumetric(vol)
        ```
        <!-- k3d-output: black-tophat/original -->

        ```python
        # Apply the black top-hat to extract dark details
        vol_black = qim3d.morphology.black_tophat(vol, kernel=(10,10,10), method='scipy.ndimage')

        qim3d.viz.volumetric(vol_black)
        ```
        <!-- k3d-output: black-tophat/dark-details -->
        <!-- /k3d-example -->
    """

    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.black_tophat(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)

qim3d.morphology.closing

closing(volume, kernel, method='scipy.ndimage', **kwargs)

Performs morphological closing on a 3D volume.

Closing is defined as a dilation followed by an erosion. It is primarily used to fill small dark holes, cracks, or gaps within bright objects while preserving their overall shape and size. It smooths object contours by fusing narrow breaks and filling small depressions.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
closed_vol ndarray

The closed volume.

Example
import qim3d
import numpy as np

# Generate a cube with a hole through it
cube = np.zeros((110,110,110))
cube[10:90, 10:90, 10:90] = 1
cube[60:70,:,60:70]=0

# Visualize synthetic volume
qim3d.viz.volumetric(cube)
# Apply closing
cube_closed = qim3d.morphology.closing(cube, kernel=(15,15,15), method='scipy.ndimage')

# Visualize
qim3d.viz.volumetric(cube_closed)
Source code in qim3d/morphology/_common_morphologies.py
def closing(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs morphological closing on a 3D volume.

    Closing is defined as a **dilation** followed by an **erosion**. It is primarily used to fill small dark holes, cracks, or gaps within bright objects while preserving their overall shape and size. It smooths object contours by fusing narrow breaks and filling small depressions.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        closed_vol (np.ndarray):
            The closed volume.

    Example:
        <!-- k3d-example: closing -->

        ```python
        import qim3d
        import numpy as np

        # Generate a cube with a hole through it
        cube = np.zeros((110,110,110))
        cube[10:90, 10:90, 10:90] = 1
        cube[60:70,:,60:70]=0

        # Visualize synthetic volume
        qim3d.viz.volumetric(cube)
        ```
        <!-- k3d-output: closing/perforated-cube -->
        ```python
        # Apply closing
        cube_closed = qim3d.morphology.closing(cube, kernel=(15,15,15), method='scipy.ndimage')

        # Visualize
        qim3d.viz.volumetric(cube_closed)
        ```
        <!-- k3d-output: closing/closed-cube -->
        <!-- /k3d-example -->
    """

    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.grey_closing(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)

qim3d.morphology.dilate

dilate(volume, kernel, method='scipy.ndimage', **kwargs)

Performs morphological dilation on a 3D volume.

Dilation enlarges bright regions (foreground) and shrinks dark regions (background). It is commonly used to close small holes, connect disjoint features, or thicken object boundaries.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
dilated_vol ndarray

The dilated volume.

Example
import qim3d
import numpy as np

# Generate tubular synthetic blob
vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

# Visualize synthetic volume
qim3d.viz.volumetric(vol)
# Apply dilation
vol_dilated = qim3d.morphology.dilate(vol, kernel=(8,8,8), method='scipy.ndimage')

# Visualize
qim3d.viz.volumetric(vol_dilated)
Source code in qim3d/morphology/_common_morphologies.py
def dilate(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs morphological dilation on a 3D volume.

    Dilation enlarges bright regions (foreground) and shrinks dark regions (background). It is commonly used to close small holes, connect disjoint features, or thicken object boundaries.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        dilated_vol (np.ndarray):
            The dilated volume.

    Example:
        <!-- k3d-example: dilation -->

        ```python
        import qim3d
        import numpy as np

        # Generate tubular synthetic blob
        vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

        # Visualize synthetic volume
        qim3d.viz.volumetric(vol)
        ```
        <!-- k3d-output: dilation/original -->

        ```python
        # Apply dilation
        vol_dilated = qim3d.morphology.dilate(vol, kernel=(8,8,8), method='scipy.ndimage')

        # Visualize
        qim3d.viz.volumetric(vol_dilated)
        ```
        <!-- k3d-output: dilation/dilated -->
        <!-- /k3d-example -->
    """

    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.grey_dilation(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)

qim3d.morphology.erode

erode(volume, kernel, method='scipy.ndimage', **kwargs)

Performs morphological erosion on a 3D volume.

Erosion shrinks bright regions (foreground) and enlarges dark regions (background). It is commonly used to remove small noise (salt noise), detach touching objects, or thin out features.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
eroded_vol ndarray

The eroded volume.

Example
import qim3d
import numpy as np

# Generate tubular synthetic blob
vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

# Visualize synthetic volume
qim3d.viz.volumetric(vol)
# Apply erosion
vol_eroded = qim3d.morphology.erode(vol, kernel=(10,10,10), method='scipy.ndimage')

# Visualize
qim3d.viz.volumetric(vol_eroded)
Source code in qim3d/morphology/_common_morphologies.py
def erode(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs morphological erosion on a 3D volume.

    Erosion shrinks bright regions (foreground) and enlarges dark regions (background). It is commonly used to remove small noise (salt noise), detach touching objects, or thin out features.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        eroded_vol (np.ndarray):
            The eroded volume.

    Example:
        <!-- k3d-example: erosion -->

        ```python
        import qim3d
        import numpy as np

        # Generate tubular synthetic blob
        vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

        # Visualize synthetic volume
        qim3d.viz.volumetric(vol)
        ```
        <!-- k3d-output: erosion/original -->
        ```python
        # Apply erosion
        vol_eroded = qim3d.morphology.erode(vol, kernel=(10,10,10), method='scipy.ndimage')

        # Visualize
        qim3d.viz.volumetric(vol_eroded)
        ```
        <!-- k3d-output: erosion/eroded -->
        <!-- /k3d-example -->
    """

    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.grey_erosion(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)

qim3d.morphology.opening

opening(volume, kernel, method='scipy.ndimage', **kwargs)

Performs morphological opening on a 3D volume.

Opening is defined as an erosion followed by a dilation. It is primarily used to remove small bright objects (salt noise) from the background while preserving the shape and size of larger objects. It smooths object contours by breaking narrow isthmuses and eliminating thin protrusions.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
opened_vol ndarray

The opened volume.

Example
import qim3d
import numpy as np

# Generate tubular synthetic blob
vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

# Add noise to the data
vol_noised = qim3d.generate.background(
    background_shape=vol.shape,
    apply_method = 'add',
    apply_to = vol
)

# Visualize synthetic volume
qim3d.viz.volumetric(vol_noised, grid_visible=True)
# Apply opening
vol_opened = qim3d.morphology.opening(vol_noised, kernel=(6,6,6), method='scipy.ndimage')

# Visualize
qim3d.viz.volumetric(vol_opened)
Source code in qim3d/morphology/_common_morphologies.py
def opening(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs morphological opening on a 3D volume.

    Opening is defined as an **erosion** followed by a **dilation**. It is primarily used to remove small bright objects (salt noise) from the background while preserving the shape and size of larger objects. It smooths object contours by breaking narrow isthmuses and eliminating thin protrusions.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        opened_vol (np.ndarray):
            The opened volume.

    Example:
        <!-- k3d-example: opening -->

        ```python
        import qim3d
        import numpy as np

        # Generate tubular synthetic blob
        vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

        # Add noise to the data
        vol_noised = qim3d.generate.background(
            background_shape=vol.shape,
            apply_method = 'add',
            apply_to = vol
        )

        # Visualize synthetic volume
        qim3d.viz.volumetric(vol_noised, grid_visible=True)
        ```

        <!-- k3d-output: opening/noisy -->

        ```python
        # Apply opening
        vol_opened = qim3d.morphology.opening(vol_noised, kernel=(6,6,6), method='scipy.ndimage')

        # Visualize
        qim3d.viz.volumetric(vol_opened)
        ```

        <!-- k3d-output: opening/opened -->
        <!-- /k3d-example -->
    """
    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.grey_opening(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)

qim3d.morphology.white_tophat

white_tophat(volume, kernel, method='scipy.ndimage', **kwargs)

Performs the white top-hat transform on a 3D volume.

The white top-hat transform is defined as the difference between the original volume and its morphological opening (Input - Opening). It is used to extract bright features and peaks that are smaller than the structuring element (kernel) from a darker background. This is a powerful tool for background subtraction, enhancing small bright spots, or correcting uneven illumination in a volume.

Parameters:

Name Type Description Default
volume ndarray

The input 3D volume.

required
kernel (int, tuple or ndarray)

The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.

required
method Literal['scipy.ndimage']

The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.

'scipy.ndimage'
**kwargs Any

Additional keyword arguments passed to the underlying method.

{}

Returns:

Name Type Description
tophat_vol ndarray

The processed volume containing the extracted bright features.

Example
import qim3d
import numpy as np

# Generate tubular synthetic blob
vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

# Visualize synthetic volume
qim3d.viz.volumetric(vol)
# Apply the white top-hat to extract bright details
vol_white = qim3d.morphology.white_tophat(vol, kernel=(10,10,10), method='scipy.ndimage')

qim3d.viz.volumetric(vol_white)
Source code in qim3d/morphology/_common_morphologies.py
def white_tophat(
    volume: np.ndarray,
    kernel: int | tuple | np.ndarray,
    method: Literal["scipy.ndimage"] = "scipy.ndimage",
    **kwargs,
) -> np.ndarray:
    """
    Performs the white top-hat transform on a 3D volume.

    The white top-hat transform is defined as the difference between the original volume and its morphological opening (Input - Opening). It is used to extract bright features and peaks that are smaller than the structuring element (kernel) from a darker background. This is a powerful tool for background subtraction, enhancing small bright spots, or correcting uneven illumination in a volume.

    Args:
        volume (np.ndarray): The input 3D volume.
        kernel (int, tuple or np.ndarray): The structuring element. An int gives a cube of that side length, a tuple of 3 ints a box of that shape, and a 3D array is used directly as the footprint.
        method (Literal["scipy.ndimage"], optional): The backend implementation to use. Currently only 'scipy.ndimage' is supported. Defaults to 'scipy.ndimage'.
        **kwargs (Any): Additional keyword arguments passed to the underlying method.

    Returns:
        tophat_vol (np.ndarray):
            The processed volume containing the extracted bright features.

    Example:
        <!-- k3d-example: white-tophat -->

        ```python
        import qim3d
        import numpy as np

        # Generate tubular synthetic blob
        vol = qim3d.generate.volume(noise_scale=0.025, seed=50)

        # Visualize synthetic volume
        qim3d.viz.volumetric(vol)
        ```
        <!-- k3d-output: white-tophat/original -->

        ```python
        # Apply the white top-hat to extract bright details
        vol_white = qim3d.morphology.white_tophat(vol, kernel=(10,10,10), method='scipy.ndimage')

        qim3d.viz.volumetric(vol_white)
        ```
        <!-- k3d-output: white-tophat/bright-details -->
        <!-- /k3d-example -->
    """

    try:
        volume = np.asarray(volume)
    except TypeError as e:
        err = "Input volume must be array-like."
        raise TypeError(err) from e

    assert len(volume.shape) == 3, "Volume must be three-dimensional."

    if method == "scipy.ndimage":
        kernel = _create_kernel(kernel)
        assert kernel.ndim == 3, "Kernel must a 3D np.ndarray."

        return ndi.white_tophat(volume, footprint=kernel, **kwargs)

    else:
        err = f"Unknown method '{method}'. Supported: 'scipy.ndimage'."
        raise ValueError(err)