imagetools module
- class clabtoolkit.imagetools.MorphologicalOperations[source]
Bases:
objectA class to perform morphological operations on binary arrays.
Provides methods for common morphological operations including erosion, dilation, opening, closing, and hole filling on 2D and 3D binary images.
- create_structuring_element(shape='cube', size=3, dimensions=None)[source]
Create a structuring element for morphological operations.
- Parameters:
- Returns:
Boolean array representing the structuring element.
- Return type:
np.ndarray
- Raises:
ValueError – If shape is not supported or dimensions are invalid.
Examples
>>> morph = MorphologicalOperations() >>> cube_elem = morph.create_structuring_element('cube', size=5) >>> ball_elem = morph.create_structuring_element('ball', size=7, dimensions=3)
- erode(binary_array, structure=None, iterations=1)[source]
Perform binary erosion to shrink objects and remove small noise.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. If None, uses default 3x3 or 3x3x3 cube. Default is None.
iterations (int, optional) – Number of erosion iterations. Default is 1.
- Returns:
Eroded binary array.
- Return type:
np.ndarray
Examples
>>> eroded = morph.erode(binary_image, iterations=2)
- dilate(binary_array, structure=None, iterations=1)[source]
Perform binary dilation to expand objects and fill small gaps.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. If None, uses default 3x3 or 3x3x3 cube. Default is None.
iterations (int, optional) – Number of dilation iterations. Default is 1.
- Returns:
Dilated binary array.
- Return type:
np.ndarray
Examples
>>> dilated = morph.dilate(binary_image, iterations=3)
- opening(binary_array, structure=None, iterations=1)[source]
Perform morphological opening (erosion followed by dilation).
Removes small objects and noise while preserving larger structures.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. Default is None.
iterations (int, optional) – Number of iterations. Default is 1.
- Returns:
Opened binary array.
- Return type:
np.ndarray
Examples
>>> cleaned = morph.opening(noisy_image, iterations=2)
- closing(binary_array, structure=None, iterations=1)[source]
Perform morphological closing (dilation followed by erosion).
Fills small holes and gaps while preserving object size.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. Default is None.
iterations (int, optional) – Number of iterations. Default is 1.
- Returns:
Closed binary array.
- Return type:
np.ndarray
Examples
>>> filled = morph.closing(image_with_holes, iterations=1)
- fill_holes(binary_array, structure=None)[source]
Fill holes in binary objects.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element for connectivity. Default is None.
- Returns:
Binary array with filled holes.
- Return type:
np.ndarray
Examples
>>> filled = morph.fill_holes(binary_mask)
- remove_small_objects(binary_array, min_size=50)[source]
Remove connected components smaller than specified size.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
min_size (int, optional) – Minimum size of objects to keep in voxels/pixels. Default is 50.
- Returns:
Binary array with small objects removed.
- Return type:
np.ndarray
Examples
>>> cleaned = morph.remove_small_objects(binary_image, min_size=100)
- gradient(binary_array, structure=None)[source]
Morphological gradient (dilation - erosion) to highlight object boundaries.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. Default is None.
- Returns:
Binary array containing object boundaries.
- Return type:
np.ndarray
Examples
>>> edges = morph.gradient(binary_object)
- tophat(binary_array, structure=None)[source]
White top-hat transform (original - opening) to extract small bright structures.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. Default is None.
- Returns:
Binary array containing small bright structures.
- Return type:
np.ndarray
Examples
>>> small_objects = morph.tophat(binary_image)
- blackhat(binary_array, structure=None)[source]
Black top-hat transform (closing - original) to extract small dark structures.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
structure (np.ndarray, optional) – Structuring element. Default is None.
- Returns:
Binary array containing small dark structures (holes).
- Return type:
np.ndarray
Examples
>>> small_holes = morph.blackhat(binary_image)
- clabtoolkit.imagetools.quick_morphology(binary_array, operation, **kwargs)[source]
Quick access to morphological operations without creating class instance.
- Parameters:
binary_array (np.ndarray) – Binary numpy array (2D or 3D).
operation (str) – Operation name: ‘erode’, ‘dilate’, ‘opening’, ‘closing’, ‘fill_holes’, ‘remove_small’, ‘gradient’, ‘tophat’, ‘blackhat’.
**kwargs – Additional arguments for the specific operation.
- Returns:
Result of the morphological operation.
- Return type:
np.ndarray
- Raises:
ValueError – If operation is not supported.
Examples
>>> # Quick erosion >>> eroded = quick_morphology(binary_image, 'erode', iterations=2) >>> >>> # Quick hole filling >>> filled = quick_morphology(binary_mask, 'fill_holes')
- clabtoolkit.imagetools.get_voxel_size(affine)[source]
Compute voxel dimensions from NIfTI affine matrix.
- Parameters:
affine (np.ndarray) – 4x4 affine transformation matrix from NIfTI header.
- Returns:
Voxel sizes (voxel_x, voxel_y, voxel_z) in mm.
- Return type:
Examples
>>> img = nib.load('image.nii.gz') >>> vox_x, vox_y, vox_z = get_voxel_size(img.affine) >>> print(f"Voxel size: {vox_x:.2f} x {vox_y:.2f} x {vox_z:.2f} mm")
- clabtoolkit.imagetools.get_voxel_volume(affine)[source]
Compute voxel dimensions from an affine matrix.
- Parameters:
affine (np.ndarray) – 4x4 affine transformation matrix from NIfTI header.
- Returns:
Voxel sizes (voxel_x, voxel_y, voxel_z) in mm.
- Return type:
Examples
>>> img = nib.load('image.nii.gz') >>> vox_x, vox_y, vox_z = get_voxel_size(img.affine) >>> print(f"Voxel size: {vox_x:.2f} x {vox_y:.2f} x {vox_z:.2f} mm")
- clabtoolkit.imagetools.get_center(affine)[source]
Compute voxel volume from NIfTI affine matrix.
- Parameters:
affine (np.ndarray) – 4x4 affine transformation matrix from NIfTI header.
- Returns:
Voxel volume in mm³.
- Return type:
Examples
>>> img = nib.load('image.nii.gz') >>> volume = get_voxel_volume(img.affine) >>> print(f"Voxel volume: {volume:.3f} mm³")
- clabtoolkit.imagetools.get_rotation_matrix(affine)[source]
Extract normalized rotation matrix from affine matrix.
- Parameters:
affine (np.ndarray) – 4x4 affine transformation matrix from NIfTI header.
- Returns:
3x3 normalized rotation matrix (without scaling).
- Return type:
np.ndarray
Examples
>>> rotation = get_rotation_matrix(img.affine) >>> print(f"Rotation matrix shape: {rotation.shape}")
- clabtoolkit.imagetools.get_vox_neighbors(coord, neighborhood='26', dims='3', order=1)[source]
Get neighborhood coordinates for a voxel.
- Parameters:
coord (np.ndarray) – Coordinates of the center voxel.
neighborhood (str, optional) – Neighborhood type: ‘6’, ‘18’, ‘26’ for 3D or ‘4’, ‘8’ for 2D. Default is ‘26’.
dims (str, optional) – Number of dimensions: ‘2’ or ‘3’. Default is ‘3’.
order (int, optional) – Order parameter (currently unused). Default is 1.
- Returns:
Array of neighbor coordinates.
- Return type:
np.ndarray
- Raises:
ValueError – If dimensions don’t match coordinates or neighborhood type is invalid.
Examples
>>> # Get 26-connected neighbors in 3D >>> center = np.array([10, 15, 20]) >>> neighbors = get_vox_neighbors(center, neighborhood='26', dims='3') >>> print(f"Found {len(neighbors)} neighbors")
- clabtoolkit.imagetools.crop_image_from_mask(in_image, mask, out_image, st_codes=None)[source]
Crop image using a mask to minimum bounding box containing specified structures.
- Parameters:
in_image (str) – Path to input image file.
mask (str or np.ndarray) – Path to mask file or mask array. Can be binary or multi-label.
out_image (str) – Path for output cropped image.
st_codes (list or np.ndarray, optional) – Structure codes to include in cropping. If None, uses all non-zero values. Default is None.
- Returns:
Path to the created output image.
- Return type:
- Raises:
ValueError – If input parameters are invalid or files don’t exist.
Examples
>>> # Crop using binary mask >>> output = crop_image_from_mask( ... 'brain.nii.gz', 'mask.nii.gz', 'cropped_brain.nii.gz' ... ) >>> >>> # Crop specific structures >>> output = crop_image_from_mask( ... 'image.nii.gz', 'segmentation.nii.gz', 'cropped.nii.gz', ... st_codes=[1, 2, 3] ... )
- clabtoolkit.imagetools.cropped_to_native(in_image, native_image, out_image)[source]
Restore cropped image to dimensions of reference native image.
- Parameters:
- Returns:
Path to the created output image.
- Return type:
- Raises:
ValueError – If input parameters are not strings.
Examples
>>> # Restore cropped image to original dimensions >>> restored = cropped_to_native( ... 'cropped_result.nii.gz', ... 'original.nii.gz', ... 'restored_result.nii.gz' ... )
- clabtoolkit.imagetools.apply_multi_transf(in_image, out_image, ref_image, xfm_output, interp_order=0, invert=False, cont_tech='local', cont_image=None, force=False)[source]
Apply ANTs transformation to image with support for multiple transform types.
- Parameters:
in_image (str) – Path to input image.
out_image (str) – Path for transformed output image.
ref_image (str) – Path to reference image defining target space.
xfm_output (str) – Path to transformation files (supports affine and nonlinear).
interp_order (int, optional) – Interpolation method: 0=NearestNeighbor, 1=Linear, 2=BSpline, etc. Default is 0.
invert (bool, optional) – Whether to invert the transformation. Default is False.
cont_tech (str, optional) – Container technology: ‘local’, ‘singularity’, ‘docker’. Default is ‘local’.
cont_image (str, optional) – Container image specification. Default is None.
force (bool, optional) – Force recomputation if output exists. Default is False.
Examples
>>> # Apply transformation with nearest neighbor interpolation >>> apply_multi_transf( ... 'input.nii.gz', 'output.nii.gz', 'template.nii.gz', ... 'transform_prefix', interp_order=0 ... )
- clabtoolkit.imagetools.vox2mm(vox_coords, affine)[source]
Convert voxel coordinates to millimeter coordinates using affine matrix.
- Parameters:
vox_coords (np.ndarray) – Matrix with voxel coordinates (N x 3).
affine (np.ndarray) – 4x4 affine transformation matrix.
- Returns:
Matrix with millimeter coordinates (N x 3).
- Return type:
np.ndarray
- Raises:
ValueError – If input matrix doesn’t have 3 columns.
Examples
>>> # Convert voxel coordinates to mm >>> vox_coords = np.array([[10, 20, 30], [15, 25, 35]]) >>> mm_coords = vox2mm(vox_coords, img.affine) >>> print(f"MM coordinates: {mm_coords}")
- clabtoolkit.imagetools.mm2vox(mm_coords, affine)[source]
Convert millimeter coordinates to voxel coordinates using affine matrix.
- Parameters:
mm_coords (np.ndarray) – Matrix with millimeter coordinates (N x 3).
affine (np.ndarray) – 4x4 affine transformation matrix.
- Returns:
Matrix with voxel coordinates (N x 3).
- Return type:
np.ndarray
- Raises:
ValueError – If input matrix doesn’t have 3 columns.
Examples
>>> # Convert mm coordinates to voxels >>> mm_coords = np.array([[45.5, -12.3, 78.9]]) >>> vox_coords = mm2vox(mm_coords, img.affine) >>> print(f"Voxel coordinates: {vox_coords}")
- clabtoolkit.imagetools.merge_to_4d(file_paths, output_path=None, check_affine=True)[source]
Merge multiple 3D NIfTI files into a single 4D NIfTI file.
Takes a list of NIfTI file paths and combines them along the 4th dimension to create a 4D volume. This is commonly used for creating time series datasets or multi-contrast imaging data.
- Parameters:
file_paths (list of str or Path) – List of paths to 3D NIfTI files to be merged. Files should have identical spatial dimensions and preferably the same affine matrix.
output_path (str or Path, optional) – Path where the merged 4D NIfTI file should be saved. If None, the file is not saved to disk.
check_affine (bool, default True) – Whether to check that all input files have the same affine matrix. If True, raises ValueError for mismatched affines.
- Returns:
A 4D NIfTI image where the 4th dimension corresponds to the input files in the order provided.
- Return type:
nibabel.Nifti1Image
- Raises:
ValueError – If input files have different spatial dimensions or affine matrices (when check_affine=True).
FileNotFoundError – If any of the input files cannot be found.
IOError – If there are issues reading the NIfTI files.
Examples
>>> file_list = ['vol001.nii.gz', 'vol002.nii.gz', 'vol003.nii.gz'] >>> merged_img = merge_nifti_to_4d(file_list, 'merged_4d.nii.gz') >>> print(merged_img.shape) # (64, 64, 30, 3) for example
>>> # Merge without saving to disk >>> merged_img = merge_nifti_to_4d(file_list) >>> data_4d = merged_img.get_fdata()
Notes
All input files must have the same spatial dimensions (x, y, z). The resulting 4D array will have shape (x, y, z, n) where n is the number of input files.
Memory usage scales with the total size of all input volumes, so consider available RAM when processing large datasets.
- clabtoolkit.imagetools.create_spams(in_parcs, out_spams, lut_table, save_color_spams=False, rgb255=True)[source]
Create SPAM probability maps from multiple parcellation images. Generates spatial probability maps (SPAMs) from a list of parcellation images, using a lookup table (LUT) for region definitions and colors.
- Parameters:
in_parcs (list of str or Path) – List of file paths to input parcellation images.
out_spams (str or Path) – File path for the output SPAM image.
lut_table (str, Path, or dict) – Path to LUT file (TSV or LUT format) or a dictionary with ‘index’, ‘name’, and ‘color’ keys defining regions.
save_color_spams (bool, optional) – Whether to save a color-coded SPAM image. Default is False.
rgb255 (bool, optional) – Whether to scale RGB colors to 0-255 range. Default is True.
- Raises:
ValueError – If input parameters are invalid.
Examples
>>> # Create SPAMs from parcellations with LUT file >>> create_spams( ... in_parcs=['subj1_parc.nii.gz', 'subj2_parc.nii.gz'], ... out_spams='group_spams.nii.gz ... lut_table='parc_lut.tsv', ... save_color_spams=True, ... rgb255=True ... )
- clabtoolkit.imagetools.spams2maxprob(spam_image, prob_thresh=0.05, vol_indexes=None, maxp_name=None)[source]
Convert SPAM probability maps to maximum probability parcellation.
Transforms 4D spatial probability maps into discrete 3D parcellation by selecting the most probable label at each voxel, with optional thresholding and volume selection.
- Parameters:
spam_image (str) – Path to 4D SPAM image file with probability maps for each region.
prob_thresh (float, optional) – Minimum probability threshold. Values below this are set to zero. Default is 0.05.
vol_indexes (np.ndarray, optional) – Indices of volumes (regions) to include. If None, uses all volumes. Default is None.
maxp_name (str, optional) – Output file path for maximum probability image. If None, returns array without saving. Default is None.
- Returns:
Output file path if maxp_name provided, otherwise numpy array with maximum probability labels.
- Return type:
str or np.ndarray
Notes
The conversion process: 1. Applies probability threshold to remove low-confidence voxels 2. Optionally filters to specific volume indices 3. Finds maximum probability across volumes for each voxel 4. Assigns winner-take-all labels (1-indexed) 5. Sets background where no probabilities exceed threshold
Useful for converting probabilistic atlases to discrete parcellations for analysis requiring discrete labels.
Examples
>>> # Convert SPAM to discrete parcellation >>> maxprob_file = spams2maxprob( ... 'AAL_SPAM.nii.gz', ... prob_thresh=0.1, ... maxp_name='AAL_discrete.nii.gz' ... ) >>> >>> # Get array without saving, specific regions only >>> selected_regions = np.array([0, 1, 2, 5, 6]) # Volume indices >>> maxprob_array = spams2maxprob( ... 'probabilistic_atlas.nii.gz', ... vol_indexes=selected_regions, ... prob_thresh=0.2 ... ) >>> print(f"Max label: {maxprob_array.max()}")
- clabtoolkit.imagetools.simulate_image(input_image, simulated_image=None, n_volumes=3, distribution='normal', random_seed=None, **dist_params)[source]
Generate a simulated image with random values at non-zero voxel positions.
This function creates a new NIfTI image where non-zero voxels from the input image are filled with random values following a specified statistical distribution. The output preserves the spatial dimensions, affine transformation, and header information from the input image.
This is useful for simulating functional or structural images based on a mask or anatomical image, allowing for controlled random value generation in specific regions of interest.
- Parameters:
input_image (str or nibabel.Nifti1Image) – Input image used as a mask. Can be either a file path to a NIfTI image or a nibabel Nifti1Image object.
simulated_image (str) – Output file path where the simulated image will be saved. Must include the .nii or .nii.gz extension. If None, the function will generate a default name based on the input image.
n_volumes (int, default=3) – Number of volumes in the output image: - If n_volumes == 1: creates a 3D image - If n_volumes > 1: creates a 4D image with n_volumes timepoints
distribution (str, default='normal') – Statistical distribution for random value generation. Supported options: - ‘normal’: Normal (Gaussian) distribution - ‘uniform’: Uniform distribution - ‘exponential’: Exponential distribution
random_seed (int, optional) – Random seed for reproducible results. If None, uses system time.
**dist_params (dict) – Distribution-specific parameters: - For ‘normal’: loc (mean, default=0), scale (std, default=1) - For ‘uniform’: low (default=0), high (default=1) - For ‘exponential’: scale (default=1)
- Returns:
The simulated image object with the same spatial properties as input.
- Return type:
nibabel.Nifti1Image
- Raises:
FileNotFoundError – If input_image path does not exist.
ValueError – If input_image is not a valid type, distribution is unsupported, n_volumes is invalid, or output directory doesn’t exist.
RuntimeError – If no non-zero voxels are found in the input image.
Examples
>>> # Create 3D simulation with normal distribution >>> sim_img = simulate_image( ... 'brain_mask.nii.gz', ... 'output_3d.nii.gz', ... n_volumes=1, ... distribution='normal', ... loc=0, ... scale=1, ... random_seed=42 ... )
>>> # Create 4D simulation with uniform distribution >>> sim_img = simulate_image( ... 'brain_mask.nii.gz', ... 'output_4d.nii.gz', ... n_volumes=10, ... distribution='uniform', ... low=0, ... high=100 ... )
Notes
Only voxels with non-zero values in the input image will contain random values
All other voxels remain zero in the output
The function preserves the input image’s affine transformation and header
Output file extension should be .nii or .nii.gz
- clabtoolkit.imagetools.delete_volumes_from_4D_images(in_image, out_image, vols_to_delete=None, overwrite=False)[source]
Remove specific volumes from a 4D neuroimaging file.
This function removes specified volumes from 4D NIfTI images (such as fMRI time series, DTI volumes, or other 4D datasets) and saves the result to a new file. It supports flexible volume specification including individual indices, ranges, and complex string-based patterns.
- Parameters:
in_image (str) – Path to the input 4D NIfTI image file (.nii or .nii.gz). The file must exist and be a valid 4D image.
out_image (str) – Path where the output 4D image will be saved. The directory must exist. If the file already exists, use overwrite=True to replace it.
vols_to_delete (list of int, tuple, list, np.ndarray, or str) –
Specification of volumes to remove from the 4D image. Supports multiple formats:
- Individual integers:
Single volume indices to remove (0-based indexing).
- Tuples of 2 integers:
Ranges specified as (start, end) - both endpoints are included. Example: (5, 8) removes volumes [5, 6, 7, 8]
- Lists or numpy arrays:
Collections of volume indices, automatically flattened.
- Strings (flexible syntax):
Powerful string-based specification supporting:
Single numbers: “5” → [5]
Hyphen ranges: “8-10” → [8, 9, 10]
Colon ranges: “11:13” → [11, 12, 13]
Step ranges: “14:2:22” → [14, 16, 18, 20, 22]
Comma-separated: “1, 2, 3” → [1, 2, 3]
Mixed combinations: “0-2, 5, 10:2:14, 20” → [0, 1, 2, 5, 10, 12, 14, 20]
Note: All formats can be mixed in a single list.
overwrite (bool, default=False) – Whether to overwrite the output file if it already exists. If False and the output file exists, raises FileExistsError.
- Returns:
out_image (str) – Path to the successfully created output image file.
vols_removed (list of int) – Sorted list of all volume indices that were removed from the original image. Useful for verification and logging purposes.
- Raises:
If the input image file does not exist - If the output directory does not exist
If vols_to_delete is None or empty after parsing - If the input image is not 4D (wrong number of dimensions) - If any volume indices are out of range (negative or >= number of volumes)
FileExistsError – If the output file already exists and overwrite=False.
RuntimeError – If attempting to delete all volumes (would result in empty image).
- Return type:
Notes
Volume indexing is 0-based (first volume is index 0)
Duplicate volume indices are automatically removed
The function preserves the original image’s affine transformation and header
Memory usage scales with image size; very large 4D images may require substantial RAM
The function validates all volume indices before processing to prevent partial failures
Performance considerations: - Loading and processing large 4D images may take significant time and memory - Consider processing in chunks for very large datasets
File format support: - Input: .nii and .nii.gz files - Output: Format determined by output filename extension
Examples
Basic usage - Remove specific volumes:
>>> delete_volumes_from_4D_images( ... 'fmri_data.nii.gz', ... 'fmri_cleaned.nii.gz', ... vols_to_delete=[0, 1, 2, 99], ... overwrite=True ... )
Remove ranges using tuples:
>>> delete_volumes_from_4D_images( ... 'dti_data.nii.gz', ... 'dti_subset.nii.gz', ... vols_to_delete=[(0, 4), (95, 99)], # Remove first 5 and last 5 volumes ... overwrite=True ... )
String-based range specification:
>>> delete_volumes_from_4D_images( ... 'timeseries.nii.gz', ... 'timeseries_clean.nii.gz', ... vols_to_delete=["0-4", "95:99"], # Same as above using strings ... overwrite=True ... )
Complex mixed specification:
>>> delete_volumes_from_4D_images( ... 'bold_data.nii.gz', ... 'bold_processed.nii.gz', ... vols_to_delete=[ ... "0-2", # Remove first 3 volumes (motion artifacts) ... (147, 149), # Remove volumes 147-149 (spike artifacts) ... "200:5:220", # Remove every 5th volume from 200-220 ... [300, 301, 302], # Remove specific outlier volumes ... "450" # Remove final volume ... ], ... overwrite=True ... )
Advanced string patterns:
>>> # Remove multiple ranges and individual volumes in one string >>> delete_volumes_from_4D_images( ... 'input.nii.gz', ... 'output.nii.gz', ... vols_to_delete=["0-2, 5, 10:2:14, 20-22, 50"], ... overwrite=True ... ) >>> # This removes: [0,1,2,5,10,12,14,20,21,22,50]
- clabtoolkit.imagetools.extract_mesh_from_volume(volume_array, gaussian_smooth=True, sigma=1.0, fill_holes=True, smooth_iterations=10, affine=None, closing_iterations=1, vertex_value=1.0)[source]
Extract surface mesh from 3D volume using marching cubes algorithm.
Creates high-quality surface mesh with optional smoothing, hole filling, and coordinate transformation to millimeter space.
- Parameters:
volume_array (np.ndarray) – 3D binary volume array for mesh extraction.
gaussian_smooth (bool, optional) – Whether to apply Gaussian smoothing before extraction. Default is True.
sigma (float, optional) – Standard deviation for Gaussian smoothing. Default is 1.0.
fill_holes (bool, optional) – Whether to fill holes in extracted mesh. Default is True.
smooth_iterations (int, optional) – Number of Taubin smoothing iterations. Default is 10.
affine (np.ndarray, optional) – 4x4 affine matrix to transform vertices to mm space. Default is None.
closing_iterations (int, optional) – Morphological closing iterations before extraction. Default is 1.
vertex_value (float, optional) – Scalar value assigned to mesh vertices. Default is 1.0.
- Returns:
PyVista mesh with vertices in mm coordinates (if affine provided), computed normals, and scalar values.
- Return type:
pv.PolyData
- Raises:
TypeError – If volume_array is not a numpy array.
ValueError – If volume_array is not 3D or no surface can be extracted.
Notes
The extraction pipeline includes: 1. Morphological closing to fill small gaps 2. Optional Gaussian smoothing for noise reduction 3. Marching cubes surface extraction 4. Mesh cleaning and hole filling 5. Taubin smoothing for feature preservation 6. Normal computation for proper shading
Examples
>>> # Basic mesh extraction >>> mesh = extract_mesh_from_volume(binary_volume) >>> print(f"Mesh has {mesh.n_points} vertices and {mesh.n_cells} faces") >>> >>> # High-quality mesh with coordinate transformation >>> mesh = extract_mesh_from_volume( ... binary_volume, ... affine=img.affine, ... smooth_iterations=20, ... fill_holes=True ... ) >>> >>> # Save mesh >>> mesh.save('surface.ply')
- clabtoolkit.imagetools.extract_centroid_from_volume(volume_array, gaussian_smooth=True, sigma=1.0, closing_iterations=1)[source]
Extract centroid and voxel count from a 3D binary volume. Computes the centroid of the non-zero region in the volume and counts the number of voxels. Optionally applies Gaussian smoothing and morphological closing to improve the region definition.
- Parameters:
volume_array (np.ndarray) – 3D binary volume array where non-zero values represent the region of interest.
gaussian_smooth (bool, optional) – Whether to apply Gaussian smoothing before centroid calculation. Default is True.
sigma (float, optional) – Standard deviation for Gaussian smoothing. Default is 1.0.
closing_iterations (int, optional) – Number of morphological closing iterations to apply before centroid calculation. Default is 1.
- Returns:
A tuple containing: - Centroid coordinates as a numpy array of shape (3,) in mm space. - Voxel count as an integer.
- Return type:
- Raises:
TypeError – If volume_array is not a numpy ndarray.
ValueError – If volume_array is not 3D or if no region is found in the volume.
ValueError – If the volume does not contain sufficient data to compute a centroid.
Notes The function processes the input volume as follows: 1. Converts non-zero values to 1 to create a binary mask. 2. Applies morphological closing to fill small gaps in the region. 3. Optionally applies Gaussian smoothing to reduce noise. 4. Computes the centroid of the non-zero region. 5. Counts the number of voxels in the region. 6. Returns the centroid coordinates and voxel count as a numpy array.
Examples
>>> # Basic centroid extraction >>> centroid_info = extract_centroid_from_volume(binary_volume) >>> print(f"Centroid: {centroid_info[:3]}, Voxel Count: {centroid_info[3]}") >>> >>> # With Gaussian smoothing and morphological closing >>> centroid_info = extract_centroid_from_volume(binary_volume, gaussian_smooth=True, sigma=1.5, closing_iterations=2) >>> print(f"Centroid: {centroid_info[:3]}, Voxel Count: {centroid_info[3]}")
- clabtoolkit.imagetools.create_spams_from_volume(indiv_parc, sts_ids)[source]
Create SPAMs (Spatial Probability Maps) from individual parcellation volumes.
- Parameters:
indiv_parc (numpy.ndarray) – 4D array with dimensions (X, Y, Z, N) where N is the number of subjects. Each voxel contains integer labels representing different structures.
sts_ids (list or numpy.ndarray) – List or array of integer structure IDs for which to create SPAMs.
- Returns:
4D array with dimensions (X, Y, Z, M) where M is the number of structure IDs. Each voxel contains the proportion of subjects that have the corresponding structure ID at that voxel.
- Return type:
- Raises:
ValueError – If indiv_parc is not a 4D numpy array.
ValueError – If sts_ids is not a list or numpy array of integers.
Notes
- The function computes the proportion of subjects that have each specified
structure ID at each voxel.
The output SPAMs can be used for group-level analyses in neuroimaging studies.
Examples
>>> # Example usage >>> indiv_parc = np.random.randint(0, 5, size=(64, 64, 64, 10)) # 10 subjects with labels 0-4 >>> sts_ids = [1, 2, 3] >>> spams = create_spams_from_volume(indiv_parc, sts_ids) >>> print(spams.shape) # Output shape will be (64, 64, 64, 3)
- clabtoolkit.imagetools.spams2maxprob_from_volume(spam_vol, prob_thresh=0.0, vol_indexes=None)[source]
Convert SPAMs (Spatial Probability Maps) to a maximum probability parcellation volume.
- Parameters:
spam_vol (numpy.ndarray) – 4D array with dimensions (X, Y, Z, M) where M is the number of structures. Each voxel contains the probability of belonging to each structure.
prob_thresh (float, optional) – Probability threshold to apply before determining maximum probability. Voxels with probabilities below this threshold will be set to zero. Default is 0.0.
vol_indexes (list or numpy.ndarray, optional) – List or array of integer structure indexes to consider for maximum probability. If provided, only these structures will be considered. Default is None.
- Returns:
3D array with dimensions (X, Y, Z) where each voxel contains the index of the structure with the maximum probability, or 0 if below the threshold.
- Return type:
- Raises:
ValueError – If spam_vol is not a 4D numpy array.
Notes
- The function applies a probability threshold to the SPAMs and then determines
the structure with the maximum probability at each voxel.
Voxels with probabilities below the threshold are assigned a value of 0 in the output
If vol_indexes is provided, only those structures are considered for maximum probability.
Examples
>>> # Example usage >>> spam_vol = np.random.rand(64, 64, 64, 5) # SPAMs for 5 structures >>> maxprob_vol = spams2maxprob_from_volume(spam_vol, prob_thresh=0.2) >>> print(maxprob_vol.shape) # Output shape will be (64, 64, 64)
- clabtoolkit.imagetools.compute_statistics_at_nonzero_voxels(mask_array, data_array, metric='mean')[source]
Compute the value of certain statistic from data_array at positions where mask_array is non-zero.
- Parameters:
mask_array (numpy.ndarray) – 3D array with dimensions (N, M, P) - used to find non-zero positions Non-zero positions in this array indicate where to compute the statistic in data_array.
data_array (numpy.ndarray) – 3D array (N, M, P) or 4D array (N, M, P, T) - data to compute mean from If 3D, computes a single mean value. If 4D, computes mean across non-zero positions for each time point T.
metric (str, optional) – Metric to compute at non-zero positions. Default is “mean”. Supported metrics: “mean”, “std”, “var”, “median”, “sum”, “max”, “min”.
- Returns:
If data_array is 3D: returns a single float value
If data_array is 4D: returns a 1D array of length T
- Return type:
- Raises:
ValueError – If data_array is not 3D or 4D.
ValueError – If metric is not one of the supported metrics.
Notes
The function extracts values from data_array at positions where mask_array is non-zero.
For 3D data_array, it computes the mean of all selected values.
For 4D data_array, it computes the mean across non-zero positions for each time point,
returning a 1D array with the mean for each time point. - If mask_array has no non-zero positions, the function will return NaN for 3D data_array or an array of NaNs for 4D data_array.
Examples
>>> # Example with 3D data_array >>> mask = np.array([[[0, 1], [0, 0]], ... [[1, 0], [0, 1]]]) >>> data = np.array([[[1, 2], [3, 4]], ... [[5, 6], [7, 8]]]) >>> mean_value = compute_statistics_at_nonzero_voxels(mask, data) >>> print(mean_value) # Output: 4.5 (mean of 2, 5, 6, 8) >>> >>> # Example with 4D data_array >>> mask_4d = np.array([[[0, 1], [0, 0]], ... [[1, 0], [0, 1]]]) >>> data_4d = np.array([[[[1, 2], [3, 4]], ... [[5, 6], [7, 8]]], ... [[[9, 10], [11, 12]], ... [[13, 14], [15, 16]]]]) >>> mean_values_4d = compute_statistics_at_nonzero_voxels(mask_4d, data_4d) >>> print(mean_values_4d) # Output: [ 6. 8. 10. 12.] (mean for each time point 1, 2, 3, 4)
- clabtoolkit.imagetools.interpolate(scalar_data, vertices_vox, interp_method='linear')[source]
Interpolate 3D or 4D scalar data at specified voxel coordinates using regular grid interpolation. :param scalar_data: 3D or 4D array of scalar values to interpolate from. :type scalar_data: np.ndarray :param vertices_vox: Nx3 array of voxel coordinates where interpolation is desired. :type vertices_vox: np.ndarray :param interp_method: Interpolation method: ‘linear’, ‘nearest’, or ‘slinear’. Default is ‘linear’. :type interp_method: str, optional
- Returns:
Interpolated scalar values at the specified voxel coordinates.
- Return type:
np.ndarray
- Raises:
ValueError – If scalar_data is not 3D or 4D, or if vertices_vox is not Nx3. If interp_method is not one of the supported methods.
Notes
Uses scipy’s RegularGridInterpolator for interpolation.
Supports both 3D and 4D scalar data.
Interpolates each volume separately if scalar_data is 4D.
Out-of-bounds coordinates are filled with 0.
- clabtoolkit.imagetools.region_growing(iparc, mask, neighborhood='26')[source]
Fill gaps in parcellation using region growing algorithm.
Labels unlabeled voxels within the mask by assigning the most frequent label among their labeled neighbors, iteratively until convergence or no more voxels can be labeled.
- Parameters:
- Returns:
Updated parcellation array with gaps filled, masked to input mask.
- Return type:
np.ndarray
Notes
The algorithm works iteratively: 1. Identifies unlabeled voxels with at least one labeled neighbor 2. For each candidate voxel, finds most frequent label among neighbors 3. In case of ties, selects label from spatially closest neighbor 4. Repeats until no more voxels can be labeled or convergence
Particularly useful for: - Filling gaps in atlas-based parcellations - Completing partial segmentations - Correcting registration artifacts
Examples
>>> # Fill gaps in parcellation >>> filled_parc = region_growing(parcellation_array, brain_mask) >>> print(f"Filled {np.sum(filled_parc > 0) - np.sum(parcellation_array > 0)} voxels") >>> >>> # Use 6-connectivity for more conservative growing >>> conservative_fill = region_growing( ... incomplete_labels, ... region_mask, ... neighborhood='6' ... )
- clabtoolkit.imagetools.simulate_array(mask_array, n_volumes=1, distribution='normal', random_seed=None, **dist_params)[source]
Generate a simulated array with random values at non-zero voxel positions.
This function creates a new array where non-zero voxels from the mask array are filled with random values following a specified statistical distribution.
- Parameters:
mask_array (numpy.ndarray) – 3D array used as a mask to determine where to place random values. Shape: (N, M, P)
n_volumes (int, default=1) – Number of volumes in the output array: - If n_volumes == 1: creates a 3D array (N, M, P) - If n_volumes > 1: creates a 4D array (N, M, P, n_volumes)
distribution (str, default='normal') – Statistical distribution for random value generation. Supported options: - ‘normal’: Normal (Gaussian) distribution - ‘uniform’: Uniform distribution - ‘exponential’: Exponential distribution
random_seed (int, optional) – Random seed for reproducible results. If None, uses system time.
**dist_params (dict) – Distribution-specific parameters: - For ‘normal’: loc (mean, default=0), scale (std, default=1) - For ‘uniform’: low (default=0), high (default=1) - For ‘exponential’: scale (default=1)
- Returns:
Simulated array with random values at non-zero mask positions: - 3D array (N, M, P) if n_volumes == 1 - 4D array (N, M, P, n_volumes) if n_volumes > 1
- Return type:
- Raises:
ValueError – If mask_array is not 3D, distribution is unsupported, n_volumes is invalid, or distribution parameters are invalid.
RuntimeError – If no non-zero voxels are found in the mask array.
Examples
>>> # Create 3D simulation with normal distribution >>> mask = np.random.randint(0, 2, (64, 64, 30)) >>> sim_3d = simulate_array( ... mask, ... n_volumes=1, ... distribution='normal', ... loc=0, ... scale=1, ... random_seed=42 ... )
>>> # Create 4D simulation with uniform distribution >>> sim_4d = simulate_array( ... mask, ... n_volumes=10, ... distribution='uniform', ... low=0, ... high=100, ... random_seed=42 ... )
Notes
Only voxels with non-zero values in the mask array will contain random values
All other voxels remain zero in the output
For 4D outputs, each volume gets independent random values
- clabtoolkit.imagetools.delete_volumes_from_4D_array(in_array, vols_to_delete=None)[source]
Remove specific volumes from a 4D array.
This function allows you to delete specified volumes from a 4D numpy array, which is commonly used in neuroimaging data (e.g., fMRI, DTI). It supports various formats for specifying which volumes to remove, including individual indices, ranges, lists, and flexible string-based specifications. The function returns the modified array and a list of removed volume indices. It is designed to handle large 4D arrays efficiently and ensures that the integrity of the remaining data is preserved. 4D arrays are expected to have the shape (X, Y, Z, T), where T is the number of volumes.
- Parameters:
in_array (np.ndarray) – Input 4D numpy array from which volumes will be removed.
vols_to_delete (list of int, tuple, list, np.ndarray, or str) –
Specification of volumes to remove from the 4D image. Supports multiple formats:
- Individual integers:
Single volume indices to remove (0-based indexing).
- Tuples of 2 integers:
Ranges specified as (start, end) - both endpoints are included. Example: (5, 8) removes volumes [5, 6, 7, 8]
- Lists or numpy arrays:
Collections of volume indices, automatically flattened.
- Strings (flexible syntax):
Powerful string-based specification supporting:
Single numbers: “5” → [5]
Hyphen ranges: “8-10” → [8, 9, 10]
Colon ranges: “11:13” → [11, 12, 13]
Step ranges: “14:2:22” → [14, 16, 18, 20, 22]
Comma-separated: “1, 2, 3” → [1, 2, 3]
Mixed combinations: “0-2, 5, 10:2:14, 20” → [0, 1, 2, 5, 10, 12, 14, 20]
Note: All formats can be mixed in a single list.
- Returns:
out_array (np.ndarray) – The modified 4D numpy array with specified volumes removed.
vols_removed (list of int) – Sorted list of all volume indices that were removed from the original image. Useful for verification and logging purposes.
- Raises:
TypeError – If in_array is not a numpy ndarray or if vols_to_delete is not a list or convertible to a list.
ValueError – If in_array is not a 4D array, if vols_to_delete is empty, or if any specified volume indices are out of range.
Notes –
- The function checks for valid input types and dimensions. –
- It handles both individual volume indices and ranges specified as tuples or strings. –
- The output array retains the original shape minus the removed volumes. –
- If all volumes are specified for deletion, it returns the original array unchanged. –
- Return type:
Examples
Basic usage - Remove specific volumes:
>>> delete_volumes_from_4D_array( ... in_array=np.random.rand(64, 64, 30, 100), # Example 4D array ... vols_to_delete=[0, 1, 2], # Remove first 3 volumes ... )
(array with shape (64, 64, 30, 97), [0, 1, 2])
Remove a range of volumes: >>> delete_volumes_from_4D_array( … in_array=np.random.rand(64, 64, 30, 100), # Example 4D array … vols_to_delete=[(5, 8)], # Remove volumes 5 to 8 (inclusive) … ) (array with shape (64, 64, 30, 96), [5, 6, 7, 8])
Remove volumes using a string specification: >>> delete_volumes_from_4D_array( … in_array=np.random.rand(64, 64, 30, 100), # Example 4D array … vols_to_delete=[“0-2”, “5”, “10:2:14”, “20”] # Mixed specification … ) (array with shape (64, 64, 30, 92), [0, 1, 2, 5, 10, 12, 14, 20])
The imagetools module provides advanced neuroimaging operations, morphological processing, and image manipulation capabilities specifically designed for brain imaging data.
Key Features
2D/3D morphological operations on binary images
Volume filtering and hole filling algorithms
Image resampling and geometric transformations
Quality control and preprocessing utilities
Multi-modal image processing support
Structuring element generation for morphological operations
3D/4D scalar data interpolation at specified coordinates
Main Classes
MorphologicalOperations
Comprehensive class for binary image morphological processing.
Key Methods:
- erosion(): Erode binary structures
- dilation(): Dilate binary structures
- opening(): Morphological opening (erosion + dilation)
- closing(): Morphological closing (dilation + erosion)
- fill_holes(): Fill holes in binary structures
- remove_small_objects(): Filter small connected components
Common Usage Examples
Binary image processing:
from clabtoolkit.imagetools import MorphologicalOperations
import nibabel as nib
# Load binary image
img = nib.load("/path/to/binary_mask.nii.gz")
binary_data = img.get_fdata().astype(bool)
# Initialize morphological operations
morph = MorphologicalOperations()
# Perform morphological closing
structuring_element = morph.create_spherical_kernel(radius=2)
closed_image = morph.closing(binary_data, structuring_element)
# Fill holes in the image
filled_image = morph.fill_holes(closed_image)
Advanced morphological processing:
# Create custom structuring element
kernel = morph.create_cubic_kernel(size=3)
# Chain operations
processed = morph.opening(binary_data, kernel)
processed = morph.remove_small_objects(processed, min_size=100)
# Save result
output_img = nib.Nifti1Image(processed.astype(np.uint8), img.affine, img.header)
nib.save(output_img, "/path/to/processed_mask.nii.gz")
Image quality control:
# Validate image properties
if morph.validate_binary_image(binary_data):
print("Image is valid binary format")
# Get image statistics
stats = morph.get_image_statistics(binary_data)
print(f"Volume: {stats['volume']} voxels")
3D/4D data interpolation:
from clabtoolkit.imagetools import interpolate
import numpy as np
import nibabel as nib
# Load 3D scalar volume
img = nib.load("/path/to/scalar_data.nii.gz")
scalar_data = img.get_fdata()
# Define voxel coordinates for interpolation (Nx3 array)
vertices_vox = np.array([
[10.5, 20.3, 15.7], # fractional coordinates allowed
[25.2, 30.1, 45.9],
[12.0, 18.5, 22.3]
])
# Interpolate values at specified coordinates
interpolated_values = interpolate(
scalar_data=scalar_data,
vertices_vox=vertices_vox,
interp_method="linear" # options: 'linear', 'nearest', 'slinear'
)
# For 4D data (e.g., time series)
functional_img = nib.load("/path/to/4d_functional.nii.gz")
functional_data = functional_img.get_fdata() # shape: (x, y, z, time)
# Interpolate 4D data - returns values for each timepoint
time_series_values = interpolate(
scalar_data=functional_data,
vertices_vox=vertices_vox,
interp_method="linear"
) # shape: (n_vertices, n_timepoints)