Processing 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
qim3d.processing.blob_detection
blob_detection(vol, background='dark', min_sigma=1, max_sigma=50, sigma_ratio=1.6, threshold=0.5, overlap=0.5, threshold_rel=None, exclude_border=False)
Extract blobs from a volume using Difference of Gaussian (DoG) method, and retrieve a binary volume with the blobs marked as True
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
ndarray
|
The volume to detect blobs in |
required |
background |
str
|
'dark' if background is darker than the blobs, 'bright' if background is lighter than the blobs |
'dark'
|
min_sigma |
float
|
The minimum standard deviation for Gaussian kernel |
1
|
max_sigma |
float
|
The maximum standard deviation for Gaussian kernel |
50
|
sigma_ratio |
float
|
The ratio between the standard deviation of Gaussian Kernels |
1.6
|
threshold |
float
|
The absolute lower bound for scale space maxima. Reduce this to detect blobs with lower intensities |
0.5
|
overlap |
float
|
The fraction of area of two blobs that overlap |
0.5
|
threshold_rel |
float
|
The relative lower bound for scale space maxima |
None
|
exclude_border |
bool
|
If True, exclude blobs that are too close to the border of the image |
False
|
Returns:
Name | Type | Description |
---|---|---|
blobs |
ndarray
|
The blobs found in the volume as (p, r, c, radius) |
binary_volume |
ndarray
|
A binary volume with the blobs marked as True |
Example
import qim3d
# Get data
vol = qim3d.examples.cement_128x128x128
vol_blurred = qim3d.processing.gaussian(vol, sigma=2)
# Detect blobs, and get binary mask
blobs, mask = qim3d.processing.blob_detection(
vol_blurred,
min_sigma=1,
max_sigma=8,
threshold=0.001,
overlap=0.1,
background="bright"
)
# Visualize detected blobs
qim3d.viz.circles(blobs, vol, alpha=0.8, color='blue')
Source code in qim3d/processing/detection.py
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|
qim3d.processing.structure_tensor
structure_tensor(vol, sigma=1.0, rho=6.0, base_noise=True, full=False, visualize=False, **viz_kwargs)
Wrapper for the 3D structure tensor implementation from the structure_tensor package.
The structure tensor algorithm is a method for analyzing the orientation of fiber-like structures in 3D images. The core of the algorithm involves computing a 3-by-3 matrix at each point in a volume, capturing the local orientation. This matrix, known as the structure tensor, is derived from the gradients of the image intensities and integrates neighborhood information using Gaussian kernels.
The implementation here used allows for fast and efficient computation using GPU-based processing, making it suitable for large datasets. This efficiency is particularly advantageous for high-resolution imaging techniques like X-ray computed microtomography (μCT).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
ndarray
|
3D NumPy array representing the volume. |
required |
sigma |
float
|
A noise scale, structures smaller than sigma will be removed by smoothing. |
1.0
|
rho |
float
|
An integration scale giving the size over the neighborhood in which the orientation is to be analysed. |
6.0
|
base_noise |
bool
|
A flag indicating whether to add a small noise to the volume. Default is True. |
True
|
full |
bool
|
A flag indicating that all three eigenvalues should be returned. Default is False. |
False
|
visualize |
bool
|
Whether to visualize the structure tensor. Default is False. |
False
|
**viz_kwargs |
Additional keyword arguments for passed to |
{}
|
Raises:
Type | Description |
---|---|
ValueError
|
If the input volume is not 3D. |
Returns:
Name | Type | Description |
---|---|---|
val |
ndarray
|
An array with shape |
vec |
ndarray
|
An array with shape |
Example
Runtime and memory usage of the structure tensor method for different volume sizes
Performance computed on Intel(R) Xeon(R) Gold 6226 CPU @ 2.70GHz.
Reference
Jeppesen, N., et al. "Quantifying effects of manufacturing methods on fiber orientation in unidirectional composites using structure tensor analysis." Composites Part A: Applied Science and Manufacturing 149 (2021): 106541. https://doi.org/10.1016/j.compositesa.2021.106541
@article{JEPPESEN2021106541,
title = {Quantifying effects of manufacturing methods on fiber orientation in unidirectional composites using structure tensor analysis},
journal = {Composites Part A: Applied Science and Manufacturing},
volume = {149},
pages = {106541},
year = {2021},
issn = {1359-835X},
doi = {https://doi.org/10.1016/j.compositesa.2021.106541},
url = {https://www.sciencedirect.com/science/article/pii/S1359835X21002633},
author = {N. Jeppesen and L.P. Mikkelsen and A.B. Dahl and A.N. Christensen and V.A. Dahl}
}
Source code in qim3d/processing/structure_tensor_.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
|
qim3d.processing.local_thickness
Wrapper for the local thickness function from the local thickness package
The "Fast Local Thickness" by Vedrana Andersen Dahl and Anders Bjorholm Dahl from the Technical University of Denmark is a efficient algorithm for computing local thickness in 2D and 3D images. Their method significantly reduces computation time compared to traditional algorithms by utilizing iterative dilation with small structuring elements, rather than the large ones typically used. This approach allows the local thickness to be determined much faster, making it feasible for high-resolution volumetric data that are common in contemporary 3D microscopy.
Testing against conventional methods and other Python-based tools like PoreSpy shows that the new algorithm is both accurate and faster, offering significant improvements in processing time for large datasets.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
ndarray
|
2D or 3D NumPy array representing the image/volume. If binary, it will be passed directly to the local thickness function. If grayscale, it will be binarized using Otsu's method. |
required |
scale |
float
|
Downscaling factor, e.g. 0.5 for halving each dim of the image. Default is 1. |
1
|
mask |
ndarray
|
binary mask of the same size of the image defining parts of the image to be included in the computation of the local thickness. Default is None. |
None
|
visualize |
bool
|
Whether to visualize the local thickness. Default is False. |
False
|
**viz_kwargs |
Additional keyword arguments passed to |
{}
|
Returns:
Name | Type | Description |
---|---|---|
local_thickness |
ndarray
|
2D or 3D NumPy array representing the local thickness of the input image/volume. |
Example
import qim3d
fly = qim3d.examples.fly_150x256x256 # 3D volume
lt_fly = qim3d.processing.local_thickness(fly, visualize=True, axis=0)
import qim3d
# Generate synthetic collection of blobs
num_objects = 15
synthetic_collection, labels = qim3d.generate.collection(num_objects = num_objects)
# Extract one slice to show that localthickness works on 2D slices too
slice = synthetic_collection[:,:,50]
lt_blobs = qim3d.processing.local_thickness(slice, visualize=True)
Runtime and memory usage of the local thickness method for different volume sizes
Performance computed on Intel(R) Xeon(R) Gold 6226 CPU @ 2.70GHz.
Reference
Dahl, V. A., & Dahl, A. B. (2023, June). Fast Local Thickness. 2023 IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops (CVPRW). https://doi.org/10.1109/cvprw59228.2023.00456
@inproceedings{Dahl_2023, title={Fast Local Thickness},
url={http://dx.doi.org/10.1109/CVPRW59228.2023.00456},
DOI={10.1109/cvprw59228.2023.00456},
booktitle={2023 IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops (CVPRW)},
publisher={IEEE},
author={Dahl, Vedrana Andersen and Dahl, Anders Bjorholm},
year={2023},
month=jun }
Source code in qim3d/processing/local_thickness_.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
|
qim3d.processing.get_3d_cc
Returns an object (CC) containing the connected components of the input volume. Use plot_cc to visualize the connected components.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
ndarray
|
An array-like object to be labeled. Any non-zero values in |
required |
Returns:
Name | Type | Description |
---|---|---|
CC |
CC
|
A ConnectedComponents object containing the connected components and the number of connected components. |
Example
Source code in qim3d/processing/cc.py
qim3d.processing.gaussian
Applies a Gaussian filter to the input volume using scipy.ndimage.gaussian_filter or dask_image.ndfilters.gaussian_filter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
The input image or volume. |
required | |
dask |
Whether to use Dask for the Gaussian filter. |
False
|
|
chunks |
Defines how to divide the array into blocks when using Dask. Can be an integer, tuple, size in bytes, or "auto" for automatic sizing. |
'auto'
|
|
*args |
Additional positional arguments for the Gaussian filter. |
()
|
|
**kwargs |
Additional keyword arguments for the Gaussian filter. |
{}
|
Returns:
Type | Description |
---|---|
The filtered image or volume. |
Source code in qim3d/processing/filters.py
qim3d.processing.median
Applies a median filter to the input volume using scipy.ndimage.median_filter or dask_image.ndfilters.median_filter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
The input image or volume. |
required | |
dask |
Whether to use Dask for the median filter. |
False
|
|
chunks |
Defines how to divide the array into blocks when using Dask. Can be an integer, tuple, size in bytes, or "auto" for automatic sizing. |
'auto'
|
|
**kwargs |
Additional keyword arguments for the median filter. |
{}
|
Returns:
Type | Description |
---|---|
The filtered image or volume. |
Source code in qim3d/processing/filters.py
qim3d.processing.maximum
Applies a maximum filter to the input volume using scipy.ndimage.maximum_filter or dask_image.ndfilters.maximum_filter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
The input image or volume. |
required | |
dask |
Whether to use Dask for the maximum filter. |
False
|
|
chunks |
Defines how to divide the array into blocks when using Dask. Can be an integer, tuple, size in bytes, or "auto" for automatic sizing. |
'auto'
|
|
**kwargs |
Additional keyword arguments for the maximum filter. |
{}
|
Returns:
Type | Description |
---|---|
The filtered image or volume. |
Source code in qim3d/processing/filters.py
qim3d.processing.minimum
Applies a minimum filter to the input volume using scipy.ndimage.minimum_filter or dask_image.ndfilters.minimum_filter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
The input image or volume. |
required | |
dask |
Whether to use Dask for the minimum filter. |
False
|
|
chunks |
Defines how to divide the array into blocks when using Dask. Can be an integer, tuple, size in bytes, or "auto" for automatic sizing. |
'auto'
|
|
**kwargs |
Additional keyword arguments for the minimum filter. |
{}
|
Returns:
Type | Description |
---|---|
The filtered image or volume. |
Source code in qim3d/processing/filters.py
qim3d.processing.tophat
Remove background from the volume.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
The volume to remove background from. |
required | |
radius |
The radius of the structuring element (default: 3). |
required | |
background |
Color of the background, 'dark' or 'bright' (default: 'dark'). If 'bright', volume will be inverted. |
required | |
dask |
Whether to use Dask for the tophat filter (not supported, will default to SciPy). |
False
|
|
chunks |
Defines how to divide the array into blocks when using Dask. Can be an integer, tuple, size in bytes, or "auto" for automatic sizing. |
'auto'
|
|
**kwargs |
Additional keyword arguments. |
{}
|
Returns:
Name | Type | Description |
---|---|---|
vol |
The volume with background removed. |
Source code in qim3d/processing/filters.py
qim3d.processing.get_lines
Expects list of arrays where each array is 2D segmentation with only 2 classes. This function gets the border between those two so it could be plotted. Used with qim3d.processing.segment_layers
Parameters:
Name | Type | Description | Default |
---|---|---|---|
segmentations |
list | ndarray
|
list of arrays where each array is 2D segmentation with only 2 classes |
required |
Returns:
Name | Type | Description |
---|---|---|
segmentation_lines |
list
|
list of 1D numpy arrays |
Source code in qim3d/processing/layers2d.py
qim3d.processing.segment_layers
segment_layers(data, inverted=False, n_layers=1, delta=1, min_margin=10, max_margin=None, wrap=False)
Works on 2D and 3D data. Light one function wrapper around slgbuilder https://github.com/Skielex/slgbuilder to do layer segmentation Now uses only MaxflowBuilder for solving.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
ndarray
|
2D or 3D array on which it will be computed |
required |
inverted |
bool
|
if True, it will invert the brightness of the image |
False
|
n_layers |
int
|
How many layers are we looking for (result in a layer and background) |
1
|
delta |
float
|
Smoothness parameter |
1
|
min_margin |
int
|
If we want more layers, we have to have a margin otherwise they are all going to be exactly the same |
10
|
max_margin |
int
|
Maximum margin between layers |
None
|
wrap |
bool
|
If True, starting and ending point of the border between layers are at the same level |
False
|
Returns:
Name | Type | Description |
---|---|---|
segmentations |
list of numpy arrays, even if n_layers == 1, each array is only 0s and 1s, 1s segmenting this specific layer |
Raises:
Type | Description |
---|---|
TypeError
|
If Data is not np.array, if n_layers is not integer. |
ValueError
|
If n_layers is less than 1, if delta is negative or zero |
Example
Example is only shown on 2D image, but segment_layers can also take 3D structures.
import qim3d
layers_image = qim3d.io.load('layers3d.tif')[:,:,0]
layers = qim3d.processing.segment_layers(layers_image, n_layers = 2)
layer_lines = qim3d.processing.get_lines(layers)
from matplotlib import pyplot as plt
plt.imshow(layers_image, cmap='gray')
plt.axis('off')
for layer_line in layer_lines:
plt.plot(layer_line, linewidth = 3)
Source code in qim3d/processing/layers2d.py
qim3d.processing.create_mesh
Convert a volume to a mesh using the Marching Cubes algorithm, with optional thresholding and padding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
volume |
ndarray
|
The 3D numpy array representing the volume. |
required |
level |
float
|
The threshold value for Marching Cubes. If None, Otsu's method is used. |
None
|
step_size |
int
|
The step size for the Marching Cubes algorithm. |
1
|
allow_degenerate |
bool
|
Whether to allow degenerate (i.e. zero-area) triangles in the end-result. |
False
|
padding |
tuple of int
|
Padding to add around the volume. |
(2, 2, 2)
|
**kwargs |
Any
|
Additional keyword arguments to pass to |
{}
|
Returns:
Name | Type | Description |
---|---|---|
trimesh |
Trimesh
|
The generated mesh. |
Example
Source code in qim3d/processing/mesh.py
qim3d.processing.Pipeline
Example
import qim3d
from qim3d.processing import Pipeline, Median, Gaussian, Maximum, Minimum
# Get data
vol = qim3d.examples.fly_150x256x256
# Show original
qim3d.viz.slices(vol, axis=0, show=True)
# Create filter pipeline
pipeline = Pipeline(
Median(size=5),
Gaussian(sigma=3, dask = True)
)
# Append a third filter to the pipeline
pipeline.append(Maximum(size=3))
# Apply filter pipeline
vol_filtered = pipeline(vol)
# Show filtered
qim3d.viz.slices(vol_filtered, axis=0)
Source code in qim3d/processing/filters.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
|
qim3d.processing.Pipeline.append
Appends a filter to the end of the sequence.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
fn |
Type[FilterBase]
|
An instance of a FilterBase subclass to be appended. |
required |
Example
Source code in qim3d/processing/filters.py
qim3d.processing.operations
qim3d.processing.operations.remove_background
remove_background(vol, median_filter_size=2, min_object_radius=3, background='dark', **median_kwargs)
Remove background from a volume using a qim3d filters.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
ndarray
|
The volume to remove background from. |
required |
median_filter_size |
int
|
The size of the median filter. Defaults to 2. |
2
|
min_object_radius |
int
|
The radius of the structuring element for the tophat filter. Defaults to 3. |
3
|
background |
str
|
The background type. Can be 'dark' or 'bright'. Defaults to 'dark'. |
'dark'
|
**median_kwargs |
Additional keyword arguments for the Median filter. |
{}
|
Returns:
Type | Description |
---|---|
ndarray
|
np.ndarray: The volume with background removed. |
Example
Source code in qim3d/processing/operations.py
qim3d.processing.operations.watershed
Apply watershed segmentation to a binary volume.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
bin_vol |
ndarray
|
Binary volume to segment. The input should be a 3D binary image where non-zero elements represent the objects to be segmented. |
required |
min_distance |
int
|
Minimum number of pixels separating peaks in the distance transform. Peaks that are too close will be merged, affecting the number of segmented objects. Default is 5. |
5
|
Returns:
Type | Description |
---|---|
tuple[ndarray, int]
|
tuple[np.ndarray, int]:
- Labeled volume (np.ndarray): A 3D array of the same shape as the input |
Example
Source code in qim3d/processing/operations.py
qim3d.processing.operations.fade_mask
Apply edge fading to a volume.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vol |
ndarray
|
The volume to apply edge fading to. |
required |
decay_rate |
float
|
The decay rate of the fading. Defaults to 10. |
10
|
ratio |
float
|
The ratio of the volume to fade. Defaults to 0.5. |
0.5
|
geometric |
str
|
The geometric shape of the fading. Can be 'spherical' or 'cylindrical'. Defaults to 'spherical'. |
required |
axis |
int
|
The axis along which to apply the fading. Defaults to 0. |
0
|
Returns:
Name | Type | Description |
---|---|---|
vol_faded |
ndarray
|
The volume with edge fading applied. |
Example
Image before edge fading has visible artifacts from the support. Which obscures the object of interest. Afterwards the artifacts are faded out, making the object of interest more visible for visualization purposes.Source code in qim3d/processing/operations.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
|
qim3d.processing.operations.overlay_rgb_images
Overlay an RGB foreground onto an RGB background using alpha blending.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
background |
ndarray
|
The background RGB image. |
required |
foreground |
ndarray
|
The foreground RGB image (usually masks). |
required |
alpha |
float
|
The alpha value for blending. Defaults to 0.5. |
0.5
|
hide_black |
bool
|
If True, black pixels will have alpha value 0, so the black won't be visible. Used for segmentation where we don't care about background. Defaults to True. |
True
|
Returns:
Name | Type | Description |
---|---|---|
composite |
ndarray
|
The composite RGB image with overlaid foreground. |
Raises:
Type | Description |
---|---|
ValueError
|
If input images have different shapes. |
Note
- The function performs alpha blending to overlay the foreground onto the background.
- It ensures that the background and foreground have the same first two dimensions (image size matches).
- It can handle greyscale images, values from 0 to 1, raw values which are negative or bigger than 255.
- It calculates the maximum projection of the foreground and blends them onto the background.
Source code in qim3d/processing/operations.py
qim3d.processing.features
qim3d.processing.features.area
Compute the surface area of a 3D volume or mesh.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Either a np.ndarray volume or a mesh object of type trimesh.Trimesh. |
required | |
**mesh_kwargs |
Additional arguments for mesh creation if the input is a volume. |
{}
|
Returns:
Name | Type | Description |
---|---|---|
area |
float
|
The surface area of the object. |
Example
Compute area from a mesh:
import qim3d
# Load a mesh from a file
mesh = qim3d.io.load_mesh('path/to/mesh.obj')
# Compute the surface area of the mesh
area = qim3d.processing.area(mesh)
print(f"Area: {area}")
Compute area from a np.ndarray:
Source code in qim3d/processing/features.py
qim3d.processing.features.volume
Compute the volume of a 3D volume or mesh.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Either a np.ndarray volume or a mesh object of type trimesh.Trimesh. |
required | |
**mesh_kwargs |
Additional arguments for mesh creation if the input is a volume. |
{}
|
Returns:
Name | Type | Description |
---|---|---|
volume |
float
|
The volume of the object. |
Example
Compute volume from a mesh:
import qim3d
# Load a mesh from a file
mesh = qim3d.io.load_mesh('path/to/mesh.obj')
# Compute the volume of the mesh
volume = qim3d.processing.volume(mesh)
print('Volume:', volume)
Compute volume from a np.ndarray:
Source code in qim3d/processing/features.py
qim3d.processing.features.sphericity
Compute the sphericity of a 3D volume or mesh.
Sphericity is a measure of how spherical an object is. It is defined as the ratio of the surface area of a sphere with the same volume as the object to the object's actual surface area.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Either a np.ndarray volume or a mesh object of type trimesh.Trimesh. |
required | |
**mesh_kwargs |
Additional arguments for mesh creation if the input is a volume. |
{}
|
Returns:
Name | Type | Description |
---|---|---|
sphericity |
float
|
A float value representing the sphericity of the object. |
Example
Compute sphericity from a mesh:
import qim3d
# Load a mesh from a file
mesh = qim3d.io.load_mesh('path/to/mesh.obj')
# Compute the sphericity of the mesh
sphericity = qim3d.processing.sphericity(mesh)
Compute sphericity from a np.ndarray:
Limitations due to pixelation
Sphericity is particularly sensitive to the resolution of the mesh, as it directly impacts the accuracy of surface area and volume calculations. Since the mesh is generated from voxel-based 3D volume data, the discrete nature of the voxels leads to pixelation effects that reduce the precision of sphericity measurements. Higher resolution meshes may mitigate these errors but often at the cost of increased computational demands.