Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
Signed-off-by: neuronflow <[email protected]>
  • Loading branch information
neuronflow committed Mar 30, 2024
1 parent 77d7fb1 commit 9a55b45
Show file tree
Hide file tree
Showing 126 changed files with 310 additions and 411 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
pip install -e .
pip install -e .[all]
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand Down
22 changes: 5 additions & 17 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
os: "ubuntu-22.04"
tools:
python: "3.10"
jobs:
post_create_environment:
# Install poetry
# https://python-poetry.org/docs/#installing-manually
- pip install poetry
# Tell poetry to not use a virtual environment
- poetry config virtualenvs.create false
post_install:
# Install dependencies with 'docs' dependency group
# https://python-poetry.org/docs/managing-dependencies/#dependency-groups
- poetry install --with docs
# VIRTUAL_ENV needs to be set manually for now.
# See https://github.com/readthedocs/readthedocs.org/pull/11152/
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/source/conf.py
# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:
# - pdf

# Optionally declare the Python requirements required to build your docs
configuration: docs/source/conf.py
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,16 @@


# BrainLes-Preprocessing
`BrainLes preprocessing` is a comprehensive tool for preprocessing tasks in biomedical imaging, with a focus on (but not limited to) multi-modal brain MRI. It can be used to build to build modular preprocessing pipelines:

`BrainLes-Preprocessing` is a comprehensive tool tailored for preprocessing tasks in medical imaging, with a current focus on brain MRIs. Here's what it can currently do:
This includes **normalization**, **co-registration**, **atlas registration** and **skulstripping / brain extraction**.

- **Co-registration using NiftyReg**: Aligning two images or series of images. While `NiftyReg` is the current tool used for co-registration, our architecture allows for potential extensions with other tools in the future.
- **Atlas Registration**: Maps images to a standard atlas for consistent spatial referencing.
- **Transformation**: Adjusts the image based on certain parameters.
- **Skull-stripping in BRATS-space**: Removes non-brain tissue from MRI data.
- **Apply Masking**: Applies a mask to an image, highlighting or hiding specific parts of it.
BrainLes is written `backend-agnostic` meaning it allows to swap the registration and brain extration tools.

The outcome of this processing sequence is a set of 4 NIFTI images, skull-stripped in BRATS-space. These results are then saved to the provided path.
<!-- TODO mention defacing -->

## Atlas Reference
<!-- TODO include image here -->

We use the SRI-24 atlas from this [publication](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2915788/)

## Installation

Expand All @@ -26,3 +22,26 @@ With a Python 3.10+ environment you can install directly from [pypi.org](https:/
```
pip install brainles-preprocessing
```


## Usage
Please have a look at our [Jupyter Notebook tutorials](https://github.com/BrainLesion/tutorials/tree/main/preprocessing) illustrating the usage of BrainLes preprocessing.


<!-- TODO citation -->


## FAQ
Please credit the authors by citing their work.

### Atlas Reference
We provide the SRI-24 atlas from this [publication](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2915788/).
However, custom atlases can be supplied.

### Brain extraction
We currently provide support for [HD-BET](https://github.com/MIC-DKFZ/HD-BET).

### Registration
We currently provide support for [niftyreg](https://github.com/KCL-BMEIS/niftyreg).

<!-- TODO mention defacing -->
98 changes: 90 additions & 8 deletions brainles_preprocessing/modality.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import shutil
from typing import List, Optional

from auxiliary.nifti.io import read_nifti, write_nifti
from auxiliary.normalization.normalizer_base import Normalizer
Expand Down Expand Up @@ -41,17 +42,73 @@ def __init__(
self,
modality_name: str,
input_path: str,
output_path: str,
bet: bool,
normalizer: Normalizer | None = None,
raw_bet_output_path: Optional[str] = None,
raw_skull_output_path: Optional[str] = None,
normalized_bet_output_path: Optional[str] = None,
normalized_skull_output_path: Optional[str] = None,
normalizer: Optional[Normalizer] = None,
atlas_correction: bool = True,
) -> None:
# basics
self.modality_name = modality_name

self.input_path = turbopath(input_path)
self.output_path = turbopath(output_path)
self.bet = bet
self.normalizer = normalizer
self.current = self.input_path

self.normalizer = normalizer
self.atlas_correction = atlas_correction

# check that atleast one output is generated
if (
raw_bet_output_path is None
and normalized_bet_output_path is None
and raw_skull_output_path is None
and normalized_skull_output_path is None
):
raise ValueError(
"All output paths are None. At least one output path must be provided."
)

# handle input paths
if raw_bet_output_path is not None:
self.raw_bet_output_path = turbopath(raw_bet_output_path)
else:
self.raw_bet_output_path = raw_bet_output_path

if raw_skull_output_path is not None:
self.raw_skull_output_path = turbopath(raw_skull_output_path)
else:
self.raw_skull_output_path = raw_skull_output_path

if normalized_bet_output_path is not None:
if normalizer is None:
raise ValueError(
"A normalizer must be provided if normalized_bet_output_path is not None."
)
self.normalized_bet_output_path = turbopath(normalized_bet_output_path)
else:
self.normalized_bet_output_path = normalized_bet_output_path

if normalized_skull_output_path is not None:
if normalizer is None:
raise ValueError(
"A normalizer must be provided if normalized_skull_output_path is not None."
)
self.normalized_skull_output_path = turbopath(normalized_skull_output_path)
else:
self.normalized_skull_output_path = normalized_skull_output_path

# print("self.raw_bet_output_path", self.raw_bet_output_path)
# print("self.normalized_skull_output_path", self.normalized_skull_output_path)
# print("self.bet:", self.bet)

@property
def bet(self) -> bool:
return any(
path is not None
for path in [self.raw_bet_output_path, self.normalized_bet_output_path]
)

def normalize(
self,
temporary_directory: str,
Expand Down Expand Up @@ -113,7 +170,9 @@ def register(
str: Path to the registration matrix.
"""
registered = os.path.join(registration_dir, f"{moving_image_name}.nii.gz")
registered_matrix = os.path.join(registration_dir, f"{moving_image_name}.txt")
registered_matrix = os.path.join(
registration_dir, f"{moving_image_name}"
) # note, add file ending depending on registration backend!
registered_log = os.path.join(registration_dir, f"{moving_image_name}.log")

registrator.register(
Expand Down Expand Up @@ -219,5 +278,28 @@ def extract_brain_region(
brain_mask_path=atlas_mask_path,
log_file_path=bet_log,
)
self.current = atlas_bet_cm
if self.bet is True:
self.current = atlas_bet_cm
return atlas_mask_path

def save_current_image(
self,
output_path: str,
normalization=False,
) -> None:
os.makedirs(output_path.parent, exist_ok=True)

if normalization is False:
shutil.copyfile(
self.current,
output_path,
)
elif normalization is True:
image = read_nifti(self.current)
print("current image", self.current)
normalized_image = self.normalizer.normalize(image=image)
write_nifti(
input_array=normalized_image,
output_nifti_path=output_path,
reference_nifti_path=self.current,
)
Loading

0 comments on commit 9a55b45

Please sign in to comment.