synthbold.geometries¶
Single geometries to generate label maps for the data synthesis pipeline.
- class synthbold.geometries.Cubes(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (0.05, 2.0), allow_overlap: bool = True, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom cube mask generator.
Generates random cube label masks with set volume fraction. Each cube is a regular cube placed at a random position in the volume with a random orientation and a random circumradius drawn uniformly from
diameter_range. Follows the same interface asCylinders; see that class for a full description of the shared parameters.Notes
The
diameter_rangeis interpreted as the circumdiameter (diameter of the circumscribed sphere), consistent with theTetrahedraconvention.Examples
Create 100 random cube label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> num_cubes = 10 >>> fname = "<fname-zarr>" >>> cube_map = Cubes(shape, fov, num_cubes) >>> cube_map(100, fname)
- class synthbold.geometries.CylinderTrees(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (0.05, 2.0), allow_overlap: bool = True, segment_length_range: tuple[float, float] = (2.0, 6.0), branch_prob: float = 0.35, branch_angle_range: tuple[float, float] = (0.2618, 0.7854), max_depth: int = 6, min_radius_fraction: float = 0.15, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom bifurcating cylinder tree mask generator.
Generates masks of randomly branching cylinder trees, each built from straight cylindrical segments connected end-to-end. Starting from a root segment with a random position, direction, and radius (drawn the same way as
Cylinders), each segment is extended by a random length and, with probability branch_prob, splits into two child segments instead of terminating. Child directions diverge from the parent by an angle drawn from branch_angle_range around a random azimuth, and child radii are derived from the parent radius via Murray’s law (r_parent^3 = r_child1^3 + r_child2^3) with a random asymmetric split, so calibre tapers realistically towards the leaves. A branch stops growing once its radius falls below min_radius_fraction of the root radius or max_depth generations have been reached. All segments belonging to one tree are written as a single object label.Follows the same interface as
Cylindersfor volume-fraction/num_objects control and root diameter sampling; see that class for a full description of the shared parameters.- Parameters:
segment_length_range – Range of individual segment lengths in mm.
branch_prob – Probability that a segment bifurcates into two children instead of terminating (subject to max_depth).
branch_angle_range – Range of angles in radians between a parent segment and each of its two children at a bifurcation.
max_depth – Maximum number of branching generations grown below the root.
min_radius_fraction – Fraction of the root radius below which a branch stops growing.
- Raises:
ValueError – If branch_prob is not in
[0, 1], if max_depth is negative, or if min_radius_fraction is not in(0, 1].
Examples
Create 100 random cylinder tree label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> num_trees = 5 >>> fname = "<fname-zarr>" >>> tree_map = CylinderTrees(shape, fov, num_trees) >>> tree_map(100, fname)
- property attrs: dict[str, Any]¶
Metadata for ZARR/NIfTI storage.
- class synthbold.geometries.Cylinders(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (0.05, 2.0), allow_overlap: bool = True, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom cylinder mask generator.
Generates random cylindrical label masks with set volume fraction. Volume fraction and diameters are randomly chosen from a uniform distribution with set boundaries. Optionally, instead of using volume fraction, the number of cylinders can be set directly.
These masks can be used to define random vessel distributions with set blood volume fraction and vessel diameters.
- Parameters:
shape – Matrix size of the cylinder label map
(X, Y, Z).fov – Field of view in mm, used to compute voxel size.
num_objects – Fixed number of cylinders to generate. Mutually exclusive with vf_range.
vf_range – Range of target volume fractions. Cylinders are added until the volume fraction is reached. Mutually exclusive with num_objects.
diameter_range – Range of cylinder diameters in mm.
allow_overlap – If False, cylinders are only added if they contribute new voxels.
device – Target compute device, e.g. ‘cuda’ or ‘cpu’.
seed – Random seed for reproducibility.
Examples
Create 100 random cylinder label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> num_cylinders = 10 >>> fname = "<fname-zarr>" >>> cylinder_map = Cylinders(output_shape, fov, num_cylinders) >>> cylinder_map(100, fname)
- class synthbold.geometries.Shapes(shape: tuple[int, int, int] = (128, 128, 128), J: int = 10, displacement_shape: tuple[int, int, int] = (2, 2, 2), scale: float = 0.2, *, device: str | device = 'cpu', seed: int | None = None)¶
Bases:
BaseGeometryRandom shape mask generator.
Generates masks with J input labels of random generic shapes. Maps are created by first drawing J smoothly varying noise images by sampling voxels from a standard distribution at lower resolution and upsampling to full size. Second, each image is warped with a random smooth deformation field. Third, we create an input mask by assigning, for each voxel, the label corresponding to the image that has the highest intensity (Hoffmann et al., 2021; Hoffmann et al., 2023).
These masks can be used to define random background tissue signal for synthetic BOLD data generation.
- Parameters:
shape – Matrix size of the target shape mask
(X, Y, Z).J – Number of distinct labels.
displacement_shape – Matrix size of the low-resolution displacement field.
scale – Scale factor of the low-resolution displacement field.
device – Target compute device, e.g. ‘cuda’ or ‘cpu’.
seed – Random seed for reproducibility.
- Raises:
ValueError – If J is less than 1, or if any displacement_shape dimension is less than 1.
Examples
Create 100 random maps and save to disk:
>>> J = 26 >>> shape = (32, 32, 32) >>> fname = "<fname.zarr>" >>> shape_mask = Shapes(shape, J) >>> shape_mask(100, fname)
References
Hoffmann, M. et al. (2021). Learning MRI contrast-agnostic registration. Proc IEEE Int Symp Biomed Imaging.
Hoffmann, M. et al. (2022). SynthMorph: Learning contrast-invariant registration without acquired images. IEEE Trans Med Imaging.
- property attrs: dict[str, Any]¶
Metadata for ZARR/NIfTI storage.
- forward() Tensor¶
Generate random shape mask.
- class synthbold.geometries.Spheres(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (0.05, 2.0), allow_overlap: bool = True, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom sphere mask generator.
Generates random spherical label masks. Follows the same interface as
Cylinders; see that class for a full description of the shared parameters.
- class synthbold.geometries.SplineVessels(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (32.0, 32.0, 32.0), nb_levels: int = 2, tree_density: tuple[float, float] = (0.01, 0.01), tortuosity: tuple[float, float] = (5.0, 3.0), radius: tuple[float, float] = (0.1, 0.02), radius_change: tuple[float, float] = (1.0, 0.1), nb_children: tuple[float, float] = (5.0, 5.0), radius_ratio: tuple[float, float] = (0.7, 0.1), device: str | device = 'cpu', seed: int | None = None)¶
Bases:
BaseGeometryRandom vessel-tree mask generator based on synthspline.
Generates a single hierarchical, branching vessel tree per sample using synthspline’s SynthSplineBlock, as an alternative to the straight-cylinder and cylinder-tree geometries in synthbold.geometries. Unlike those, tree topology and shape parameters (density, tortuosity, radius, branching) are drawn from log-normal distributions defined by synthspline itself rather than sampled here.
Requires the optional synthspline package; install with
pip install git+https://github.com/haenelt/synthspline.git@main. The dependency is only imported when this class is instantiated, so importing synthbold never requires it.- Parameters:
shape – Matrix size of the spline label map
(X, Y, Z).fov – Field of view in mm, used to compute voxel size.
nb_levels – Number of hierarchical levels in the tree.
tree_density –
(mean, std)of the log-normal distribution of trees/mm^3.tortuosity –
(mean, std)of the log-normal distribution of tortuosity (cord / length).radius –
(mean, std)of the log-normal distribution of the root radius in mm.radius_change –
(mean, std)of the log-normal distribution of radius variation along a spline.nb_children –
(mean, std)of the log-normal distribution of the number of branches per spline.radius_ratio –
(mean, std)of the log-normal distribution of the child/parent radius ratio.device – Target compute device, e.g. ‘cuda’ or ‘cpu’.
seed – Random seed for reproducibility.
Notes
synthspline draws from PyTorch’s global RNG rather than an explicit torch.Generator, so this class seeds torch.manual_seed once at construction time (if seed is given) as a best effort for reproducibility. Unlike the other geometries in this package, samples are therefore not reproducible if other unseeded PyTorch random calls are interleaved on the same process between samples.
- Raises:
ImportError – If synthspline is not installed.
Examples
Create 100 random spline vessel-tree label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> fname = "<fname.zarr>" >>> vessel_map = SplineVessels(shape, fov) >>> vessel_map(100, fname)
- property attrs: dict[str, Any]¶
Metadata for ZARR/NIfTI storage.
- forward() Tensor¶
Generate a single random spline vessel-tree label map.
- class synthbold.geometries.Tetrahedra(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (0.05, 2.0), allow_overlap: bool = True, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom tetrahedron mask generator.
Generates random tetrahedral label masks. Each tetrahedron is a regular tetrahedron placed at a random position in the volume with a random orientation and a random circumradius drawn uniformly from
diameter_range. Follows the same interface asCylinders; see that class for a full description of the shared parameters.Examples
Create 100 random tetrahedron label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> num_tetrahedra = 10 >>> fname = "<fname-zarr>" >>> tetra_map = Tetrahedra(shape, fov, num_tetrahedra) >>> tetra_map(100, fname)
- class synthbold.geometries.Toroids(shape: tuple[int, int, int] = (128, 128, 128), fov: tuple[float, float, float] = (1.0, 1.0, 1.0), num_objects: int | None = None, vf_range: tuple[float, float] | None = (0.05, 0.1), diameter_range: tuple[float, float] = (2.0, 10.0), tube_ratio_range: tuple[float, float] = (0.1, 0.4), allow_overlap: bool = True, device: str = 'cpu', seed: int | None = None)¶
Bases:
ObjectGeometryRandom toroid mask generator.
Generates random toroidal label masks with set volume fraction. Each torus is placed at a random position in the volume with a random orientation. The major radius (R, distance from the torus center to the tube center) is drawn uniformly from
diameter_rangeafter converting from mm to voxels. The tube radius (r) is set as a fraction of the major radius sampled uniformly fromtube_ratio_range. Follows the same interface asCylinders; see that class for a full description of the shared parameters.- Parameters:
tube_ratio_range – Range of r/R, where r is the tube radius. Must be in (0, 1) for a non-self-intersecting ring torus.
- Raises:
ValueError – If tube_ratio_range contains a value outside
(0, 1).
Examples
Create 100 random toroid label maps and save to disk:
>>> shape = (128, 128, 128) >>> fov = (32.0, 32.0, 32.0) >>> num_toroids = 5 >>> fname = "<fname-zarr>" >>> toroid_map = Toroids(shape, fov, num_toroids) >>> toroid_map(100, fname)
- property attrs: dict[str, Any]¶
Metadata for ZARR/NIfTI storage.