Getting started

Installation

PyTorch: Before installing the package, PyTorch needs to be installed which can be done using the instructions on PyTorch.

FetalBrain package: The fetalbrain package will be hosted on pip, but can currently be used by cloning the repository locally with:

$ git clone git@github.com:oxford-omni-lab-org/OMNI_ultrasound.git

User installation

The package can then be installed from the root of the repository with (This will install the package and all required dependencies):

$ pip install .

Then download the model weights using the provided command line downloader (this only downloads the model weights if that folder does not exists yet):

$ ftlbr_download_modelweights

To overwrite any existing downloads use:

$ ftlbr_download_modelweights --force

After installation and download of the model weights, the package can simply be used in Python with:

import fetalbrain

Development installation

To install the package for development, use:

$ pip install -e ".[all]"

This will install the package as editable, meaning that any changes to the package are immediately available without having to reinstall the package. The [all] option installs all dependencies needed for development, testing and documentation (as specified in the setup.cfg file). Also rerun the downlaoder to load the model weights in the correct location.

To perform testing, run the downloader with the additional argument –testdata to download the test data:

$ ftlbr_download_modelweights --testdata

Minimal Example

The following example shows a minimal example of using the whole pipeline to align, and segment a fetal brain scan.

from pathlib import Path
from fetalbrain.utils import read_image, write_image
from fetalbrain.alignment.align import align_scan
from fetalbrain.structural_segmentation.subcortical_segm import segment_scan_subc, compute_volume_segm
from fetalbrain.tedsnet_multi.teds_multi_segm import segment_scan_tedsall
from fetalbrain.brain_extraction.extract import extract_scan_brain
from fetalbrain.model_paths import EXAMPLE_IMAGE_PATH

example_scan, _ = read_image(EXAMPLE_IMAGE_PATH)

# Start with alignment to atlas space
aligned_scan, params = align_scan(example_scan, scale=False, to_atlas=True)

# Perform subcortical segmentation
subc_segm, subc_keys = segment_scan_subc(aligned_scan, connected_component=True)

# Use TEDSnet to do all structure segmentations
allstructure_segm, multi_keys = segment_scan_tedsall(aligned_scan)

# Extract the brain
brain_mask, brain_key = extract_scan_brain(aligned_scan)

# Write out the results in the aligned orientation
write_image(Path("aligned_scan.nii.gz"), aligned_scan.squeeze().numpy())
write_image(Path("subcortical_segm.nii.gz"), subc_segm.squeeze(), segm=True)
write_image(Path("allstructure_segm.nii.gz"), allstructure_segm.squeeze(), segm=True)
write_image(Path("brain_mask.nii.gz"), brain_mask.squeeze(), segm=True)

# compute volumes of the segmentation masks
volume_dict = compute_volume_segm(subc_segm, subc_keys, spacing=(0.6, 0.6, 0.6))
print(volume_dict)

Advanced Example

To run the pipeline for multiple scans and with more flexibility, it is recommended to use the individual pipeline functions rather than the wrapper functions. This ensures that the models are not reloaded for each scan. The following example demonstrates this for a single example.

from pathlib import Path
import torch
from fetalbrain.utils import read_image, write_image
from fetalbrain.alignment.align import load_alignment_model, align_to_atlas, prepare_scan
from fetalbrain.structural_segmentation.subcortical_segm import load_segmentation_model, segment_subcortical
from fetalbrain.tedsnet_multi.teds_multi_segm import (
    load_tedsmulti_model,
    segment_tedsall,
    load_sidedetector_model,
    detect_side,
)
from fetalbrain.brain_extraction.extract import extract_brain, load_brainextraction_model
from fetalbrain.alignment.kelluwen_transforms import apply_affine
from fetalbrain.model_paths import EXAMPLE_IMAGE_PATH


# Load the models once
align_model = load_alignment_model()
subc_segmmodel = load_segmentation_model()
teds_multimodel = load_tedsmulti_model()
side_detectormodel = load_sidedetector_model()
brainextraction_model = load_brainextraction_model()

# whether to do connected component analysis for subcortical segm
connected_component = True

# Loop over all scans (just one here as example)
example_scan, _ = read_image(EXAMPLE_IMAGE_PATH)
torch_scan = prepare_scan(example_scan)

# Start with alignment to atlas space
aligned_scan, params = align_to_atlas(torch_scan, align_model, scale=False)

# Perform subcortical segmentation
subc_segm, subc_keys = segment_subcortical(aligned_scan, subc_segmmodel, connected_component=True)

# Perform segmentation with multi structure tedsnet
side, prob_side = detect_side(aligned_scan, side_detectormodel)
allstructure_segm, multi_keys = segment_tedsall(aligned_scan, teds_multimodel, side=side)

# perform whole brian extraction (i.e. brain masking)
brain_mask, brain_key = extract_brain(aligned_scan, brainextraction_model)

# Write out the results in the aligned orientation
savefolder = Path("results")
savefolder.mkdir(exist_ok=True)
write_image(savefolder / "aligned_scan.nii.gz", aligned_scan.squeeze().numpy())
write_image(savefolder / "subcortical_segm.nii.gz", subc_segm.squeeze(), segm=True)
write_image(savefolder / "allstructure_segm.nii.gz", allstructure_segm.squeeze(), segm=True)
write_image(savefolder / "brain_mask.nii.gz", brain_mask.squeeze().numpy(), segm=True)


# to create segmentations in the original orientation
aligned_scan, params, affine = align_to_atlas(torch_scan, align_model, scale=False, return_affine=True)
subc_segm_original = apply_affine(torch.from_numpy(subc_segm).unsqueeze(0), affine.inverse(), type_resampling="nearest")

# Write out the results in the original orientation
write_image(savefolder / "original_scan.nii.gz", example_scan)
write_image(savefolder / "subcortical_segm_original.nii.gz", subc_segm_original.squeeze().numpy(),  # type: ignore
            segm=True)