Skip to content

Commit 39ec210

Browse files
github actions
1 parent 6c341ad commit 39ec210

4 files changed

Lines changed: 218 additions & 50 deletions

File tree

.github/workflows/recon-docker.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Build & Push Recon Image
2+
3+
on:
4+
push:
5+
branches: [main]
6+
tags: ["v*"]
7+
paths:
8+
- "src/recon/**"
9+
- ".github/workflows/recon-docker.yml"
10+
11+
jobs:
12+
build-push:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
packages: write
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Log in to GHCR
23+
uses: docker/login-action@v3
24+
with:
25+
registry: ghcr.io
26+
username: ${{ github.actor }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Extract metadata
30+
id: meta
31+
uses: docker/metadata-action@v5
32+
with:
33+
images: ghcr.io/bic-mac-challenge/recon
34+
tags: |
35+
type=semver,pattern={{version}}
36+
type=semver,pattern={{major}}.{{minor}}
37+
type=sha,prefix=sha-,format=short
38+
type=raw,value=latest,enable={{is_default_branch}}
39+
40+
- name: Set up Docker Buildx
41+
uses: docker/setup-buildx-action@v3
42+
43+
- name: Build and push
44+
uses: docker/build-push-action@v6
45+
with:
46+
context: src/recon
47+
push: true
48+
tags: ${{ steps.meta.outputs.tags }}
49+
labels: ${{ steps.meta.outputs.labels }}
50+
cache-from: type=registry,ref=ghcr.io/bic-mac-challenge/recon:cache
51+
cache-to: type=registry,ref=ghcr.io/bic-mac-challenge/recon:cache,mode=max

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.old/
22
conversion/
3-
3+
CLAUDE.md
44

55
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,python
66
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,python

README.md

Lines changed: 165 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,196 @@
1-
# BIC-MAC Challenge: Big Cross-Modal Attenuation Correction
1+
# BIC-MAC Challenge Codebase
22

3-
Synthesizing pseudo-CT (mu-map) for PET attenuation correction from multimodal inputs (PET, MRI, Topogram).
3+
**Big Cross-Modal Attenuation Correction** — synthesize pseudo-CT from multi-modal PET/MRI input to enable CT-less PET reconstruction.
44

5-
## Tasks
5+
[Challenge website](https://bic-mac-challenge.github.io/)
66

7-
**Task 1**: Generate mu-map in CT-space (evaluated vs reference CT-mu-map)
7+
---
88

9-
**Task 2**: Generate mu-map for PET reconstruction in PET-space (evaluated vs reference CT-AC PET)
9+
## Overview
1010

11-
## Docker Interface
11+
PET/CT scanners combine functional PET imaging with anatomical CT. The CT is used to compute an attenuation correction factor (ACF) — a correction for how much the body absorbs the 511 keV photons emitted during PET scanning. While PET tracer doses have dropped significantly with modern scanners, the CT component remains the primary radiation source in a PET/CT exam.
1212

13-
### Task 1 and 2: Mu-map Prediction
13+
This challenge asks participants to synthesize a pseudo-CT from three radiation-free inputs: non-attenuation-corrected PET (NAC-PET), whole-body MRI, and a 2D topogram (scout X-ray). The predicted CT is then used as a drop-in replacement in the standard reconstruction pipeline, producing an attenuation-corrected PET (ACPET) image without a volumetric CT scan. Eliminating the CT dose is particularly valuable for radiation-sensitive populations such as children and pregnant patients.
14+
15+
The dataset comprises 100 healthy volunteers acquired on a **Siemens Biograph Vision Quadra** (PET/CT) and **MAGNETOM Vida** (MRI), with 75 training cases and 4 validation cases. Both static and dynamic acquisition protocols are included.
16+
17+
---
18+
19+
## Repository Structure
20+
21+
```
22+
src/
23+
├── baseline/ # Baseline pseudo-CT model (patch-based MONAI 3D UNet, NAC-PET input)
24+
├── evaluation/ # Five-metric evaluation suite
25+
└── recon/ # PET reconstruction pipeline (STIR-based, Dockerized)
26+
```
27+
28+
---
29+
30+
## Getting Started
31+
32+
**Requirements:** Python 3.12, [uv](https://github.com/astral-sh/uv), Docker
1433

1534
```bash
16-
docker run --rm \
17-
-v /path/to/subject:/input:ro \
18-
-v /path/to/output/dir:/output \
19-
your-solution:latest \
20-
/input /output/predicted_ct.nii.gz
35+
uv sync
36+
```
37+
38+
**Dataset:** Download from Hugging Face Hub (link available at challenge launch — see [website](https://bic-mac-challenge.github.io/)).
39+
40+
---
41+
42+
## Data Format
43+
44+
Each subject is a directory with four subdirectories:
45+
46+
```
47+
sub-000/
48+
├── features/ # Inputs to your model
49+
├── ct-label/ # Ground-truth CT and segmentations
50+
├── recon/ # Sinogram data for reconstruction
51+
└── pet-label/ # Ground-truth ACPET and segmentations
2152
```
2253

23-
**Arguments:**
24-
1. Input directory: PET, MRI, Topogram, metadata.json
25-
2. Output file path: Predicted CT (NIfTI)
54+
### `features/` — model inputs
55+
56+
| File | Description |
57+
|------|-------------|
58+
| `nacpet.nii.gz` | Non-attenuation-corrected PET (NAC-PET) |
59+
| `topogram.nii.gz` | 2D scout X-ray (topogram) resampled to 3D CT grid |
60+
| `mri_chunk_*_*.nii.gz` | DIXON MRI chunks (in-phase and out-of-phase) |
61+
| `mri_combined_*_phase.nii.gz` | Combined whole-body DIXON MRI |
62+
| `metadata.json` | Demographics: `{sex, age, height, weight}` |
63+
64+
### `ct-label/` — ground-truth CT
65+
66+
| File | Description |
67+
|------|-------------|
68+
| `ct.nii.gz` | Anonymized ground-truth CT in Hounsfield units (HU) |
69+
| `body_seg.nii.gz` | Binary body mask |
70+
| `organ_seg.nii.gz` | TotalSegmentator organ labels |
71+
| `face_seg.nii.gz` | Face mask (used for anonymization) |
72+
73+
### `recon/` — reconstruction inputs
74+
75+
| File | Description |
76+
|------|-------------|
77+
| `mult_factors_forSTIR_SSRB.hs/.s` | Multiplicative correction sinogram |
78+
| `additive_term_SSRB.hs/.s` | Additive correction sinogram (scatter + randoms) |
79+
| `prompts_SSRB.hs/.s` | Prompt (raw) sinogram |
80+
| `offset.json` | Bed position and gantry offset for origin alignment |
81+
| `ct_face.nii.gz` | Ground-truth CT face region (for optional face swap) |
82+
| `face_mask.nii.gz` | Face mask for anonymization |
83+
84+
### `pet-label/` — ground-truth ACPET
85+
86+
| File | Description |
87+
|------|-------------|
88+
| `acpet.nii.gz` | Ground-truth CT-attenuation-corrected PET (reference) |
89+
| `body_seg.nii.gz` | Body mask resampled to PET space |
90+
| `organ_seg.nii.gz` | Organ labels resampled to PET space |
91+
| `brain_seg.nii.gz` | SynthSeg brain segmentation |
92+
93+
---
94+
95+
## Baseline (`src/baseline/`)
2696

27-
**Input files:**
28-
- `*nacstat_pet.nii.gz`
29-
- `*DIXONbodyIN_T1w.nii.gz`, `*DIXONbodyOUT_T1w.nii.gz`
30-
- `*DIXONbodyIN_chunk-{1-4}_T1w.nii.gz`, `*DIXONbodyOUT_chunk-{1-4}_T1w.nii.gz`
31-
- `*DIXONheadIN_T1w.nii.gz`, `*DIXONheadOUT_T1w.nii.gz`
32-
- `*acq-TOPOGRAM_rec-tr20f_Xray.nii.gz`
33-
- `metadata.json`
97+
A simple patch-based MONAI 3D UNet that predicts pseudo-CT from NAC-PET only. It is provided as a starting-point reference — participants are expected to improve on it by incorporating MRI and topogram inputs.
3498

35-
### Task 2: PET Reconstruction
99+
A pre-built Docker image is available for download (see [website](https://bic-mac-challenge.github.io/)).
100+
101+
**Direct Python usage:**
36102

37103
```bash
38-
docker run --rm \
39-
-v /path/to/predicted_ct.nii.gz:/input_ct:ro \
40-
-v /path/to/recon_dir:/recon:ro \
41-
-v /path/to/output/dir:/output \
42-
reconstruction-software:latest \
43-
/input_ct /recon /output/reconstructed_pet.nii.gz
104+
python src/baseline/model.py <input_dir> <output_ct.nii.gz>
105+
# Example:
106+
python src/baseline/model.py data/sub-000/features/ results/sub-000/ct_pred.nii.gz
44107
```
45108

46-
**Arguments:**
47-
1. Input CT: Predicted mu-map from Task 1
48-
2. Reconstruction directory: Sinograms, scatter maps, normalization data
49-
3. Output file path: Reconstructed PET (NIfTI)
109+
---
110+
111+
## Reconstruction Pipeline (`src/recon/`)
112+
113+
Converts a predicted pseudo-CT into a reconstructed ACPET image using [STIR](http://stir.sourceforge.net/) (Software for Tomographic Image Reconstruction). The pipeline:
50114

51-
## Baseline
115+
1. Validates CT shape, affine, and HU range
116+
2. Converts HU → linear attenuation coefficients (μ-map) at 511 keV using the Carney et al. (2006) bilinear model
117+
3. Smooths the μ-map (4mm FWHM Gaussian)
118+
4. Resamples the μ-map to STIR sinogram format
119+
5. Computes the ACF (attenuation correction factor) sinogram
120+
6. Applies ACF to multiplicative/additive sinograms
121+
7. Reconstructs using OSEM (ordered subsets expectation maximisation)
122+
8. Applies 4mm post-reconstruction filter
123+
9. Converts to NIfTI with correct bed/gantry offset origin
124+
125+
### Option 1: Docker (recommended)
126+
127+
A pre-built image with STIR and all dependencies is available (see [website](https://bic-mac-challenge.github.io/)).
52128

53129
```bash
54-
cd src/baseline
55-
docker build -t baseline-solution:latest .
130+
docker pull ghcr.io/bic-mac-challenge/recon:latest # placeholder — final name on website
56131

57132
docker run --rm \
58-
-v /path/to/subject:/input:ro \
59-
-v /path/to/output:/output \
60-
baseline-solution:latest \
61-
/input /output/predicted_ct.nii.gz
133+
-v /path/to/sub-000/recon:/data/recon \
134+
-v /path/to/ct_pred.nii.gz:/data/ct/ct.nii.gz \
135+
-v /path/to/output:/data/output \
136+
ghcr.io/bic-mac-challenge/recon:latest
62137
```
63138

64-
## Evaluation
139+
The reconstructed PET is written to `/data/output/pet.nii.gz`.
65140

66-
### Task 1
141+
Set `OVERWRITE=1` to re-run over existing outputs:
67142

68143
```bash
69-
python src/evaluation/run_docker_model.py your-solution:latest /path/to/subject /path/to/output.nii.gz
70-
python src/evaluation/evaluate_task1.py /path/to/predictions /path/to/ground_truth
144+
docker run --rm -e OVERWRITE=1 \
145+
-v /path/to/sub-000/recon:/data/recon \
146+
...
71147
```
72148

73-
### Task 2
149+
### Option 2: Direct Python (requires local STIR)
74150

75151
```bash
76-
python src/evaluation/run_docker_model.py your-solution:latest /path/to/subject /path/to/predicted_ct.nii.gz
77-
python src/evaluation/run_docker_reconstruction.py reconstruction-software:latest /path/to/predicted_ct.nii.gz /path/to/recon_dir /path/to/output_pet.nii.gz
78-
python src/evaluation/evaluate_task2.py /path/to/reconstructed_pets /path/to/reference_ct_ac_pets
152+
python src/recon/main.py <recon_dir> <ct.nii.gz> <pet_out.nii.gz> \
153+
[--overwrite] [--intermediates_dir <dir>]
79154
```
155+
156+
---
157+
158+
## Evaluation (`src/evaluation/`)
159+
160+
Five metrics compare predicted PET and CT outputs against the ground truth:
161+
162+
| Metric | Flag | Description | Region |
163+
|--------|------|-------------|--------|
164+
| Whole-body SUV MAE | `whole_body_mae` | Mean absolute error in standardised uptake value (SUV = activity × weight / total dose) | Body mask, excluding ±4 cm around liver |
165+
| Brain Outlier Score | `brain_outlier` | AUC of fraction of brain voxels within relative error thresholds (5%, 10%, 15%) | Brain |
166+
| Organ Bias (MARE) | `organ_bias` | Mean absolute relative error of mean SUV in 8 organs: brain, liver, spleen, heart, pancreas, muscle, adipose, extremities | TotalSegmentator organ labels |
167+
| TAC Bias | `tac_bias` | AUC MARE for time-activity curves in aorta + 6 brain regions (4D dynamic PET only) | Aorta + brain regions |
168+
| CT MAE | `ct_mae` | Mean absolute error in HU between predicted and ground-truth CT | Body mask |
169+
170+
**Run all metrics:**
171+
172+
```bash
173+
python src/evaluation/eval.py <subject_dir> <pred_pet.nii.gz> <pred_ct.nii.gz> -all
174+
```
175+
176+
**Run a single metric:**
177+
178+
```bash
179+
python src/evaluation/eval.py <subject_dir> <pred_pet.nii.gz> <pred_ct.nii.gz> \
180+
-specific_metric <metric>
181+
# <metric>: whole_body_mae | brain_outlier | organ_bias | tac_bias | ct_mae
182+
```
183+
184+
---
185+
186+
## Tips & FAQ
187+
188+
_Coming soon._
189+
190+
---
191+
192+
## Organizers
193+
194+
This challenge is organized by [Rigshospitalet](https://www.rigshospitalet.dk/), [Technical University of Denmark (DTU)](https://www.dtu.dk/), [University of Copenhagen (KU)](https://www.ku.dk/), and [KU Leuven](https://www.kuleuven.be/), with support from [QIM](https://qim.dk/) and [SyneRBI](https://www.synergistic-biomedical-imaging.eu/).
195+
196+
For full details, timeline, and registration: [bic-mac-challenge.github.io](https://bic-mac-challenge.github.io/)

src/recon/docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ services:
22

33
recon:
44
build: .
5-
image: christianhinge/recon
5+
image: ghcr.io/bic-mac-challenge/recon

0 commit comments

Comments
 (0)