-
Notifications
You must be signed in to change notification settings - Fork 20
[FEAT]: BAMF nnUNet Breast MR Model #82
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
Open
rahul99
wants to merge
27
commits into
MHubAI:main
Choose a base branch
from
bamf-health:bamf_nnunet_mr_breast
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 19 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
cf81190
[FEAT]: breast, fgt, and tumor seg module
b972102
added meta data and refactored post processor
e4ead8b
added nnunet v2 runner class
c5fe136
updated metadata
07adc87
updated metadata
f48bf52
update nnunet version and refactor env vars
6dc7a28
fix rois
b47061f
minor description update
204238f
custom SegDB keys
10f587d
custom SegDB keys
c7f2007
custom SegDB module
5d7e268
move custom segDB triplets to config
312ae55
update documentation
5997cda
minor refactoring for PR-82
24d3b6b
minor refactoring for PR-82
5217425
[PR-82] update output classes in meta
a3a3474
[PR-82] indicate nnUNetv2 in debug output
e23f9c4
BREAST+FGT label correction
3eb991e
Switch FGT to SCT scheme designator
66f8ce8
rollback custom SegDB triplet: keys now available in SegDB
c04ab11
refactor roi key name
833aed7
refactor model display name
f44935d
omit context for tissue roi
745ed82
Add mhub deployment instance
4ae4c9a
Add mhub deployment instance v2
9bdce2f
update down url
d7e5d04
add publication in meta.json
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
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,65 @@ | ||
| general: | ||
| data_base_dir: /app/data | ||
| version: 1.0 | ||
| description: Default configuration for Bamf NNUnet Breast and tumor segmentation on MR scans (dicom to dicom) | ||
|
|
||
| segdb: | ||
| triplets: | ||
| T_BREAST_FGT_STRUCTURE: | ||
| code: 1342375003 | ||
| meaning: Structure of fibroglandular tissue of breast | ||
| scheme_designator: SCT | ||
| T_BREAST_CARCINOMA_MASS: | ||
| code: 4147007 | ||
| meaning: Mass | ||
| scheme_designator: SCT | ||
| segments: | ||
| FGT: | ||
| name: FGT | ||
| category: C_RADIOLOGIC_FINDING | ||
| type: T_BREAST_FGT_STRUCTURE | ||
| color: [128, 174, 128] | ||
| BREAST_CARCINOMA: | ||
| name: Breast_Carcinoma | ||
| category: C_MORPHOLOGICALLY_ABNORMAL_STRUCTURE | ||
| type: T_BREAST_CARCINOMA_MASS | ||
| modifier: M_RIGHT_AND_LEFT | ||
| color: [144, 238, 144] | ||
|
|
||
| execute: | ||
| - DicomImporter | ||
| - NiftiConverter | ||
| - module: NNUnetRunnerV2 | ||
| nnunet_dataset: Dataset009_Breast | ||
| roi: BREAST,BREAST+FGT | ||
| - module: NNUnetRunnerV2 | ||
| nnunet_dataset: Dataset011_Breast | ||
| roi: BREAST+BREAST_CARCINOMA | ||
| - BreastPostProcessor | ||
| - DsegConverter | ||
| - DataOrganizer | ||
|
|
||
| modules: | ||
| DicomImporter: | ||
| source_dir: input_data | ||
| import_dir: sorted_data | ||
| sort_data: true | ||
| meta: | ||
| mod: '%Modality' | ||
|
|
||
| NNUnetRunnerV2: | ||
| in_data: nifti:mod=mr | ||
|
|
||
| BreastPostProcessor: | ||
| in_breast_data: nifti:mod=seg:nnunet_task=Dataset009_Breast | ||
| in_tumor_data: nifti:mod=seg:nnunet_task=Dataset011_Breast | ||
|
|
||
| DsegConverter: | ||
| model_name: Bamf NNUnet MR Breast and tumor | ||
| target_dicom: dicom:mod=mr | ||
| source_segs: nifti:mod=seg:processor=bamf | ||
| skip_empty_slices: True | ||
|
|
||
| DataOrganizer: | ||
| targets: | ||
| - dicomseg-->[i:sid]/bamf_nnunet_mr_breast.seg.dcm | ||
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,39 @@ | ||
| FROM mhubai/base:latest | ||
|
|
||
| # FIXME: set this environment variable as a shortcut to avoid nnunet crashing the build | ||
| # by pulling sklearn instead of scikit-learn | ||
| # N.B. this is a known issue: | ||
| # https://github.com/MIC-DKFZ/nnUNet/issues/1281 | ||
| # https://github.com/MIC-DKFZ/nnUNet/pull/1209 | ||
| ENV SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL=True | ||
|
|
||
| # Install nnunet and platipy | ||
| RUN pip3 install --no-cache-dir nnunetv2 | ||
|
|
||
| # Clone the main branch of MHubAI/models | ||
| ARG MHUB_MODELS_REPO | ||
| RUN buildutils/import_mhub_model.sh bamf_nnunet_mr_breast ${MHUB_MODELS_REPO} | ||
|
|
||
| # Pull nnUNet model weights into the container for Dataset009_Breast | ||
| ENV WEIGHTS_DIR=/root/.nnunet/nnUNet_models/nnUNet/ | ||
| RUN mkdir -p $WEIGHTS_DIR | ||
| ENV WEIGHTS_FN=Dataset009_Breast.zip | ||
| ENV WEIGHTS_URL=https://zenodo.org/record/11998679/files/$WEIGHTS_FN | ||
| RUN wget --directory-prefix ${WEIGHTS_DIR} ${WEIGHTS_URL} | ||
| RUN unzip ${WEIGHTS_DIR}${WEIGHTS_FN} -d ${WEIGHTS_DIR} | ||
| RUN rm ${WEIGHTS_DIR}${WEIGHTS_FN} | ||
|
|
||
| # Pull nnUNet model weights into the container for Task775_CT_NSCLC_RG | ||
| ENV TASK_NAME_NSCLC_RG=Task775_CT_NSCLC_RG | ||
| ENV WEIGHTS_FN=Dataset011_Breast.zip | ||
| ENV WEIGHTS_URL=https://zenodo.org/record/11998632/files/$WEIGHTS_FN | ||
| RUN wget --directory-prefix ${WEIGHTS_DIR} ${WEIGHTS_URL} | ||
| RUN unzip ${WEIGHTS_DIR}${WEIGHTS_FN} -d ${WEIGHTS_DIR} | ||
| RUN rm ${WEIGHTS_DIR}${WEIGHTS_FN} | ||
|
|
||
| # specify nnunet specific environment variables | ||
| ENV WEIGHTS_FOLDER=$WEIGHTS_DIR | ||
|
|
||
| # Default run script | ||
| ENTRYPOINT ["mhub.run"] | ||
| CMD ["--config", "/app/models/bamf_nnunet_mr_breast/config/default.yml"] |
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,134 @@ | ||
| { | ||
| "id": "", | ||
| "name": "bamf_nnunet_mr_breast", | ||
| "title": "BAMF MR Breast Segmentation (nnU-Net)", | ||
| "summary": { | ||
| "description": "An nnU-Net based model to segment breast from MR scans", | ||
| "inputs": [ | ||
| { | ||
| "label": "Input Image", | ||
| "description": "The MR scan of a patient.", | ||
| "format": "DICOM", | ||
| "modality": "MR", | ||
| "bodypartexamined": "BREAST", | ||
| "slicethickness": "2.5mm", | ||
| "non-contrast": true, | ||
| "contrast": false | ||
| } | ||
| ], | ||
| "outputs": [ | ||
| { | ||
| "label": "Segmentation", | ||
| "type": "Segmentation", | ||
| "description": "Segmentation for breast, fgt, and breast carcinoma", | ||
| "classes": [ | ||
| "BREAST", | ||
| "FGT", | ||
| "BREAST+BREAST_CARCINOMA" | ||
| ] | ||
| } | ||
| ], | ||
| "model": { | ||
| "architecture": "U-net v2", | ||
| "training": "supervised", | ||
| "cmpapproach": "3D" | ||
| }, | ||
| "data": { | ||
| "training": { | ||
| "vol_samples": 587 | ||
| }, | ||
| "evaluation": { | ||
| "vol_samples": 92 | ||
| }, | ||
| "public": true, | ||
| "external": true | ||
| } | ||
| }, | ||
| "details": { | ||
| "name": "AIMI Breast MR", | ||
| "version": "1.0.0", | ||
| "devteam": "BAMF Health", | ||
| "authors": [ | ||
| "Murugesan, Gowtham Krishnan", | ||
| "Soni, Rahul", | ||
| "McCrumb, Diana", | ||
| "Van Oss, Jeff" | ||
| ], | ||
| "type": "nnU-Net v2 (U-Net structure, optimized by data-driven heuristics)", | ||
| "date": { | ||
| "code": "07.06.2024", | ||
| "weights": "06.06.2024", | ||
| "pub": "07.06.2024" | ||
| }, | ||
| "cite": "Murugesan, Gowtham Krishnan, Diana McCrumb, Mariam Aboian, Tej Verma, Rahul Soni, Fatima Memon, and Jeff Van Oss. The AIMI Initiative: AI-Generated Annotations for Imaging Data Commons Collections. arXiv preprint arXiv:2310.14897 (2023).", | ||
| "license": { | ||
| "code": "MIT", | ||
| "weights": "CC BY-NC 4.0" | ||
| }, | ||
| "publications": [ | ||
| { | ||
| "title": "", | ||
| "uri": "" | ||
| } | ||
| ], | ||
| "github": "https://github.com/bamf-health/aimi-breast-mr" | ||
| }, | ||
| "info": { | ||
| "use": { | ||
| "title": "Intended Use", | ||
| "text": "This model is intended to perform breast, fgt, and breast tumor segmentation in MR scans. The model has been trained and tested on scans aquired during clinical care of patients, so it might not be suited for a healthy population. The generalization capabilities of the model on a range of ages, genders, and ethnicities are unknown." | ||
| }, | ||
| "analyses": { | ||
| "title": "Quantitative Analyses", | ||
| "text": "The model's performance was assessed using the Dice Coefficient with tolerance 7mm, as specified in the Duke-Breast-Cancer-MRI. The model was used to segment cases from the IDC collection ACRIN-Contralateral-Breast-MR [1]. All validation cases (=92) were reviewed and corrected by board-certified radiologists. The analysis is published here [2]", | ||
| "tables": [ | ||
| { | ||
| "label": "Label-wise metrics (mean) between AI derived and manually corrected MR Breast annotations", | ||
| "entries": { | ||
| "Dice: BREAST": "0.98", | ||
| "Dice: FGT": "0.80", | ||
| "Dice: BREAST+TUMOR": "0.56" | ||
| } | ||
| } | ||
| ], | ||
| "references": [ | ||
| { | ||
| "label": "ACRIN-Contralateral-Breast-MR", | ||
| "uri": "https://www.cancerimagingarchive.net/collection/acrin-contralateral-breast-mr" | ||
| }, | ||
| { | ||
| "label": "The AIMI Initiative: AI-Generated Annotations for Imaging Data Commons Collections", | ||
| "uri": "https://arxiv.org/abs/2310.14897" | ||
| } | ||
| ] | ||
| }, | ||
| "evaluation": { | ||
| "title": "Evaluation Data", | ||
| "text": "The model was used to segment 92 cases from the ACRIN-Contralateral-Breast-MR [1]. All of those cases were reviewed and corrected by a board-certified radiologist. The model predictions, and radiologist corrections would be published on zenodo soon", | ||
| "references": [ | ||
| { | ||
| "label": "ACRIN-Contralateral-Breast-MR", | ||
| "uri": "https://www.cancerimagingarchive.net/collection/acrin-contralateral-breast-mr" | ||
| }, | ||
| { | ||
| "label": "Image segmentations produced by the AIMI Annotations initiative", | ||
| "uri": "https://zenodo.org/records/13244892" | ||
| } | ||
| ] | ||
| }, | ||
| "training": { | ||
| "title": "Training Data", | ||
| "text": "The training dataset consists of 587 breast, fgt, and breast tumor annotations. The breast and fgt annotations where taken from the Duke-Breast-Cancer-MRI dataset [1] (N=98) and breast tumor annotations where taken from the ACRIN-Contralateral-Breast-MR [2] (N=489).", | ||
| "references": [ | ||
| { | ||
| "label": "Duke-Breast-Cancer-MRI Dataset", | ||
| "uri": "https://wiki.cancerimagingarchive.net/pages/viewpage.action?pageId=70226903" | ||
| }, | ||
| { | ||
| "label": "ACRIN-Contralateral-Breast-MR", | ||
| "uri": "https://www.cancerimagingarchive.net/collection/acrin-contralateral-breast-mr" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } |
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,99 @@ | ||
| """ | ||
| ------------------------------------------------- | ||
| MHub - Run Module for ensembling nnUNet inference. | ||
| ------------------------------------------------- | ||
| ------------------------------------------------- | ||
| Author: Rahul Soni | ||
| Email: [email protected] | ||
| ------------------------------------------------- | ||
| """ | ||
|
|
||
| from mhubio.core import IO | ||
| from mhubio.core import Module, Instance, InstanceData | ||
| import os, shutil | ||
| import SimpleITK as sitk | ||
| import numpy as np | ||
| from skimage import measure, filters | ||
| from typing import Union | ||
| from pathlib import Path | ||
| import yaml | ||
|
|
||
|
|
||
|
|
||
| class BreastPostProcessor(Module): | ||
|
|
||
| def get_mask(self, ip_path): | ||
| # get segmentation mask | ||
| seg_data = sitk.GetArrayFromImage(sitk.ReadImage(ip_path)) | ||
| seg_data[seg_data > 0] = 1 | ||
| return seg_data | ||
|
|
||
| def n_connected(self, img_data: sitk.Image) -> sitk.Image: | ||
| """ | ||
| Analyse connected components and drop smaller blobs | ||
| """ | ||
| img_data_mask = np.zeros(img_data.shape) | ||
| img_data_mask[img_data >= 1] = 1 | ||
| img_filtered = np.zeros(img_data_mask.shape) | ||
| blobs_labels = measure.label(img_data_mask, background=0) | ||
| lbl, counts = np.unique(blobs_labels, return_counts=True) | ||
| lbl_dict = {} | ||
| for i, j in zip(lbl, counts): | ||
| lbl_dict[i] = j | ||
| sorted_dict = dict(sorted(lbl_dict.items(), key=lambda x: x[1], reverse=True)) | ||
| count = 0 | ||
| for key, value in sorted_dict.items(): | ||
| if count >= 1 and count <= 2: | ||
| print(key, value) | ||
| img_filtered[blobs_labels == key] = 1 | ||
| count += 1 | ||
|
|
||
| img_data[img_filtered != 1] = 0 | ||
| return img_data | ||
|
|
||
| def merge_segmentations(self, breast_and_fgt_seg:sitk.Image, tumor_seg:sitk.Image, mr_path:Union[str,Path]) -> sitk.Image: | ||
| """ | ||
| Merge labels of breast, fgt, and breast tumor | ||
| breast_and_fgt_seg: contains label=1 for breast, and label=2 for fgt | ||
| tumor_seg: assign label=3 for breast tumor in the merge image | ||
| returns: sitk image containing labels: [0,1,2,3] | ||
| """ | ||
| tumor_seg[breast_and_fgt_seg == 0] = 0 # only focusing on predictions within the breast and fgt region | ||
| breast_and_fgt_seg[tumor_seg == 1] = 3 | ||
| ref = sitk.ReadImage(mr_path) | ||
| seg_img = sitk.GetImageFromArray(breast_and_fgt_seg) | ||
| seg_img.CopyInformation(ref) | ||
| return seg_img | ||
|
|
||
| @IO.Instance() | ||
| @IO.Input('in_breast_and_fgt_data', 'nifti:mod=seg:nnunet_dataset=Dataset009_Breast', the='input data from breast and fgt segmentation') | ||
| @IO.Input('in_breast_tumor_data', 'nifti:mod=seg:nnunet_dataset=Dataset011_Breast', the='input data from breast tumor segmentation') | ||
| @IO.Input('in_mr_data', 'nifti:mod=mr', the='input mr data') | ||
| @IO.Output('out_data', 'bamf_processed.nii.gz', 'nifti:mod=seg:processor=bamf:roi=BREAST,FGT,BREAST+BREAST_CARCINOMA', | ||
| the="get breast, fgt, and breast-tumor segmentation masks") | ||
| def task(self, instance: Instance, in_breast_and_fgt_data: InstanceData, in_breast_tumor_data: InstanceData, | ||
| in_mr_data: InstanceData, out_data: InstanceData): | ||
|
|
||
| print('input breast and fgt segmentation: ' + in_breast_and_fgt_data.abspath) | ||
| print('input breast tumor segmentation: ' + in_breast_tumor_data.abspath) | ||
| print('output path: ' + out_data.abspath) | ||
|
|
||
| # Breast and FGT segmentation | ||
| breast_and_fgt_seg = self.get_mask(in_breast_and_fgt_data.abspath) | ||
| breast_and_fgt_seg = self.n_connected(breast_and_fgt_seg) | ||
|
|
||
| # Breast tumor segmentation | ||
| tumor_seg = self.get_mask(in_breast_tumor_data.abspath) | ||
| tumor_seg = self.n_connected(tumor_seg) | ||
|
|
||
| # Merged segmentation masks | ||
| output_seg = self.merge_segmentations( | ||
| breast_and_fgt_seg = np.copy(breast_and_fgt_seg), | ||
| tumor_seg = np.copy(tumor_seg), | ||
| mr_path = in_mr_data.abspath | ||
| ) | ||
| sitk.WriteImage( | ||
| output_seg, | ||
| out_data.abspath, | ||
| ) | ||
|
|
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.
Uh oh!
There was an error while loading. Please reload this page.