diff --git a/.gitignore b/.gitignore index 6acf99ddd141ad1b3f5df7ed086840fe8074a5a6..d0990d6dc47420c48da2cf26392051f02c7f5d06 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ build/ # Notebook checkpoints .ipynb_checkpoints/ + +# MacOS finder files +*.DS_Store \ No newline at end of file diff --git a/docs/assets/screenshots/operations-remove_background_after.png b/docs/assets/screenshots/operations-remove_background_after.png new file mode 100644 index 0000000000000000000000000000000000000000..0148a8f65a770f6707fa7264ad41a0c30ecbfac0 Binary files /dev/null and b/docs/assets/screenshots/operations-remove_background_after.png differ diff --git a/docs/assets/screenshots/operations-remove_background_before.png b/docs/assets/screenshots/operations-remove_background_before.png new file mode 100644 index 0000000000000000000000000000000000000000..e4c63b94598b763df56075475bf0e09ce4ff7970 Binary files /dev/null and b/docs/assets/screenshots/operations-remove_background_before.png differ diff --git a/docs/processing.md b/docs/processing.md index b469a21c6bf8cf1c9115e9efa0f9404dd62c9b53..2987f9f74c493a2032cbba95c903db2cc2fa056a 100644 --- a/docs/processing.md +++ b/docs/processing.md @@ -1,6 +1,6 @@ # Processing data -`qim3d` provides various tools for 3D image processing. Here, we provide a suite of powerful functionalities designed specifically for 3D image analysis and processing. From filter pipelines to structure tensor computation and blob detection, `qim3d` equips you with the tools you need to extract meaningful insights from your data. +Here, we provide functionalities designed specifically for 3D image analysis and processing. From filter pipelines to structure tensor computation and blob detection, `qim3d` equips you with the tools you need to extract meaningful insights from your data. ::: qim3d.processing options: @@ -9,4 +9,9 @@ - local_thickness - get_3d_cc - Pipeline - - Blob \ No newline at end of file + - Blob + +::: qim3d.processing.operations + options: + members: + - remove_background diff --git a/docs/releases.md b/docs/releases.md index 3f611b8c1992b6f31560b58bb54f1e59725a2bca..64a04fd7137771be248d71eddc0773b8cef93569 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -18,6 +18,7 @@ And remember to keep your pip installation [up to date](/qim3d/#upgrade) so that - Support for loading DICOM files with `qim3d.io.load`🎉 - Introduction of `qim3d.processing.get_3d_cc` for 3D connected components and `qim3d.viz.plot_cc` for associated visualization 🎉 - Introduction of `qim3d.viz.colormaps` for easy visualization of e.g. multi-label segmentation results 🎉 +- Introduction of `qim3d.processing.operations.background_removal` 🎉 ### v0.3.2 (23/02/2024) diff --git a/qim3d/processing/__init__.py b/qim3d/processing/__init__.py index 18b959f02996a87d8e4a2c46c0577c02419ecae7..34dea0c4f0c556184277de549acf22dc9ad3f59e 100644 --- a/qim3d/processing/__init__.py +++ b/qim3d/processing/__init__.py @@ -2,4 +2,5 @@ from .local_thickness_ import local_thickness from .structure_tensor_ import structure_tensor from .filters import * from .detection import * +from .operations import * from .cc import get_3d_cc diff --git a/qim3d/processing/filters.py b/qim3d/processing/filters.py index c7d39ef901f834aa12828c7f9cad014dd416b73a..354214c4d7e699de2c934cfbfed0710dd51e1c23 100644 --- a/qim3d/processing/filters.py +++ b/qim3d/processing/filters.py @@ -1,8 +1,12 @@ """Provides filter functions and classes for image processing""" -from typing import Union, Type +from typing import Type, Union + import numpy as np from scipy import ndimage +from skimage import morphology + +from qim3d.io.logger import log __all__ = [ "Gaussian", @@ -10,10 +14,12 @@ __all__ = [ "Maximum", "Minimum", "Pipeline", + "Tophat", "gaussian", "median", "maximum", "minimum", + "tophat", ] @@ -85,6 +91,19 @@ class Minimum(FilterBase): """ return minimum(input, **self.kwargs) +class Tophat(FilterBase): + def __call__(self, input): + """ + Applies a tophat filter to the input. + + Args: + input: The input image or volume. + + Returns: + The filtered image or volume. + """ + return tophat(input, **self.kwargs) + class Pipeline: """ @@ -243,3 +262,28 @@ def minimum(vol, **kwargs): The filtered image or volume. """ return ndimage.minimum_filter(vol, **kwargs) + +def tophat(vol, **kwargs): + """ + Remove background from the volume + Args: + vol: The volume to remove background from + radius: The radius of the structuring element (default: 3) + background: color of the background, 'dark' or 'bright' (default: 'dark'). If 'bright', volume will be inverted. + Returns: + vol: The volume with background removed + """ + radius = kwargs["radius"] if "radius" in kwargs else 3 + background = kwargs["background"] if "background" in kwargs else "dark" + + if background == "bright": + log.info("Bright background selected, volume will be temporarily inverted when applying white_tophat") + vol = np.invert(vol) + + selem = morphology.ball(radius) + vol = vol - morphology.white_tophat(vol, selem) + + if background == "bright": + vol = np.invert(vol) + + return vol diff --git a/qim3d/processing/operations.py b/qim3d/processing/operations.py new file mode 100644 index 0000000000000000000000000000000000000000..70193564e4ccde690d61a71c70714ed3d1b4cbe9 --- /dev/null +++ b/qim3d/processing/operations.py @@ -0,0 +1,51 @@ +import numpy as np +import qim3d.processing.filters as filters + + +def remove_background( + vol: np.ndarray, + median_filter_size: int = 2, + min_object_radius: int = 3, + background: str = "dark", + **median_kwargs +) -> np.ndarray: + """ + Remove background from a volume using a qim3d filters. + + Args: + vol (np.ndarray): The volume to remove background from. + median_filter_size (int, optional): The size of the median filter. Defaults to 2. + min_object_radius (int, optional): The radius of the structuring element for the tophat filter. Defaults to 3. + background (str, optional): The background type. Can be 'dark' or 'bright'. Defaults to 'dark'. + **median_kwargs: Additional keyword arguments for the Median filter. + + Returns: + np.ndarray: The volume with background removed. + + + Example: + ```python + import qim3d + + vol = qim3d.examples.cement_128x128x128 + qim3d.viz.slices(vol, vmin=0, vmax=255) + ``` +  + + ```python + vol_filtered = qim3d.processing.operations.remove_background(vol, + min_object_radius=3, + background="bright") + qim3d.viz.slices(vol_filtered, vmin=0, vmax=255) + ``` +  + """ + + # Create a pipeline with a median filter and a tophat filter + pipeline = filters.Pipeline( + filters.Median(size=median_filter_size, **median_kwargs), + filters.Tophat(radius=min_object_radius, background=background), + ) + + # Apply the pipeline to the volume + return pipeline(vol)