diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index b016bc2..35cacfd 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -3,7 +3,7 @@ name: pre-commit on: pull_request: push: - branches: [main] + branches: ["main", "spiros-dev"] jobs: pre-commit: diff --git a/.github/workflows/sphinx-docs.yml b/.github/workflows/sphinx-docs.yml index 14fef2b..ccc1863 100644 --- a/.github/workflows/sphinx-docs.yml +++ b/.github/workflows/sphinx-docs.yml @@ -1,7 +1,7 @@ name: Deploy static content to Pages on: push: - branches: ["main"] + branches: ["main", "spiros-dev"] jobs: build-docs: diff --git a/NiChart_DLMUSE/CalcROIVol.py b/NiChart_DLMUSE/CalcROIVol.py index ad523fb..6910ce6 100644 --- a/NiChart_DLMUSE/CalcROIVol.py +++ b/NiChart_DLMUSE/CalcROIVol.py @@ -11,9 +11,19 @@ logging.basicConfig(filename="pipeline.log", encoding="utf-8", level=logging.DEBUG) -def calc_roi_volumes(mrid: Any, in_img: Any, label_indices: Any) -> pd.DataFrame: +def calc_roi_volumes(mrid: Any, in_img: Any, label_indices: np.ndarray) -> pd.DataFrame: """ Creates a dataframe with the volumes of rois + + :param mrid: the input mrid + :type mrid: Any + :param in_img: the input image + :type in_img: niftii image + :param label_indices: passed label indices + :type label_indices: np.ndarray + + :return: Dataframe with details of images + :rtype: pd.DataFrame """ # Keep input lists as arrays @@ -56,6 +66,14 @@ def calc_roi_volumes(mrid: Any, in_img: Any, label_indices: Any) -> pd.DataFrame def append_derived_rois(df_in: pd.DataFrame, derived_roi_map: Any) -> pd.DataFrame: """ Calculates a dataframe with the volumes of derived rois. + + :param df_in: the passed dataframe + :type df_in: pd.DataFrame + :param derived_roi_map: derived roi map file + :type derived_roi_map: Any + + :return: ROI dataframe + :rtype: pd.DataFrame """ # Read derived roi map file to a dictionary @@ -91,6 +109,17 @@ def create_roi_csv( ) -> None: """ Creates a csv file with the results of the roi calculations + + :param mrid: the input mrid + :type mrid: Any + :param in_roi: the input ROI + :type in_roi: Any + :param map_derived_roi: derived roi map file + :type map_derived_roi: Any + :param out_csv: output csv filename + :type out_csv: str + + :rtype: None """ # Calculate MUSE ROIs @@ -122,6 +151,19 @@ def apply_create_roi_csv( ) -> None: """ Apply roi volume calc to all images + + :param df_img: the passed dataframe + :type df_img: pd.DataFrame + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :type in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) @@ -140,6 +182,19 @@ def combine_roi_csv( ) -> None: """ Combine csv files + + :param df_img: passed dataframe + :type df_img: pd.DataFrame + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :type in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_name: the desired output filename + :type out_name: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) diff --git a/NiChart_DLMUSE/MaskImage.py b/NiChart_DLMUSE/MaskImage.py index d88ac4e..8e01809 100644 --- a/NiChart_DLMUSE/MaskImage.py +++ b/NiChart_DLMUSE/MaskImage.py @@ -66,10 +66,16 @@ def calc_bbox_with_padding(img: np.ndarray, perc_pad: int = 10) -> np.ndarray: return bcoors -def mask_img(in_img: Any, mask_img: Any, out_img: Any) -> None: +def mask_img(in_img: Any, mask_img: Any, out_img: str) -> None: """ Applies the input mask to the input image Crops the image around the mask + + :param in_img: the passed image + :param mask_img: the input mask + :param out_img: the output filename + :type out_img: str + :rtype: None """ # Read input image and mask @@ -99,9 +105,16 @@ def mask_img(in_img: Any, mask_img: Any, out_img: Any) -> None: nii_out.to_filename(out_img) -def combine_masks(dlmuse_mask: Any, dlicv_mask: Any, out_img: Any) -> None: +def combine_masks(dlmuse_mask: Any, dlicv_mask: Any, out_img: str) -> None: """' Combine icv and muse masks + + :param dlmuse_mask: The passed dlmuse mask + :param dlicv_mask: The passed dlicv mask + :param out_img: the output filename + :type out_img: str + + :rtype: None """ # Read input images @@ -146,6 +159,21 @@ def apply_mask_img( ) -> None: """ Apply reorientation to all images + + :param df_img: The passed dataframe + :type df_img: pd.DataFrame + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the passed input suffix + :type in_suff: str + :param mask_dir: the passed mask directory + :type mask_dir: str + :param out_dir: the passed output directory + :type out_dir: str + :param out_suff: the passed output suffix + :type out_suff: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) @@ -170,6 +198,23 @@ def apply_combine_masks( ) -> None: """ Apply reorientation to all images + + :param df_img: the passed dataframe + :type df_img: pd.DataFrame + :param dlmuse_dir: the passed dlmuse directory + :type dlmuse_dir: str + :param dlmuse_suff: the passed dlmuse suffix + :type dlmuse_suff: str + :param dlicv_dir: the passed dlicv directory + :type dlicv_dir: str + :param dlicv_suff: the passed dlicv suffix + :type dlicv_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) diff --git a/NiChart_DLMUSE/RelabelROI.py b/NiChart_DLMUSE/RelabelROI.py index 9e369f9..cad6fa9 100644 --- a/NiChart_DLMUSE/RelabelROI.py +++ b/NiChart_DLMUSE/RelabelROI.py @@ -11,10 +11,21 @@ def relabel_rois( ) -> None: """ Convert labels in input roi image to new labels based on the mapping - print() The mapping file should contain numeric indices for the mapping - irint() between the input roi image (from) and output roi image (to) + + :param in_img: the passed image + :type in_img: niftii image + :param roi_map: the passed roi map + :type roi_map: str + :param label_from: input roi image + :type label_from: Any + :param label_to: output roi image + :type label_to: Any + :param out_img: the desired filename for the output image + :type out_img: str + + :rtype: None """ # Read image @@ -52,6 +63,25 @@ def apply_relabel_rois( ) -> None: """ Apply relabeling to all images + + :param df_img: the passed dataframe + :type df_img: pd.DataFrame + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :type in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + :param roi_map: the roi map + :type roi_map: Any + :param label_from: input roi image + :type label_from: Any + :param label_to: output roi image + :type label_to: Any + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) diff --git a/NiChart_DLMUSE/ReorientImage.py b/NiChart_DLMUSE/ReorientImage.py index 13c31b8..965f195 100644 --- a/NiChart_DLMUSE/ReorientImage.py +++ b/NiChart_DLMUSE/ReorientImage.py @@ -12,9 +12,16 @@ logging.basicConfig(filename="pipeline.log", encoding="utf-8", level=logging.DEBUG) -def reorient_img(in_img: Any, ref: Any, out_img: Any) -> None: +def reorient_img(in_img: Any, ref: Any, out_img: str) -> None: """ Reorient image + + :param in_img: the input image + :type in_img: niftii image + :param out_img: the desired filename for the output image + :type out_img: str + + :rtype: None """ if os.path.exists(out_img): logging.info("Out file exists, skip reorientation ...") @@ -50,6 +57,15 @@ def apply_reorient_img( ) -> None: """ Apply reorientation to all images + + :param df_img: the passed dataframe + :type df_img: pd.DataFrame + :param out_dir: the output directory + :type out_dir: str + :param out_suffix: the output suffix + :type out_suffix: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) @@ -61,10 +77,23 @@ def apply_reorient_img( def apply_reorient_to_init( - df_img: pd.DataFrame, in_dir: str, in_suff: Any, out_dir: str, out_suff: str + df_img: pd.DataFrame, in_dir: str, in_suff: str, out_dir: str, out_suff: str ) -> None: """ Apply reorientation to init img to all images + + :param df_img: the passed dataframe + :type df_img: pd.DataFrame + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :param in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + + :rtype: None """ if not os.path.exists(out_dir): os.makedirs(out_dir) diff --git a/NiChart_DLMUSE/SegmentImage.py b/NiChart_DLMUSE/SegmentImage.py index 14e6ef4..90b9adc 100644 --- a/NiChart_DLMUSE/SegmentImage.py +++ b/NiChart_DLMUSE/SegmentImage.py @@ -6,12 +6,30 @@ def run_dlicv( in_dir: str, - in_suff: Any, + in_suff: str, out_dir: str, - out_suff: Any, + out_suff: str, device: str, extra_args: str = "", ) -> None: + """ + Run dlicv with the passed images + + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :type in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + :param device: cuda/mps for GPU acceleration otherwise cpu + :type device: str + :param extra_args: extra arguments for DLICV package + :type extra_args: str + + :rtype: None + """ # Call DLICV os.system(f"DLICV -i {in_dir} -o {out_dir} -device {device} " + extra_args) @@ -28,6 +46,24 @@ def run_dlmuse( device: str, extra_args: str = "", ) -> None: + """ + Run dlmuse with the passed images + + :param in_dir: the input directory + :type in_dir: str + :param in_suff: the input suffix + :type in_suff: str + :param out_dir: the output directory + :type out_dir: str + :param out_suff: the output suffix + :type out_suff: str + :param device: cuda/mps for GPU acceleration otherwise cpu + :type device: str + :param extra_args: extra arguments for DLMUSE package + :type extra_args: str + + :rtype: None + """ # Call DLMUSE os.system(f"DLMUSE -i {in_dir} -o {out_dir} -device {device} " + extra_args) diff --git a/NiChart_DLMUSE/dlmuse_pipeline.py b/NiChart_DLMUSE/dlmuse_pipeline.py index a498c16..b533937 100644 --- a/NiChart_DLMUSE/dlmuse_pipeline.py +++ b/NiChart_DLMUSE/dlmuse_pipeline.py @@ -45,6 +45,21 @@ def run_pipeline( ) -> None: """ NiChart pipeline + + :param in_data: the input directory + :type in_data: str + :param out_dir: the output directory + :type out_dir: str + :param device: conda/mps for GPU acceleration otherwise cpu + :type device: str + :param dlmuse_extra_args: extra arguments for DLMUSE package + :type dlmuse_extra_args: str + :param dlicv_extra_args: extra arguments for DLICV package + :type dlicv_extra_args: str + :param sub_fldr: the number of subfolders(default = 1) + :type sub_fldr: int + + :rtype: None """ logging.info(f"Starting the pipeline on folder {sub_fldr}") logging.info(f"Detecting input images for batch [{sub_fldr}]...") diff --git a/README.md b/README.md deleted file mode 100644 index c1661c1..0000000 --- a/README.md +++ /dev/null @@ -1,143 +0,0 @@ -# NiChart_DLMUSE - -[![codecov](https://codecov.io/gh/CBICA/NiChart_DLMUSE/graph/badge.svg?token=i5Vyjayoct)](https://codecov.io/gh/CBICA/NiChart_DLMUSE) -![MacOS Build](https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/macos_build.yml/badge.svg) -![Ubuntu Build](https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/ubuntu_build.yml/badge.svg) -![PyPI Stable](https://img.shields.io/pypi/v/NiChart_DLMUSE) - -## Overview - -NiChart_DLMUSE is a package that allows the users to process their brain imaging (sMRI) data easily and efficiently. - -NiChart_DLMUSE offers easy ICV (Intra-Cranial Volume) mask extraction, and brain segmentation into ROIs. This is achieved through the [DLICV](https://github.com/CBICA/DLICV) and [DLMUSE](https://github.com/CBICA/DLMUSE) methods. Intermediate step results are saved for easy access to the user. - -Given an input (sMRI) scan, NiChart_DLMUSE extracts the following: - -1. ICV mask -2. Brain MUSE ROI segmentation -3. ROI volumes in a .csv format -4. Individual ROI mask (optionally). - -This package uses [nnU-Net v2](https://github.com/MIC-DKFZ/nnUNet) as a basis model architecture for the deep learning parts, and various other [libraries](requirements.txt). - - -## Installation - -### As a locally installed package - -1. Create a new conda env - - ```bash - conda create --name NCP python=3.12 - conda activate NCP - ``` - -2. Install DLICV and DLMUSE - ```bash - pip install DLICV - pip install DLMUSE - ``` - -3. Install NiChart_DLMUSE from GitHub Repo or PyPi - - ```bash - git clone https://github.com/CBICA/NiChart_DLMUSE.git - cd NiChart_DLMUSE - pip install -e . - ``` - or - ```bash - pip install NiChart_DLMUSE - ``` - -5. (If needed for your system) Install PyTorch with compatible CUDA. - You only need to run this step if you experience errors with CUDA while running NiChart_DLMUSE. - Run "pip uninstall torch torchaudio torchvision". - Then follow the [PyTorch installation instructions](https://pytorch.org/get-started/locally/) for your CUDA version. - -6. Run NiChart_DLMUSE. Example usage below - - ```bash - NiChart_DLMUSE -i /path/to/input \ - -o /path/to/output \ - -d cpu/cuda/mps - ``` - -### Docker/Singularity/Apptainer-based build and installation - -#### Docker build -The package comes already pre-built as a [docker container](https://hub.docker.com/repository/docker/cbica/nichart_dlmuse/general), for convenience. Please see [Usage](#usage) for more information on how to use it. Alternatively, you can build the docker image locally, like so: - -```bash -docker build -t cbica/nichart_dlmuse . -``` - -#### (OUTDATED) Singularity/Apptainer build -Singularity and Apptainer images can be built for NiChart_DLMUSE, allowing for frozen versions of the pipeline and easier installation for end-users. -Note that the Singularity project recently underwent a rename to "Apptainer", with a commercial fork still existing under the name "Singularity" (confusing!). -Please note that while for now these two versions are largely identical, future versions may diverge. It is recommended to use the AppTainer distribution. For now, these instructions apply to either. - -First install [the container engine](https://apptainer.org/admin-docs/3.8/installation.html). -Then, from the cloned project repository, run: - -```bash -singularity build nichart_dlmuse.sif singularity.def -``` - -This will take some time, but will build a containerized version of your current repo. Be aware that this includes any local changes! -The nichart_dlmuse.sif file can be distributed via direct download, or pushed to a container registry that accepts SIF images. - -## Usage -Pre-trained nnUNet models for the skull-stripping can be found in [HuggingFace nichart/DLICV](https://huggingface.co/nichart/DLICV/tree/main) and segmentation tasks can be found in [HuggingFace nichart/DLMUSE](https://huggingface.co/nichart/DLMUSE/tree/main). Feel free to use it under the package's [license](LICENSE). - -### As a locally installed package - -A complete command would be (run from the directory of the package): - -```bash - -NiChart_DLMUSE -i /path/to/input \ - -o /path/to/output \ - -d cpu/cuda/mps -``` - -For further explanation please refer to the complete documentation: - -```bash -NiChart_DLMUSE -h -``` - -#### Troubleshooting model download failures -Our model download process creates several deep directory structures. If you are running on Windows and your model download process fails, it may be due to Windows file path limitations. - -To enable long path support in Windows 10, version 1607, and later, the registry key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled (Type: REG_DWORD)` must exist and be set to 1. - -If this affects you, we recommend re-running NiChart_DLMUSE with the `--clear_cache` flag set on the first run. - -### Using the docker container - -Using the file structure explained above, an example command using the [docker container](https://hub.docker.com/repository/docker/cbica/nichart_dlmuse/general) is the following: - - -```bash -# Pull the image for your CUDA version (as needed) -CUDA_VERSION=11.8 docker pull cbica/nichart_dlmuse:1.0.1-cuda${CUDA_VERSION} -# or, for CPU: -docker pull cbica/nichart_dlmuse:1.0.1 - -# Run the container with proper mounts, GPU enabled -# Place input in /path/to/input/on/host. -# Replace "-d cuda" with "-d mps" or "-d cpu" as needed... -# or don't pass at all to automatically use CPU. -# Each "/path/to/.../on/host" is a placeholder, use your actual paths! -docker run -it --name DLMUSE_inference --rm - --mount type=bind,source=/path/to/input/on/host,target=/input,readonly - --mount type=bind,source=/path/to/output/on/host,target=/output - --gpus all cbica/nichart_dlmuse -d cuda -``` - -### (OUTDATED) Using the singularity container - -```bash -singularity run --nv --containall --bind /path/to/.\:/workspace/ nichart_dlmuse.simg NiChart_DLMUSE -i /workspace/temp/nnUNet_raw_data_base/nnUNet_raw_data/ -o /workspace/temp/nnUNet_out -p structural --derived_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_derived_rois.csv --MUSE_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_consecutive_indices.csv --nnUNet_raw_data_base /workspace/temp/nnUNet_raw_data_base/ --nnUNet_preprocessed /workspace/temp/nnUNet_preprocessed/ --model_folder /workspace/temp/nnUNet_model/ --all_in_gpu True --mode fastest --disable_tta -``` diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..cc6b7b8 --- /dev/null +++ b/README.rst @@ -0,0 +1,152 @@ +NiChart_DLMUSE +============== + +.. image:: https://codecov.io/gh/CBICA/NiChart_DLMUSE/graph/badge.svg?token=i5Vyjayoct + :target: https://codecov.io/gh/CBICA/NiChart_DLMUSE + :alt: Code Coverage + +.. image:: https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/macos_build.yml/badge.svg + :target: https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/macos_build.yml + :alt: macOS Build + +.. image:: https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/ubuntu_build.yml/badge.svg + :target: https://github.com/CBICA/NiChart_DLMUSE/actions/workflows/ubuntu_build.yml + :alt: Ubuntu Build + +.. image:: https://img.shields.io/pypi/v/NiChart_DLMUSE + :target: https://pypi.org/project/NiChart_DLMUSE/ + :alt: PyPI Stable + +Overview +-------- + +**NiChart_DLMUSE** is a package that allows the users to process their brain imaging (sMRI) data easily and efficiently. + +NiChart_DLMUSE offers easy ICV (Intra-Cranial Volume) mask extraction, and brain segmentation into ROIs. This is achieved through the `DLICV `_ and `DLMUSE `_ methods. Intermediate step results are saved for easy access to the user. + +Given an input (sMRI) scan, NiChart_DLMUSE extracts the following: + + 1. ICV mask + 2. Brain MUSE ROI segmentation + 3. ROI volumes in a .csv format + 4. Individual ROI mask (optionally). + +This package uses `nnU-Net v2 `_ as a basis model architecture for the deep learning parts, and various other `libraries `_. + +Installation +------------ + +****************************** +As a locally installed package +****************************** + +You can install NiChart DLMUSE from source: :: + + $ git clone https://github.com/CBICA/NiChart_DLMUSE.git + cd NiChart_DLMUSE + python3 -m pip install -e . + +Or from out latest stable PyPI wheel: :: + + $ pip install NiChart_DLMUSE + +(If needed for your system) Install PyTorch with compatible CUDA. +You only need to run this step if you experience errors with CUDA while running NiChart_DLMUSE. +Run "pip uninstall torch torchaudio torchvision". +Then follow the `PyTorch installation instructions `_ for your CUDA version. + +****************** +Run NiChart_DLMUSE +****************** + +Example usage below: :: + + $ NiChart_DLMUSE -i /path/to/input \ + -o /path/to/output \ + -d cpu/cuda/mps + +Docker/Singularity/Apptainer-based build and installation +--------------------------------------------------------- + +************ +Docker build +************ + +The package comes already pre-built as a `docker container `_, for convenience. Please see `Usage <#usage>`_ for more information on how to use it. Alternatively, you can build the docker image +locally, like so: :: + + $ docker build -t cbica/nichart_dlmuse . + +************************************** +(OUTDATED) Singularity/Apptainer build +************************************** + +Singularity and Apptainer images can be built for NiChart_DLMUSE, allowing for frozen versions of the pipeline and easier installation for end-users. +Note that the Singularity project recently underwent a rename to "Apptainer", with a commercial fork still existing under the name "Singularity" (confusing!). +Please note that while for now these two versions are largely identical, future versions may diverge. It is recommended to use the AppTainer distribution. For now, these instructions apply to either. + +First install `the container engine `_. +Then, from the cloned project repository, run: :: + + $ singularity build nichart_dlmuse.sif singularity.def + +This will take some time, but will build a containerized version of your current repo. Be aware that this includes any local changes! +The nichart_dlmuse.sif file can be distributed via direct download, or pushed to a container registry that accepts SIF images. + +***** +Usage +***** + +Pre-trained nnUNet models for the skull-stripping can be found in `HuggingFace nichart/DLICV `_ and segmentation tasks +can be found in `HuggingFace nichart/DLMUSE `_. Feel free to use it under the package's `license `_. + +****************************** +As a locally installed package +****************************** + +A complete command would be (run from the directory of the package): :: + + $ NiChart_DLMUSE -i /path/to/input \ + -o /path/to/output \ + -d cpu/cuda/mps + +For further explanation please refer to the complete documentation: :: + + $ NiChart_DLMUSE -h + +Troubleshooting model download failures +--------------------------------------- + +Our model download process creates several deep directory structures. If you are running on Windows and your model download process fails, it may be due to Windows file path limitations. + +To enable long path support in Windows 10, version 1607, and later, the registry key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled (Type: REG_DWORD)` must exist and be set to 1. + +If this affects you, we recommend re-running NiChart_DLMUSE with the `--clear_cache` flag set on the first run. + +Using the docker container +-------------------------- + +Using the file structure explained above, an example command using the `docker container `_ is the following: :: + + # Pull the image for your CUDA version (as needed) + $ CUDA_VERSION=11.8 docker pull cbica/nichart_dlmuse:1.0.1-cuda${CUDA_VERSION} + # or, for CPU: + $ docker pull cbica/nichart_dlmuse:1.0.1 + + # Run the container with proper mounts, GPU enabled + # Place input in /path/to/input/on/host. + # Replace "-d cuda" with "-d mps" or "-d cpu" as needed... + # or don't pass at all to automatically use CPU. + # Each "/path/to/.../on/host" is a placeholder, use your actual paths! + $ docker run -it --name DLMUSE_inference --rm + --mount type=bind,source=/path/to/input/on/host,target=/input,readonly + --mount type=bind,source=/path/to/output/on/host,target=/output + --gpus all cbica/nichart_dlmuse -d cuda + + +(OUTDATED) singularity container +------------------------------------------ + +To use the singularity container, you can just do: :: + + $ singularity run --nv --containall --bind /path/to/.\:/workspace/ nichart_dlmuse.simg NiChart_DLMUSE -i /workspace/temp/nnUNet_raw_data_base/nnUNet_raw_data/ -o /workspace/temp/nnUNet_out -p structural --derived_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_derived_rois.csv --MUSE_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_consecutive_indices.csv --nnUNet_raw_data_base /workspace/temp/nnUNet_raw_data_base/ --nnUNet_preprocessed /workspace/temp/nnUNet_preprocessed/ --model_folder /workspace/temp/nnUNet_model/ --all_in_gpu True --mode fastest --disable_tta diff --git a/docs/NiChart_DLMUSE.rst b/docs/NiChart_DLMUSE.rst deleted file mode 100644 index e9058e7..0000000 --- a/docs/NiChart_DLMUSE.rst +++ /dev/null @@ -1,117 +0,0 @@ -NiChart\_DLMUSE package -======================= - -Submodules ----------- - -NiChart\_DLMUSE.CalculateROIVolume module ------------------------------------------ - -.. automodule:: NiChart_DLMUSE.CalculateROIVolume - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.CalculateROIVolumeInterface module --------------------------------------------------- - -.. automodule:: NiChart_DLMUSE.CalculateROIVolumeInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.CombineMasks module ------------------------------------ - -.. automodule:: NiChart_DLMUSE.CombineMasks - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.CombineMasksInterface module --------------------------------------------- - -.. automodule:: NiChart_DLMUSE.CombineMasksInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.MaskImage module --------------------------------- - -.. automodule:: NiChart_DLMUSE.MaskImage - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.MaskImageInterface module ------------------------------------------ - -.. automodule:: NiChart_DLMUSE.MaskImageInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.ROIRelabelInterface module ------------------------------------------- - -.. automodule:: NiChart_DLMUSE.ROIRelabelInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.ROIRelabeler module ------------------------------------ - -.. automodule:: NiChart_DLMUSE.ROIRelabeler - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.ReorientImage module ------------------------------------- - -.. automodule:: NiChart_DLMUSE.ReorientImage - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.ReorientImageInterface module ---------------------------------------------- - -.. automodule:: NiChart_DLMUSE.ReorientImageInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.Structural module ---------------------------------- - -.. automodule:: NiChart_DLMUSE.Structural - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.nnUNetInterface module --------------------------------------- - -.. automodule:: NiChart_DLMUSE.nnUNetInterface - :members: - :undoc-members: - :show-inheritance: - -NiChart\_DLMUSE.utils module ----------------------------- - -.. automodule:: NiChart_DLMUSE.utils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: NiChart_DLMUSE - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..da2b30e --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,70 @@ +NiChart\_DLMUSE source code +=========================== + +Submodules +---------- + +DLMUSE pipeline +-------------------------------------------- + +.. automodule:: NiChart_DLMUSE.dlmuse_pipeline + :members: + :undoc-members: + :show-inheritance: + +Calculate ROI Volume module +----------------------------------------- + +.. automodule:: NiChart_DLMUSE.CalcROIVol + :members: + :undoc-members: + :show-inheritance: + + +Mask Image +-------------------------------- + +.. automodule:: NiChart_DLMUSE.MaskImage + :members: + :undoc-members: + :show-inheritance: + +Relabel ROI +-------------------------------- + +.. automodule:: NiChart_DLMUSE.RelabelROI + :members: + :undoc-members: + :show-inheritance: + +Reorient Image +------------------------------------------ + +.. automodule:: NiChart_DLMUSE.ReorientImage + :members: + :undoc-members: + :show-inheritance: + +Segment Image +--------------------------------------------- + +.. automodule:: NiChart_DLMUSE.SegmentImage + :members: + :undoc-members: + :show-inheritance: + +util functions +---------------------------- + +.. automodule:: NiChart_DLMUSE.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: NiChart_DLMUSE + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py index acbb7f7..89a6572 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output github_username = "CBICA" -github_repository = "github.com/CBICA/spare_score" +github_repository = "github.com/CBICA/NiChart_DLMUSE" html_theme = "sphinx_rtd_theme" html_static_path = ["_static"] diff --git a/docs/contributors.rst b/docs/contributors.rst new file mode 100644 index 0000000..cc3e4b4 --- /dev/null +++ b/docs/contributors.rst @@ -0,0 +1,76 @@ +############ +Contributing +############ + +This document explains how to prepare your environment to contribute to our package. +Note that we always update our main branch if we want to update the stable release on PyPI, thus, creating +your own branch is recommended so that you can open a pull request. + +***************** +Third party tools +***************** + +We use pre-commit as our main tool for code formatting and checking. You always have to make sure that pre-commit pass in order to open a pull request. +You can perform this test just following these steps: :: + + # If you don't have pre-commit installed + $ pip install pre-commit && pre-commit install + + # Then run pre-commit + pre-commit run --color=always --all-files + +We already have all the necessairy hooks at our `configuration <../.pre-commit-config.yaml>`_. + +For our unit testing, we use pytest. Again, in order to contribute you need to make sure that all of the unit tests pass. +You can perform this test following these steps: :: + + # If you don't have pytest installed + $ pip install pytest pytest-cov + + # Run pytest + cd tests/ && pytest + +.. note:: + + We highly suggest you to install the dev requirements before contributing: :: + + $ pip install -r requirements.txt + +************ +Coding style +************ + +We follow a specific coding style that, luckily, can be easily checked with pre-commit. First and foremost, you should always add documentation to any new features you add. +We follow ``sphinx``'s docstring style so that the parser can detect the code comments and display them beautifully at our read-the-docs. Let's assume that you add a new function: + +.. code-block:: python + + def foo(param1: int, param2: str, param3: list) -> int: + """ + Brief explanation of what foo does. + + :param param1: Description of param1. + :type param1: int + :param param2: Description of param2. + :type param2: str + :param param3: Description of param3. + :type param3: list + :return: Description of the return value. + :rtype: int + """ + +``pre-commit`` will also check if you include libraries that are not needed, any extra spaces you might have, logic errors and much more. + +Also, as you see above, you should always add types and return types to every function and class. We only write Python 3 code. If you don't follow all of the above, ``pre-commit`` won't pass, and a maintainer won't review your pull request. + +************** +Good practices +************** + + - At your pull request, explain your additions, why are they useful or what they fix. There are currently no templates to follow for this, but you can just write a sufficient explanation so that a maintainer can understand your additions/fixes. + + - Write a nice commit message. + + - Make sure to follow the issue template if you want to open an issue. + + - Make sure to always add any third-party libraries that you add at the requirements so that the actions can install them. diff --git a/docs/help.rst b/docs/help.rst new file mode 100644 index 0000000..eebe789 --- /dev/null +++ b/docs/help.rst @@ -0,0 +1,12 @@ +############ +Getting help +############ + +If you have a problem or would like to ask a question about the inner workings of **NiChart DLMUSE** you can directly +message our maintaners via email. + +.. note:: + +You can reach out to all our maintaners by sending an email to software@cbica.upenn.edu + +If you have a bug or you like to suggest a feature request please follow the `contribution guide <../.github/CONTRIBUTE/>`_ and the `issue guide <../.github/ISSUES/>`_. diff --git a/docs/index.rst b/docs/index.rst index 8ec7849..05aea21 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,20 +1,14 @@ -.. NiChart_DLMUSE documentation master file, created by - sphinx-quickstart on Fri Jul 19 13:56:53 2024. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. include:: ../README.rst -Welcome to NiChart_DLMUSE's documentation! -========================================== +######## +Contents +######## .. toctree:: - :maxdepth: 2 - :caption: Contents: + :maxdepth: 3 - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + installation + usage + contributors + api + help diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..82b9555 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,55 @@ +############ +Installation +############ + +There are many ways you can install our package, using pip to download our latest stable version, +Docker, Singularity/Apptainer or manual installation directly from the source code. We highly suggest to install +our latest PyPI wheel. Note that the Singularity/Apptainer versions are outdated. + + +**************** +Install with pip +**************** + +To install **NiChart DLMUSE** with pip, just do: :: + + $ pip install NiChart_DLMUSE + +We always have our latest stable version on PyPI, so we highly suggest you to install it this way, as this package is under +heavy development and building from source can lead to crashes and bugs. + + +.. _`Docker Container`: + +**************** +Docker Container +**************** + +The package comes already pre-built as a docker container that you can download at our `docker hub `_. +You can build the package by running the following command: :: + + $ docker build -t cbica/nichart_dlmuse . + +.. _`Singularity/Apptainer build` + +Singularity and Apptainer images can be built for NiChart_DLMUSE, allowing for frozen versions of the pipeline and easier +installation for end-users. Note that the Singularity project recently underwent a rename to "Apptainer", with a commercial +fork still existing under the name "Singularity" (confusing!). Please note that while for now these two versions are largely identical, +future versions may diverge. It is recommended to use the AppTainer distribution. For now, these instructions apply to either. +After installing the container engine, run: :: + + $ singularity build nichart_dlmuse.sif singularity.def + +This will take some time, but will build a containerized version of your current repo. Be aware that this includes any local changes! +The nichart_dlmuse.sif file can be distributed via direct download, or pushed to a container registry that accepts SIF images. + +.. _`Manual installation` + +You can manually build the package from source by running: :: + + $ git clone https://github.com/CBICA/NiChart_DLMUSE + + $ cd NiChart_DLMUSE && python3 -m pip install -e . + +We **do not** recomment installing the package directly from source as the repository above is under heavy development and can cause +crashes and bugs. diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..0b26c24 --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,74 @@ +##### +Usage +##### + +Pre-trained nnUNet models for the skull-stripping can be found in `HuggingFace nichart/DLICV `_ and +segmentation tasks can be found in `HuggingFace nichart/DLMUSE `_. Feel free to use it under the package's license. + +********* +Using CLI +********* + +Our CLI is simply to use as it just takes 2 required parameters: :: + + $ NiChart_DLMUSE -i -o + +By default, our CLI runs on CPU. You can run it on GPU with CUDA or MPS just by specifying the device: :: + + $ NiChart_DLMUSE -i -o -d cuda + + +.. note:: + + **MPS** Can be used if your chip supports 3d convolution(M1 chips do not support 3d convolution, thus, you can't use MPS with M1 macbooks) + + +We use batch splitting and paralellization to accelerate the procedure. By default, we split the input data into +4 subfolders. You can specify the number of subfolders with the ``-c`` or ``--cores`` option: :: + + $ NiChart_DLMUSE ... -c 6 + +This will create 6 subfolders instead of the default 4. + +We also support ``BIDS`` I/O in our latest stable release. In order to run NiChart DLMUSE with a BIDS folder as the input you +need to have one T1 image under the anat subfolder. After the run NiChart DLMUSE will return the segmented images in the same +subfolders. If you have a `BIDS` input folder you have to specify it at the CLI command: :: + + $ NiChart_DLMUSE ... --bids 1 + +For further explanation please refer to the complete CLI documentation: :: + + $ NiChart_DLMUSE -h + + +************************** +Using the docker container +************************** + +Using the file structure explained above, an example command using the `docker container `_ +is the following: :: + + # For GPU + $ CUDA_VERSION=11.8 docker pull cbica/nichart_dlmuse:1.0.1-cuda${CUDA_VERSION} + + # For CPU + docker pull cbica/nichart_dlmuse:1.0.4-default + + $ # Run the container with proper mounts, GPU enabled + # Place input in /path/to/input/on/host. + # Replace "-d cuda" with "-d mps" or "-d cpu" as needed... + # or don't pass at all to automatically use CPU. + # Each "/path/to/.../on/host" is a placeholder, use your actual paths! + docker run -it --name DLMUSE_inference --rm + --mount type=bind,source=/path/to/input/on/host,target=/input,readonly + --mount type=bind,source=/path/to/output/on/host,target=/output + --gpus all cbica/nichart_dlmuse -d cuda + + +******************************* +Using the singularity container +******************************* + +We do not recommend using the singularity container as is currently outdated and not maintaned: :: + + $ singularity run --nv --containall --bind /path/to/.\:/workspace/ nichart_dlmuse.simg NiChart_DLMUSE -i /workspace/temp/nnUNet_raw_data_base/nnUNet_raw_data/ -o /workspace/temp/nnUNet_out -p structural --derived_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_derived_rois.csv --MUSE_ROI_mappings_file /NiChart_DLMUSE/shared/dicts/MUSE_mapping_consecutive_indices.csv --nnUNet_raw_data_base /workspace/temp/nnUNet_raw_data_base/ --nnUNet_preprocessed /workspace/temp/nnUNet_preprocessed/ --model_folder /workspace/temp/nnUNet_model/ --all_in_gpu True --mode fastest --disable_tta diff --git a/requirements.txt b/requirements.txt index cdaaf67..79414b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,3 +11,4 @@ pytest-cov huggingface_hub argparse pathlib +pre-commit diff --git a/setup.py b/setup.py index 68e03bc..b353a48 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import find_packages, setup this_directory = Path(__file__).parent -long_description = (this_directory / "README.md").read_text() +long_description = (this_directory / "README.rst").read_text() setup( name="NiChart_DLMUSE",