Skip to main content

Mask Operations

Object Operations 📥 Download Script

Mask Operations Tutorial.

This tutorial demonstrates operations on segmentation masks including creation, thresholding, region growing, morphological operations, boolean operations, filtering, and conversion to surfaces.

Prerequisites
  • Volvicon application must be running
  • A volume loaded in the project for segmentation operations

Listing Masks​

all_masks = app.get_all_mask_names()
all_volumes = app.get_all_volume_names()
print(f"Available masks: {all_masks}")
print(f"Available volumes: {all_volumes}")

Importing and Exporting Masks​

# Supported formats: mha, mhd, nii, nii.gz, vti

# Import a single mask file
# mask_name = MaskOperations.import_3d_mask_image_from_disk(r'C:\data\segmentation.mha')

# Import multiple mask files
# mask_names = MaskOperations.import_3d_mask_images_from_disk([
# r'C:\data\mask1.mha',
# r'C:\data\mask2.nii.gz'
# ])

# Export a single mask to file
# MaskOperations.export_mask_image_to_disk('Mask_1', r'C:\output\mask.mha')

# Export multiple masks to a directory
# MaskOperations.export_mask_images_to_disk(['Mask_1', 'Mask_2'], r'C:\output', 'mha')

Creating Masks​

# Create a blank mask with auto-assigned color
# new_mask = MaskOperations.create_mask("New_Mask", True) # autoColor=True (bool: if True, assign a color automatically)

# Create a blank mask with specific RGB color (values 0.0-1.0)
# new_mask = MaskOperations.create_mask("Red_Mask", False, [1.0, 0.0, 0.0]) # autoColor=False, rgb=[r,g,b] (0.0-1.0 floats)

Threshold Segmentation​

# Create mask by selecting voxels within intensity range

# if all_volumes:
# params = api.ThresholdParams()
# params.lower_threshold = 200 # Minimum intensity
# params.upper_threshold = 3000 # Maximum intensity
# params.fill_cavities = False
# params.filter_regions = False
#
# mask_name = MaskOperations.threshold(all_volumes[0], params)
# print(f"Created threshold mask: {mask_name}")

# Threshold with region filtering
# params = api.ThresholdParams()
# params.lower_threshold = 200
# params.upper_threshold = 3000
# params.filter_regions = True
# params.keep_largest = True # Keep only largest region
# mask_name = MaskOperations.threshold(all_volumes[0], params)

Region Growing Segmentation​

# Grow from seed points within an existing mask

# if all_volumes and all_masks:
# params = api.RegionGrowSegmentationParams()
# params.source_mask_name = all_masks[0]
# params.seeds = [[100.0, 100.0, 50.0]] # World coordinates
# params.multiple_layer = True # Apply to all slices (3D)
# params.fully_connected = False # 6-connectivity
#
# mask_name = MaskOperations.region_grow(all_volumes[0], params)

Dynamic Region Growing​

# Connectivity-based (grows based on neighborhood statistics)
# if all_volumes:
# params = api.DynamicRegionGrowConnectivitySegmentationParams()
# params.seeds = [[100.0, 100.0, 50.0]]
# params.multiplier = 2.5
# params.number_of_iterations = 4
# params.initial_neighborhood_radius = 1
# params.fill_cavities = True
# params.multiple_layer = True
#
# mask_name = MaskOperations.dynamic_region_grow_connectivity(all_volumes[0], params)

# Threshold-based (grows based on intensity range)
# if all_volumes:
# params = api.DynamicRegionGrowThresholdSegmentationParams()
# params.seeds = [[100.0, 100.0, 50.0]]
# params.lower_threshold = 100
# params.upper_threshold = 500
# params.fully_connected = False
# params.fill_cavities = True
# params.multiple_layer = True
#
# mask_name = MaskOperations.dynamic_region_grow_threshold(all_volumes[0], params)

Morphological Operations​

# Available operations: Erode, Dilate, Open, Close

# if all_masks:
# # Dilate (expand mask)
# MaskOperations.morphological_operation(
# [all_masks[0]],
# api.MorphologicalOperationType.Dilate,
# [2, 2, 2] # Ball radius in pixels [x, y, z]
# )
#
# # Erode (shrink mask)
# MaskOperations.morphological_operation(
# [all_masks[0]],
# api.MorphologicalOperationType.Erode,
# [2, 2, 2]
# )
#
# # Open (erode then dilate - removes small protrusions)
# MaskOperations.morphological_operation(
# [all_masks[0]],
# api.MorphologicalOperationType.Open,
# [2, 2, 2]
# )
#
# # Close (dilate then erode - fills small holes)
# MaskOperations.morphological_operation(
# [all_masks[0]],
# api.MorphologicalOperationType.Close,
# [2, 2, 2]
# )

Boolean Operations​

# Combine masks using Union, Intersection, or Difference

# if len(all_masks) >= 2:
# # Union - combine both masks
# result = MaskOperations.boolean(
# all_masks[0],
# [all_masks[1]],
# "", # Target name (not used when createNewMask=True)
# api.BooleanOperation.Union,
# True # createNewMask=True (bool: create a new mask instead of overwriting target)
# )
#
# # Intersection - keep only overlapping regions
# result = MaskOperations.boolean(
# all_masks[0],
# [all_masks[1]],
# "",
# api.BooleanOperation.Intersection,
# True # createNewMask=True
# )
#
# # Difference - subtract second from first
# result = MaskOperations.boolean(
# all_masks[0],
# [all_masks[1]],
# "",
# api.BooleanOperation.Difference,
# True # createNewMask=True
# )

Region Filtering​

# Keep largest regions or remove small regions

# if all_masks:
# # Keep only the 3 largest regions
# MaskOperations.keep_largest_regions([all_masks[0]], 3) # numberOfLargestRegions=3 (int)
#
# # Filter by size (remove regions smaller than 100 voxels)
# MaskOperations.filter_regions(
# [all_masks[0]],
# False, # keepLargestRegions=False (bool)
# 0, # numberOfLargestRegions=0 (int)
# 100 # minimumRegionSizeInVoxels=100 (int)
# )
#
# # Count regions in mask
# count = MaskOperations.count_regions_in_mask(all_masks[0])
# print(f"Number of regions: {count}")

Cavity and Hole Filling​

# if all_masks:
# # Fill internal cavities
# MaskOperations.cavity_fill([all_masks[0]], False) # fullyConnected=False (bool: 6 vs 26 connectivity)
#
# # Fill holes using iterative voting
# MaskOperations.fill_holes([all_masks[0]], 5) # numberOfIterations=5 (int)

Grow and Shrink Masks​

# if all_masks:
# # Grow mask by 2mm
# MaskOperations.grow_masks([all_masks[0]], 2.0) # marginSizeMM=2.0 (float in mm)
#
# # Shrink mask by 1mm
# MaskOperations.shrink_masks([all_masks[0]], 1.0) # marginSizeMM=1.0 (float in mm)

Hollow Masks​

# if all_masks:
# # Create hollow shell inside surface
# MaskOperations.hollow_masks(
# [all_masks[0]],
# api.HollowShellMode.InsideSurface,
# 2.0 # shellThicknessMM=2.0 (float in mm)
# )

Smoothing Operations​

# if all_masks:
# # Discrete Gaussian smoothing
# MaskOperations.smooth_discrete_gaussian_filter([all_masks[0]], 1.0, 1.0, 1.0) # sigmaX, sigmaY, sigmaZ (float)
#
# # Median smoothing
# MaskOperations.smooth_median_filter([all_masks[0]], 1, 1, 1) # radiusX, radiusY, radiusZ (int, pixels)
#
# # Mean smoothing
# MaskOperations.smooth_mean_filter([all_masks[0]], 1, 1, 1) # radiusX, radiusY, radiusZ (int, pixels)

Multi-Label Masks​

# Check if mask is multi-label
# if all_masks:
# is_multilabel = MaskOperations.is_multilabel_mask(all_masks[0])
# print(f"Is multi-label: {is_multilabel}")
#
# if is_multilabel:
# # Get label information
# labels = MaskOperations.get_mask_labels(all_masks[0])
# for label in labels:
# print(f"Label {label.value}: {label.annotation}")
#
# # Get label values
# label_values = MaskOperations.get_mask_label_values(all_masks[0])
# print(f"Label values: {label_values}")

# Split multi-label mask into individual masks
# if all_masks:
# individual_masks = MaskOperations.split_multi_label_mask(
# all_volumes[0],
# all_masks[0],
# False, # separateOnlyLargestLabels=False (bool)
# 0, # numLargestLabels=0 (int)
# False # removeActiveMask=False (bool)
# )

# Merge multiple masks into multi-label mask
# if len(all_masks) >= 2:
# merged = MaskOperations.merge_into_multi_label_mask(
# all_masks[:3],
# "",
# True, # createNewMask=True (bool)
# False # removeInputMasks=False (bool)
# )

Convert Mask to Surface​

# if all_masks:
# params = api.MaskToSurfaceParams()
# params.resolution_reduction = False
# params.smoothing = True
# params.smooth_iterations = 10
# params.smooth_factor = 0.5
# params.triangle_reduction = True
# params.triangle_reduction_percent = 50
#
# surface_names = MaskOperations.convert_to_surface_objects([all_masks[0]], params)
# print(f"Created surfaces: {surface_names}")

Other Operations​

# if all_masks:
# # Invert mask
# MaskOperations.invert_masks([all_masks[0]])
#
# # Binarize mask
# MaskOperations.binarize([all_masks[0]])
#
# # Flip mask along axis (0=X, 1=Y, 2=Z)
# MaskOperations.flip([all_masks[0]], 0, False) # axis=0 (0=X,1=Y,2=Z), aboutOrigin=False (bool)
#
# # Mirror mask across a custom plane
# MaskOperations.mirror_to_plane(
# [all_masks[0]], # maskNames (list)
# [0.0, 0.0, 0.0], # planeOrigin [x, y, z] in mm
# [1.0, 0.0, 0.0] # planeNormal [x, y, z] (unit vector)
# )
#
# # Clear mask content
# MaskOperations.clear_masks([all_masks[0]])
#
# # Crop mask to bounds [xMin, xMax, yMin, yMax, zMin, zMax]
# MaskOperations.crop_mask(all_masks[0], [-50, 50, -50, 50, -30, 30])

print("Mask operations tutorial completed successfully.")