High-performance connected components analysis for 2D and 3D multilabel images with support for 26, 18, and 6-connected neighborhoods.
npx @tessl/cli install tessl/pypi-connected-components-3d@3.24.0A high-performance Python library for connected components analysis on 2D and 3D multilabel images. cc3d implements optimized algorithms for labeling connected regions in both discrete and continuous valued images, supporting multiple connectivity patterns and processing images with hundreds to thousands of distinct labels simultaneously.
pip install connected-components-3dimport cc3dAlternative import for direct access:
from cc3d import connected_components, statistics, dust, largest_kimport cc3d
import numpy as np
# Create a sample 3D multilabel image
labels_in = np.ones((100, 100, 100), dtype=np.int32)
labels_in[:50, :50, :50] = 2 # Different region
# Perform connected components labeling
labels_out = cc3d.connected_components(labels_in) # 26-connected by default
# Get statistics about the components
stats = cc3d.statistics(labels_out)
print(f"Found {len(stats['voxel_counts'])-1} components")
print(f"Component sizes: {stats['voxel_counts'][1:]}") # Skip background
# Extract individual components efficiently
for label, image in cc3d.each(labels_out, binary=False, in_place=True):
print(f"Processing component {label} with {np.sum(image > 0)} voxels")
# Remove small components ("dust removal")
cleaned = cc3d.dust(labels_in, threshold=1000, connectivity=26)
# Keep only the 5 largest components
largest = cc3d.largest_k(labels_in, k=5, connectivity=26)cc3d uses a sophisticated four-pass algorithm built on these key components:
The library processes all labels simultaneously rather than requiring separate binary masks for each label, providing significant performance improvements for multilabel datasets common in biomedical imaging, computer vision, and scientific computing.
Primary connected components labeling functionality with support for multiple connectivity patterns, continuous value processing, and various output formats including memory-mapped files.
def connected_components(
data: NDArray[Any],
max_labels: int = -1,
connectivity: Literal[4, 6, 8, 18, 26] = 26,
return_N: bool = False,
delta: float = 0,
out_dtype: DTypeLike = None,
out_file: Union[str, BinaryIO, None] = None,
periodic_boundary: bool = False,
binary_image: bool = False,
) -> Union[NDArray[Union[np.uint16, np.uint32, np.uint64]], tuple[NDArray[Union[np.uint16, np.uint32, np.uint64]], int]]
def connected_components_stack(
stacked_images: typing.Iterable[NDArray[typing.Any]],
connectivity: Literal[6,26] = 26,
return_N: bool = False,
out_dtype: DTypeLike = None,
binary_image: bool = False,
) -> Union[CrackleArray, tuple[CrackleArray, int]]Compute comprehensive statistics about connected components including voxel counts, bounding boxes, centroids, and component extraction utilities.
def statistics(
out_labels: NDArray[Any],
no_slice_conversion: bool = False,
) -> Union[StatisticsDict, StatisticsSlicesDict]
def each(
labels: NDArray[UnsignedIntegerT],
binary: bool = False,
in_place: bool = False,
) -> Iterator[tuple[int, NDArray[UnsignedIntegerT]]]Filter and manipulate connected components by size, including dust removal and extraction of largest components with efficient memory management.
def dust(
img: NDArray[typing.Any],
threshold: Union[int,float,tuple[int,int],tuple[float,float],list[int],list[float]],
connectivity: Literal[4,6,8,18,26] = 26,
in_place: bool = False,
binary_image: bool = False,
precomputed_ccl: bool = False,
invert: bool = False,
return_N: bool = False,
) -> Union[NDArray[typing.Any], tuple[NDArray[typing.Any], int]]
def largest_k(
img: NDArray[typing.Any],
k: int,
connectivity: Literal[4,6,8,18,26] = 26,
delta: Union[int,float] = 0,
return_N: bool = False,
binary_image: bool = False,
precomputed_ccl: bool = False,
) -> Union[NDArray[Union[np.bool_,np.uint16,np.uint32,np.uint64]], tuple[NDArray[Union[np.bool_,np.uint16,np.uint32,np.uint64]], int]]Extract connectivity graphs between regions and voxel-level connectivity patterns for advanced analysis and network-based computations.
def contacts(
labels: NDArray[Any],
connectivity: Literal[4, 6, 8, 18, 26] = 26,
surface_area: bool = True,
anisotropy: tuple[Union[int, float], Union[int, float], Union[int, float]] = (1, 1, 1),
) -> dict[tuple[int, int], Union[int, float]]
def region_graph(
labels: NDArray[np.integer],
connectivity: Literal[4, 6, 8, 18, 26] = 26,
) -> set[tuple[int, int]]
def voxel_connectivity_graph(
data: NDArray[IntegerT],
connectivity: Literal[4, 6, 8, 18, 26] = 26,
) -> NDArray[IntegerT]
def color_connectivity_graph(
vcg: NDArray[VcgT],
connectivity: Literal[4, 6, 8, 18, 26] = 26,
return_N: bool = False,
) -> Union[NDArray[VcgT], tuple[NDArray[VcgT], int]]class DimensionError(Exception):
"""The array has the wrong number of dimensions."""
class DisjointSet:
"""Union-Find data structure for managing disjoint sets."""
def __init__(self): ...
def makeset(self, x): ...
def find(self, x): ...
def union(self, x, y): ...
class StatisticsDict(typing.TypedDict):
voxel_counts: NDArray[np.uint32]
bounding_boxes: list[tuple[slice, slice, slice]]
centroids: NDArray[np.float64]
class StatisticsSlicesDict(typing.TypedDict):
voxel_counts: NDArray[np.uint32]
bounding_boxes: NDArray[np.uint16]
centroids: NDArray[np.float64]
# Type variables for generic functions
VcgT = typing.TypeVar("VcgT", np.uint8, np.uint32)
IntegerT = typing.TypeVar("IntegerT", bound=np.integer)
UnsignedIntegerT = typing.TypeVar("UnsignedIntegerT", bound=np.unsignedinteger)
# External types (requires optional dependencies)
from crackle import CrackleArray # Available with 'pip install connected-components-3d[stack]'