{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Warning\n", "This tutorial is a work in progress, it does not cover all the functionalities of the preprocessing package yet." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# preprocessing tutorial\n", "In this Notebook, we will demonstrate how to preprocess brain MR images with the [BrainLes preprocessing package](https://github.com/BrainLesion/preprocessing/tree/main/brainles_preprocessing).\n", "\n", "\n", "### Requirements\n", "This tutorial requires:\n", "\n", "* Python 3.10+ environment\n", "* Docker\n", "* Linux (Windows and Mac OS will be supported in future versions)\n", "\n", "\n", "optional (but recommended):\n", "* CUDA\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Setup Colab environment\n", "If you installed the packages and requirements on your own machine, you can skip this section and start from the import section. Otherwise you can follow and execute the tutorial on your browser. In order to start working on the notebook, click on the following button, this will open this page in the Colab environment and you will be able to execute the code on your own.\n", "\n", "\n", " \"Open\n", "\n", "\n", "Now that you are visualizing the notebook in Colab, run the next cell to install the packages we will use. There are few things you should follow in order to properly set the notebook up:\n", "1. Warning: This notebook was not authored by Google. Click on 'Run anyway'.\n", "1. When the installation commands are done, there might be \"Restart runtime\" button at the end of the output. Please, click it.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installation of dependencies" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: brainles_preprocessing in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (0.0.24)\n", "Requirement already satisfied: auxiliary in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (0.0.40)\n", "Requirement already satisfied: BrainLes-HD-BET>=0.0.5 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from brainles_preprocessing) (0.0.5)\n", "Requirement already satisfied: nibabel<4.0.0,>=3.2.1 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from brainles_preprocessing) (3.2.2)\n", "Requirement already satisfied: numpy<2.0.0,>=1.23.0 in /home/florian/.local/lib/python3.10/site-packages (from brainles_preprocessing) (1.26.2)\n", "Requirement already satisfied: path<17.0.0,>=16.2.0 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from brainles_preprocessing) (16.9.0)\n", "Requirement already satisfied: pathlib<2.0.0,>=1.0.1 in /home/florian/.local/lib/python3.10/site-packages (from brainles_preprocessing) (1.0.1)\n", "Requirement already satisfied: rich<14.0.0,>=13.6.0 in /home/florian/.local/lib/python3.10/site-packages (from brainles_preprocessing) (13.7.0)\n", "Requirement already satisfied: tqdm<5.0.0,>=4.64.1 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from brainles_preprocessing) (4.66.1)\n", "Requirement already satisfied: ttictoc<0.6.0,>=0.5.6 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from brainles_preprocessing) (0.5.6)\n", "Requirement already satisfied: pillow>=10.0.0 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from auxiliary) (10.2.0)\n", "Requirement already satisfied: tifffile>=2023.8.25 in /home/florian/.local/lib/python3.10/site-packages (from auxiliary) (2023.12.9)\n", "Requirement already satisfied: torch>=0.4.1 in /home/florian/.local/lib/python3.10/site-packages (from BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.1.2)\n", "Requirement already satisfied: scikit-image>=0.21.0 in /home/florian/.local/lib/python3.10/site-packages (from BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (0.22.0)\n", "Requirement already satisfied: SimpleITK>=2.2.1 in /home/florian/.local/lib/python3.10/site-packages (from BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.3.1)\n", "Requirement already satisfied: packaging>=14.3 in /home/florian/.local/lib/python3.10/site-packages (from nibabel<4.0.0,>=3.2.1->brainles_preprocessing) (23.2)\n", "Requirement already satisfied: setuptools in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from nibabel<4.0.0,>=3.2.1->brainles_preprocessing) (68.2.2)\n", "Requirement already satisfied: markdown-it-py>=2.2.0 in /home/florian/.local/lib/python3.10/site-packages (from rich<14.0.0,>=13.6.0->brainles_preprocessing) (3.0.0)\n", "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /home/florian/.local/lib/python3.10/site-packages (from rich<14.0.0,>=13.6.0->brainles_preprocessing) (2.17.2)\n", "Requirement already satisfied: mdurl~=0.1 in /home/florian/.local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich<14.0.0,>=13.6.0->brainles_preprocessing) (0.1.2)\n", "Requirement already satisfied: scipy>=1.8 in /home/florian/.local/lib/python3.10/site-packages (from scikit-image>=0.21.0->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (1.11.4)\n", "Requirement already satisfied: networkx>=2.8 in /home/florian/.local/lib/python3.10/site-packages (from scikit-image>=0.21.0->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (3.2.1)\n", "Requirement already satisfied: imageio>=2.27 in /home/florian/.local/lib/python3.10/site-packages (from scikit-image>=0.21.0->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.33.1)\n", "Requirement already satisfied: lazy_loader>=0.3 in /home/florian/.local/lib/python3.10/site-packages (from scikit-image>=0.21.0->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (0.3)\n", "Requirement already satisfied: filelock in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (3.13.1)\n", "Requirement already satisfied: typing-extensions in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (4.8.0)\n", "Requirement already satisfied: sympy in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (1.12)\n", "Requirement already satisfied: jinja2 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (3.1.2)\n", "Requirement already satisfied: fsspec in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2023.10.0)\n", "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.105)\n", "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.105)\n", "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.105)\n", "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (8.9.2.26)\n", "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.3.1)\n", "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (11.0.2.54)\n", "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (10.3.2.106)\n", "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (11.4.5.107)\n", "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.0.106)\n", "Requirement already satisfied: nvidia-nccl-cu12==2.18.1 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.18.1)\n", "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.1.105)\n", "Requirement already satisfied: triton==2.1.0 in /home/florian/.local/lib/python3.10/site-packages (from torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.1.0)\n", "Requirement already satisfied: nvidia-nvjitlink-cu12 in /home/florian/.local/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (12.3.52)\n", "Requirement already satisfied: MarkupSafe>=2.0 in /home/florian/.local/lib/python3.10/site-packages (from jinja2->torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (2.1.3)\n", "Requirement already satisfied: mpmath>=0.19 in /home/florian/.local/lib/python3.10/site-packages (from sympy->torch>=0.4.1->BrainLes-HD-BET>=0.0.5->brainles_preprocessing) (1.3.0)\n", "Note: you may need to restart the kernel to use updated packages.\n", "Requirement already satisfied: matplotlib in /home/florian/.local/lib/python3.10/site-packages (3.3.1)\n", "Requirement already satisfied: certifi>=2020.06.20 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from matplotlib) (2024.2.2)\n", "Requirement already satisfied: cycler>=0.10 in /home/florian/.local/lib/python3.10/site-packages (from matplotlib) (0.12.1)\n", "Requirement already satisfied: kiwisolver>=1.0.1 in /home/florian/.local/lib/python3.10/site-packages (from matplotlib) (1.4.5)\n", "Requirement already satisfied: numpy>=1.15 in /home/florian/.local/lib/python3.10/site-packages (from matplotlib) (1.26.2)\n", "Requirement already satisfied: pillow>=6.2.0 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from matplotlib) (10.2.0)\n", "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from matplotlib) (3.1.1)\n", "Requirement already satisfied: python-dateutil>=2.1 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from matplotlib) (2.8.2)\n", "Requirement already satisfied: six>=1.5 in /home/florian/miniconda3/envs/aurora_tutorial/lib/python3.10/site-packages (from python-dateutil>=2.1->matplotlib) (1.16.0)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "%pip install brainles_preprocessing auxiliary\n", "%pip install matplotlib\n", "\n", "%load_ext autoreload\n", "%autoreload 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By running the next cell you are going to create a folder in your Google Drive. All the files for this tutorial will be uploaded to this folder. After the first execution you might receive some warning and notification, please follow these instructions:\n", "1. Permit this notebook to access your Google Drive files? Click on 'Yes', and select your account.\n", "Google Drive for desktop wants to access your Google Account. Click on 'Allow'.\n", "1. At this point, a folder has been created and you can navigate it through the lefthand panel in Colab, you might also have received an email that informs you about the access on your Google Drive" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# Create a folder in your Google Drive\n", "# from google.colab import drive\n", "# drive.mount('/content/drive')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Don't run this cell if you already cloned the repo\n", "# !git clone https://github.com/BrainLesion/tutorials.git" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# make files from the repo available in colab\n", "import sys\n", "\n", "COLAB_BASE_PATH = \"/content/tutorials/BraTS-Toolkit/\"\n", "sys.path.insert(0, COLAB_BASE_PATH)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Raw Input data\n", "TODO describe raw input data. Two exams from TCIA/TCGA with T1, T1c, T2, T2-FLAIR with skull etc.\n", "TODO visualize it" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preprocessing\n", "BraTS challenge algorithms expect co-registered, skullstripped files in SRI-24 space, to achieve this preprocessing is required.\n", "Instead of using the vanilla preprocessing pipeline from BraTS Toolkit, we recommend using the new [BrainLes preprocessing package](https://github.com/BrainLesion/preprocessing/tree/main/brainles_preprocessing).\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, we define a function that procoesses an exam." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from auxiliary.normalization.percentile_normalizer import PercentileNormalizer\n", "from auxiliary.turbopath import turbopath\n", "from tqdm import tqdm\n", "\n", "from brainles_preprocessing.brain_extraction import HDBetExtractor\n", "from brainles_preprocessing.modality import Modality\n", "from brainles_preprocessing.preprocessor import Preprocessor\n", "from brainles_preprocessing.registration import NiftyRegRegistrator\n", "\n", "\n", "def preprocess_exam_in_brats_style(inputDir: str) -> None:\n", " \"\"\"\n", " Perform BRATS (Brain Tumor Segmentation) style preprocessing on MRI exam data.\n", "\n", " Args:\n", " inputDir (str): Path to the directory containing raw MRI files for an exam.\n", "\n", " Raises:\n", " Exception: If any error occurs during the preprocessing.\n", "\n", " Example:\n", " brat_style_preprocess_exam(\"/path/to/exam_directory\")\n", "\n", " This function preprocesses MRI exam data following the BRATS style, which includes the following steps:\n", " 1. Normalization using a percentile normalizer.\n", " 2. Registration and correction using NiftyReg.\n", " 3. Brain extraction using HDBet.\n", "\n", " The processed data is saved in a structured directory within the input directory.\n", "\n", " Args:\n", " inputDir (str): Path to the directory containing raw MRI files for an exam.\n", "\n", " Returns:\n", " None\n", " \"\"\"\n", " inputDir = turbopath(inputDir)\n", " print(\"*** start ***\")\n", " brainles_dir = turbopath(inputDir) + \"/\" + inputDir.name + \"_brainles\"\n", " norm_bet_dir = brainles_dir / \"normalized_bet\"\n", "\n", " t1_file = inputDir.files(\"*t1.nii.gz\")\n", " t1c_file = inputDir.files(\"*t1c.nii.gz\")\n", " t2_file = inputDir.files(\"*t2.nii.gz\")\n", " flair_file = inputDir.files(\"*fla.nii.gz\")\n", "\n", " # we check that we have only one file of each type\n", " if len(t1_file) == len(t1c_file) == len(t2_file) == len(flair_file) == 1:\n", " t1File = t1_file[0]\n", " t1cFile = t1c_file[0]\n", " t2File = t2_file[0]\n", " flaFile = flair_file[0]\n", "\n", " # normalizer\n", " percentile_normalizer = PercentileNormalizer(\n", " lower_percentile=0.1,\n", " upper_percentile=99.9,\n", " lower_limit=0,\n", " upper_limit=1,\n", " )\n", " # define modalities\n", " center = Modality(\n", " modality_name=\"t1c\",\n", " input_path=t1cFile,\n", " normalized_bet_output_path=norm_bet_dir / inputDir.name\n", " + \"_t1c_bet_normalized.nii.gz\",\n", " atlas_correction=True,\n", " normalizer=percentile_normalizer,\n", " )\n", " moving_modalities = [\n", " Modality(\n", " modality_name=\"t1\",\n", " input_path=t1File,\n", " normalized_bet_output_path=norm_bet_dir / inputDir.name\n", " + \"_t1_bet_normalized.nii.gz\",\n", " atlas_correction=True,\n", " normalizer=percentile_normalizer,\n", " ),\n", " Modality(\n", " modality_name=\"t2\",\n", " input_path=t2File,\n", " normalized_bet_output_path=norm_bet_dir / inputDir.name\n", " + \"_t2_bet_normalized.nii.gz\",\n", " atlas_correction=True,\n", " normalizer=percentile_normalizer,\n", " ),\n", " Modality(\n", " modality_name=\"flair\",\n", " input_path=flaFile,\n", " normalized_bet_output_path=norm_bet_dir / inputDir.name\n", " + \"_fla_bet_normalized.nii.gz\",\n", " atlas_correction=True,\n", " normalizer=percentile_normalizer,\n", " ),\n", " ]\n", " preprocessor = Preprocessor(\n", " center_modality=center,\n", " moving_modalities=moving_modalities,\n", " registrator=NiftyRegRegistrator(),\n", " brain_extractor=HDBetExtractor(),\n", " # optional: we provide a temporary directory as a sandbox for the preprocessin\n", " temp_folder=\"temporary_directory\",\n", " limit_cuda_visible_devices=\"0\",\n", " )\n", "\n", " preprocessor.run(\n", " save_dir_coregistration=brainles_dir + \"/co-registration\",\n", " save_dir_atlas_registration=brainles_dir + \"/atlas-registration\",\n", " save_dir_atlas_correction=brainles_dir + \"/atlas-correction\",\n", " save_dir_brain_extraction=brainles_dir + \"/brain-extraction\",\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "now we loop through the exams to preprocess the data:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/2 [00:00