-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add clinical DICOM preprocessing files, workflow PDF, and example notebooks #8658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Hitendrasinhdata7
wants to merge
5
commits into
Project-MONAI:dev
from
Hitendrasinhdata7:feature/clinical-dicom-preprocessing
Closed
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5394658
Final commit: add clinical DICOM preprocessing files, workflow PDF, a…
Hitendrasinhdata7 aeabbbd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 24665aa
Add clinical DICOM preprocessing Python module, test module, PDF; rem…
Hitendrasinhdata7 798f8af
Remove old notebook files after converting to .py modules
Hitendrasinhdata7 08919d0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| { | ||
| "cells": [ | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "30e4219e", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "\"\"\"\n", | ||
| "Unit tests for clinical_preprocessing.py\n", | ||
| "Author: Hitendrasinh Rathod\n", | ||
| "\"\"\"\n", | ||
| "\n", | ||
| "import numpy as np\n", | ||
| "import pytest\n", | ||
| "from monai.transforms import CTWindowingTransform, MRINormalizationTransform\n", | ||
| "\n", | ||
| "def test_ct_windowing():\n", | ||
| " \"\"\"\n", | ||
| " Test the CTWindowingTransform to ensure output is scaled between 0 and 1\n", | ||
| " and the shape is preserved.\n", | ||
| " \"\"\"\n", | ||
| " # Mock CT image with Hounsfield Units\n", | ||
| " sample_ct = np.random.randint(-1024, 2048, size=(64, 64, 64), dtype=np.int16)\n", | ||
| "\n", | ||
| " transform = CTWindowingTransform()\n", | ||
| " output = transform(sample_ct)\n", | ||
| "\n", | ||
| " # Output must be in [0,1]\n", | ||
| " assert output.min() >= 0.0\n", | ||
| " assert output.max() <= 1.0\n", | ||
| " # Shape should be preserved\n", | ||
| " assert output.shape == sample_ct.shape\n", | ||
| "\n", | ||
| "def test_mri_normalization():\n", | ||
| " \"\"\"\n", | ||
| " Test the MRINormalizationTransform to ensure normalization works\n", | ||
| " and shape is preserved.\n", | ||
| " \"\"\"\n", | ||
| " # Mock MRI image with random float values\n", | ||
| " sample_mri = np.random.rand(64, 64, 64)\n", | ||
| "\n", | ||
| " transform = MRINormalizationTransform()\n", | ||
| " output = transform(sample_mri)\n", | ||
| "\n", | ||
| " # Shape should be preserved\n", | ||
| " assert output.shape == sample_mri.shape\n", | ||
| " # Values should be roughly normalized (mean near 0, std near 1)\n", | ||
| " mean_val = np.mean(output)\n", | ||
| " std_val = np.std(output)\n", | ||
| " assert np.isclose(mean_val, 0, atol=0.1) or np.isclose(std_val, 1, atol=0.1)\n" | ||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "language_info": { | ||
| "name": "python" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 5 | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| { | ||
| "cells": [ | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "WK53GWYq4eo1", | ||
| "metadata": { | ||
| "id": "WK53GWYq4eo1" | ||
| }, | ||
| "source": [ | ||
| "# Clinical DICOM CT and MRI Preprocessing with MONAI\n", | ||
| "This notebook demonstrates inference-time preprocessing pipelines for CT and MRI DICOM series using MONAI, suitable for PACS/RIS workflows in hospital radiology environments.\n", | ||
| "**Note:** This notebook focuses on preprocessing only and excludes training or patient-identifiable data." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": 1, | ||
| "id": "LTKh48zD4eo4", | ||
| "metadata": { | ||
| "colab": { | ||
| "base_uri": "https://localhost:8080/" | ||
| }, | ||
| "id": "LTKh48zD4eo4", | ||
| "outputId": "dcdc9430-1d52-4272-9079-8faba741099e" | ||
| }, | ||
| "outputs": [ | ||
| { | ||
| "name": "stdout", | ||
| "output_type": "stream", | ||
| "text": [ | ||
| "\u001b[?25l \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m0.0/2.7 MB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K \u001b[91m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m\u001b[90m\u257a\u001b[0m\u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m1.9/2.7 MB\u001b[0m \u001b[31m53.8 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K \u001b[91m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m\u001b[91m\u2578\u001b[0m \u001b[32m2.7/2.7 MB\u001b[0m \u001b[31m43.7 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m2.7/2.7 MB\u001b[0m \u001b[31m21.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | ||
| "\u001b[?25h\u001b[?25l \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m0.0/2.4 MB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K \u001b[91m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m\u001b[91m\u2578\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m147.2 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m38.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | ||
| "\u001b[?25h" | ||
| ] | ||
| } | ||
| ], | ||
| "source": [ | ||
| "# Install required packages\n", | ||
| "!pip install monai pydicom nibabel --quiet" | ||
| ] | ||
| }, | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| "cell_type": "markdown", | ||
| "id": "gyAtaTBP4eo7", | ||
| "metadata": { | ||
| "id": "gyAtaTBP4eo7" | ||
| }, | ||
| "source": [ | ||
| "## Import Libraries" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": 5, | ||
| "id": "k2DfCDZM4eo8", | ||
| "metadata": { | ||
| "id": "k2DfCDZM4eo8" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "from monai.transforms import (\n", | ||
| " LoadImage,\n", | ||
| " EnsureChannelFirst,\n", | ||
| " ScaleIntensityRange,\n", | ||
| " NormalizeIntensity,\n", | ||
| " Compose\n", | ||
| ")\n", | ||
| "import numpy as np" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "HAxGJVgy4eo8", | ||
| "metadata": { | ||
| "id": "HAxGJVgy4eo8" | ||
| }, | ||
| "source": [ | ||
| "## Define Preprocessing Pipelines" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": 6, | ||
| "id": "cP-zDmqu4eo8", | ||
| "metadata": { | ||
| "id": "cP-zDmqu4eo8" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "def get_ct_preprocessing_pipeline():\n", | ||
| " return Compose([\n", | ||
| " LoadImage(image_only=True),\n", | ||
| " EnsureChannelFirst(),\n", | ||
| " ScaleIntensityRange(a_min=-1000, a_max=400, b_min=0.0, b_max=1.0, clip=True)\n", | ||
| " ])\n", | ||
| "\n", | ||
| "def get_mri_preprocessing_pipeline():\n", | ||
| " return Compose([\n", | ||
| " LoadImage(image_only=True),\n", | ||
| " EnsureChannelFirst(),\n", | ||
| " NormalizeIntensity(nonzero=True)\n", | ||
| " ])" | ||
| ] | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "OuRHidt_4eo9", | ||
| "metadata": { | ||
| "id": "OuRHidt_4eo9" | ||
| }, | ||
| "source": [ | ||
| "## Preprocessing Function" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": 7, | ||
| "id": "BcGeKvkc4eo-", | ||
| "metadata": { | ||
| "id": "BcGeKvkc4eo-" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "def preprocess_dicom_series(dicom_path, modality):\n", | ||
| " modality = modality.upper()\n", | ||
| " if modality == 'CT':\n", | ||
| " transform = get_ct_preprocessing_pipeline()\n", | ||
| " elif modality == 'MRI':\n", | ||
| " transform = get_mri_preprocessing_pipeline()\n", | ||
| " else:\n", | ||
| " raise ValueError(\"Unsupported modality. Use 'CT' or 'MRI'.\")\n", | ||
| " image = transform(dicom_path)\n", | ||
| " return image" | ||
| ] | ||
|
||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "3bWBPrp44eo-", | ||
| "metadata": { | ||
| "id": "3bWBPrp44eo-" | ||
| }, | ||
| "source": [ | ||
| "## Example Usage" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "VlZZgpHg4eo_", | ||
| "metadata": { | ||
| "id": "VlZZgpHg4eo_" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "# Replace these paths with your own DICOM series paths\n", | ||
| "ct_dicom_path = '/path/to/ct/dicom/series'\n", | ||
| "mri_dicom_path = '/path/to/mri/dicom/series'\n", | ||
| "\n", | ||
| "ct_image = preprocess_dicom_series(ct_dicom_path, 'CT')\n", | ||
| "mri_image = preprocess_dicom_series(mri_dicom_path, 'MRI')\n", | ||
| "\n", | ||
| "print('CT image shape:', ct_image.shape)\n", | ||
| "print('MRI image shape:', mri_image.shape)" | ||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "colab": { | ||
| "provenance": [] | ||
| }, | ||
| "kernelspec": { | ||
| "display_name": "Python 3", | ||
| "language": "python", | ||
| "name": "python3" | ||
| }, | ||
| "language_info": { | ||
| "name": "python", | ||
| "version": "3.10" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 5 | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assertions may break depending on transform return type (numpy vs torch/MetaTensor) + RNG flakiness.
outputto a numpy array beforemin/max/mean/std.or.Also applies to: 36-52
🤖 Prompt for AI Agents