Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions models/deepcac2/config/default.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
general:
data_base_dir: /app/data
version: 1.0
description: custom DeepCAC2 starting from dicom and exporting AGS and RISK only for non-mapped cac segmentations

execute:
- DicomImporter
- NiftiConverter
- NNUnetRunner
- DeepCACRunner
- AGSCalculator
- ReportExporter
- module: ReportExporter
globalreport: true
meta:
scope: global
- DataOrganizer

modules:

DicomImporter:
meta:
mod: '%Modality'
pid: '%PatientID'

NNUnetRunner:
folds: all
nnunet_task: Task400_OPEN_HEART_1FOLD
nnunet_model: 3d_lowres
roi: HEART

ReportExporter:
meta:
mod: report
scope: instance
includes:
- attr: sid
label: SeriesInstanceUID
- attr: pid
label: PatientID
- data: ags
label: Predicted Agatston Score
value: value
- data: rc
label: Predicted Risk Group
value: value

DataOrganizer:
targets:
- nrrd:mod=seg:roi=CAC AND NOT any:variant=mapped-->[i:sid]/nrrd/cac.seg.nrrd
- nrrd:mod=seg:roi=CAC:variant=mapped-->[i:sid]/nrrd/mcac.seg.nrrd
- json:mod=report:scope=instance-->[i:sid]/DeepCAC.report.json
- json:mod=report:scope=global-->DeepCAC.report.json
65 changes: 65 additions & 0 deletions models/deepcac2/config/pid_nifti.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

general:
data_base_dir: /app/data
version: 1.0
description: DeepCAC2 starting from nifti file(s) named by PatientID and exporting AGS and RISK for mapped and non-mapped cac segmentations.

execute:
- FileStructureImporter
- NNUnetRunner
- DeepCACRunner
#- CACMapping
- AGSCalculator
- ReportExporter
- module: ReportExporter
globalreport: true
meta:
scope: global
- DataOrganizer

modules:

FileStructureImporter:
input_dir: 'input_data'
import_id: _instance
structures:
- re:(\d+).nii.gz::$pid@instance@nifti:mod=ct

NNUnetRunner:
folds: all
nnunet_task: Task400_OPEN_HEART_1FOLD
nnunet_model: 3d_lowres
roi: HEART

ReportExporter:
meta:
mod: report
scope: instance
includes:
- attr: pid
label: PatientID
- data: ags
label: Agatston Score Description
value: description
- data: ags
label: Predicted Agatston Score
value: value
- data: rc
label: Risk Group Description
value: description
- data: rc
label: Predicted Risk Group
value: value
# - data: mags
# label: Mapped Predicted Agatston Score
# value: value
# - data: mrc
# label: Mapped Predicted Risk Group
# value: value

DataOrganizer:
targets:
#- nrrd:mod=seg:roi=CAC AND NOT any:variant=mapped-->[i:pid]/cac.seg.nrrd
#- nrrd:mod=seg:roi=CAC:variant=mapped-->[i:pid]/mcac.seg.nrrd
#- json:mod=report:scope=instance-->[i:pid]/DeepCAC.report.json
- json:mod=report:scope=global-->DeepCAC.report.json
46 changes: 46 additions & 0 deletions models/deepcac2/dockerfiles/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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 dependencies
RUN pip3 install --no-cache-dir \
nnunet==1.7.1 \
torch==2.0.1 \
torchvision==0.15.2 \
torchio==0.19.1 \
&& pip3 install --no-cache-dir --force-reinstall \
"dicom2nifti<2.6" \
numpy==1.26.4 \
pydicom==2.4.4

# pull weights for platipy's nnU-Net so that the user doesn't need to every time a container is run
ENV WEIGHTS_DIR="/root/.platipy/nnUNet_models/nnUNet/"
ENV WEIGHTS_URL="https://zenodo.org/record/6585664/files/Task400_OPEN_HEART_3d_lowres.zip"
ENV WEIGHTS_FN="Task400_OPEN_HEART_3d_lowres.zip"

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

# Import the MHub model definition
ARG MHUB_MODELS_REPO
RUN buildutils/import_mhub_model.sh deepcac2 ${MHUB_MODELS_REPO}

# download the DeepCAC2 model weights
ENV DEEPCAC2_WEIGHTS_DIR="/app/models/deepcac2/src/weights/"
ENV DEEPCAC2_WEIGHTS_FN="vivid-haze-6_model.pt"
ENV DEEPCAC2_WEIGHTS_URL="https://www.dropbox.com/scl/fi/4rodcp9y2vula8loh1v6r/vivid-haze-6_model.pt?rlkey=7j3cyaltvdpthukchn5xbh01d&dl=1"
RUN mkdir -p ${DEEPCAC2_WEIGHTS_DIR} \
&& wget -o /dev/stdout -O ${DEEPCAC2_WEIGHTS_DIR}${DEEPCAC2_WEIGHTS_FN} ${DEEPCAC2_WEIGHTS_URL}

# Default run script
ENTRYPOINT ["mhub.run"]
CMD ["--workflow", "default"]
174 changes: 174 additions & 0 deletions models/deepcac2/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
{
"id": "7c7c7e7b-3c4d-4a84-9a45-5a6c2b46c1a1",
"name": "deepcac2",
"title": "DeepCAC2",
"summary": {
"description": "DeepCAC2 is a two-stage deep learning pipeline for coronary artery calcification assessment in chest CT. It first uses an nnU-Net-based cardiac segmentation model to localize the heart, then applies a patch-based 3D U-Net to segment coronary artery calcifications and derive Agatston calcium scores and risk categories.",
"inputs": [
{
"label": "Chest CT",
"description": "Non-contrast, low-dose chest CT scan in DICOM format.",
"format": "DICOM",
"modality": "CT",
"bodypartexamined": "CHEST",
"slicethickness": "1-5 mm",
"non-contrast": true,
"contrast": false
}
],
"outputs": [
{
"type": "Segmentation",
"classes": [
"heart",
"coronary artery calcification"
]
},
{
"type": "Prediction",
"valueType": "float",
"label": "Predicted Agatston Score",
"description": "Automated coronary artery calcium score derived from the predicted CAC segmentation."
},
{
"type": "Classification",
"classes": [
"very low",
"low",
"moderate",
"high"
]
}
],
"model": {
"architecture": "Two-stage pipeline with nnU-Net-based cardiac segmentation followed by patch-based 3D U-Net CAC segmentation.",
"training": "supervised",
"cmpapproach": "3D"
},
"data": {
"training": {
"vol_samples": 622
},
"evaluation": {
"vol_samples": 390
},
"public": true,
"external": true
}
},
"details": {
"name": "DeepCAC2",
"version": "1.0.0",
"devteam": "Artificial Intelligence in Medicine Program, Mass General Brigham / Harvard Medical School",
"type": "Segmentation and prediction",
"date": {
"weights": "2026-01-01",
"code": "2026-01-01",
"pub": "2026-03-25"
},
"cite": "Nürnberg L, Bernatz S, Foldyna B, Lu MT, Fedorov A, Aerts HJWL. Coronary artery calcification assessment in National Lung Screening Trial CT images (DeepCAC2).",
"license": {
"code": "MIT",
"weights": "MIT"
},
"publications": [
{
"title": "Coronary artery calcification assessment in National Lung Screening Trial CT images (DeepCAC2)",
"uri": "https://arxiv.org/"
}
],
"github": "https://github.com/MHubAI/models/tree/main/models/deepcac2",
"slicer": false
},
"info": {
"use": {
"title": "Intended use",
"text": "DeepCAC2 is designed for automated coronary artery calcification (CAC) segmentation and cardiovascular risk assessment from non-contrast chest CT scans, enabling opportunistic screening without dedicated cardiac CT protocols. The generated outputs and dataset can be explored via an interactive public dashboard [1] and are derived from the National Lung Screening Trial (NLST) cohort available through the Imaging Data Commons (IDC) [2].",
"references": [
{
"label": "DeepCAC2 interactive dashboard",
"uri": "https://lookerstudio.google.com/reporting/2c656fab-89ce-4ccd-a6a6-6c76ba7ecc51/page/P3qpF"
},
{
"label": "Imaging Data Commons (NLST collection)",
"uri": "https://imaging.datacommons.cancer.gov/"
}
]
},
"analyses": {
"title": "Analyses",
"text": "The pipeline produces volumetric segmentations of the heart and coronary artery calcifications, from which Agatston calcium scores (CACS) are computed and mapped to categorical risk groups (0, 1–100, 101–300, >300). These standardized outputs enable cohort stratification, longitudinal analyses, survival modeling, and reproducible imaging biomarker research at scale [1].",
"references": [
{
"label": "DeepCAC2 preprint",
"uri": "https://arxiv.org/abs/2601.10154"
}
],
"tables": [
{
"label": "CAC risk groups",
"entries": {
"0": "CACS = 0 (very low)",
"1": "CACS 1–100 (low)",
"2": "CACS 101–300 (moderate)",
"3": "CACS >300 (high)"
}
}
]
},
"evaluation": {
"title": "Evaluation",
"text": "DeepCAC2 was evaluated for both technical validity and clinical relevance. Technical validation compared automated CAC scores and risk categories against expert annotations on a subset of NLST scans, demonstrating high agreement. Clinical validation using survival analysis showed that model-derived CAC risk groups are strong independent predictors of all-cause mortality, with clear stratification across risk categories [1].",
"references": [
{
"label": "DeepCAC2 preprint",
"uri": "https://arxiv.org/abs/2601.10154"
}
],
"tables": [
{
"label": "Technical validation metrics",
"entries": {
"Evaluation dataset": "NLST subset",
"Sample size": "390 CT scans",
"Spearman correlation (CACS)": "0.879",
"Weighted Cohen's kappa (risk groups)": "0.844",
"Agreement interpretation": "High correlation and near-perfect agreement"
}
},
{
"label": "Survival analysis summary",
"entries": {
"Cohort size": "23,011 participants",
"Events": "1,624 deaths",
"Median follow-up": "6.7 years",
"Model type": "Cox proportional hazards",
"Adjusted covariates": "Age, sex, smoking status, heart disease",
"Highest risk group HR": "2.05 (95% CI 1.77–2.39)",
"Concordance index": "0.685"
}
}
]
},
"training": {
"title": "Training",
"text": "The CAC segmentation model was trained in a supervised manner using 778 ECG-gated chest CT scans from the Framingham Heart Study with expert CAC annotations. The pipeline uses a two-stage approach: nnU-Net-based cardiac segmentation followed by patch-based 3D U-Net training on balanced overlapping 3D patches extracted from heart-centered volumes [1].",
"references": [
{
"label": "DeepCAC2 preprint",
"uri": "https://arxiv.org/abs/2601.10154"
}
]
},
"limitations": {
"title": "Limitations",
"text": "The model is optimized for non-contrast, low-dose chest CT scans and may be sensitive to variations in acquisition protocols, reconstruction parameters, and image quality. CAC quantification is derived from non-ECG-gated scans, which may introduce motion-related inaccuracies compared to dedicated cardiac CT. Generalization to other populations, scanners, and clinical workflows requires further validation [1].",
"references": [
{
"label": "DeepCAC2 preprint",
"uri": "https://arxiv.org/abs/2601.10154"
}
]
}
}
}
2 changes: 2 additions & 0 deletions models/deepcac2/mhub.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[model.deployment]
test = "https://zenodo.org/records/19921552/files/mhub_test_deepcac2.zip"
1 change: 1 addition & 0 deletions models/deepcac2/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
weights/
Empty file added models/deepcac2/src/__init__.py
Empty file.
Loading
Loading