simcortexpp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simcortexpp-0.1.0/PKG-INFO +334 -0
- simcortexpp-0.1.0/README.md +309 -0
- simcortexpp-0.1.0/pyproject.toml +66 -0
- simcortexpp-0.1.0/setup.cfg +4 -0
- simcortexpp-0.1.0/src/simcortexpp/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/cli/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/cli/main.py +81 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/deform/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/deform/eval.yaml +34 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/deform/inference.yaml +60 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/deform/train.yaml +98 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/initsurf/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/initsurf/generate.yaml +50 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/seg/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/seg/eval.yaml +31 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/seg/inference.yaml +35 -0
- simcortexpp-0.1.0/src/simcortexpp/configs/seg/train.yaml +42 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/data/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/data/dataloader.py +268 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/eval.py +347 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/inference.py +244 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/models/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/models/surfdeform.py +356 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/train.py +1173 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/utils/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/deform/utils/coords.py +90 -0
- simcortexpp-0.1.0/src/simcortexpp/initsurf/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/initsurf/generate.py +354 -0
- simcortexpp-0.1.0/src/simcortexpp/initsurf/paths.py +19 -0
- simcortexpp-0.1.0/src/simcortexpp/preproc/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/preproc/fs_to_mni.py +696 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/data/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/data/dataloader.py +328 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/eval.py +248 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/inference.py +291 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/models/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/models/unet.py +63 -0
- simcortexpp-0.1.0/src/simcortexpp/seg/train.py +432 -0
- simcortexpp-0.1.0/src/simcortexpp/utils/__init__.py +0 -0
- simcortexpp-0.1.0/src/simcortexpp/utils/tca.py +298 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/PKG-INFO +334 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/SOURCES.txt +47 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/dependency_links.txt +1 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/entry_points.txt +2 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/requires.txt +20 -0
- simcortexpp-0.1.0/src/simcortexpp.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simcortexpp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SimCortexPP (SCPP) — CLI-first pipeline for cortical surface reconstruction (preproc, seg, initsurf, deform)
|
|
5
|
+
Author: Kaveh Moradkhani
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: typer>=0.12
|
|
9
|
+
Requires-Dist: numpy>=1.24
|
|
10
|
+
Requires-Dist: pandas>=2.0
|
|
11
|
+
Requires-Dist: nibabel>=5.2
|
|
12
|
+
Requires-Dist: hydra-core>=1.3
|
|
13
|
+
Requires-Dist: omegaconf>=2.3
|
|
14
|
+
Requires-Dist: tqdm>=4.66
|
|
15
|
+
Requires-Dist: tensorboard>=2.14
|
|
16
|
+
Requires-Dist: trimesh>=4.0
|
|
17
|
+
Requires-Dist: openpyxl>=3.1
|
|
18
|
+
Provides-Extra: seg
|
|
19
|
+
Requires-Dist: monai>=1.3; extra == "seg"
|
|
20
|
+
Provides-Extra: deform-metrics
|
|
21
|
+
Requires-Dist: python-fcl; extra == "deform-metrics"
|
|
22
|
+
Requires-Dist: pymeshlab; extra == "deform-metrics"
|
|
23
|
+
Provides-Extra: torch
|
|
24
|
+
Requires-Dist: torch>=2.0; extra == "torch"
|
|
25
|
+
|
|
26
|
+
# SimCortexPP (SCPP)
|
|
27
|
+
|
|
28
|
+
SimCortexPP (SCPP) is a **CLI-first** Python package for cortical surface reconstruction in MNI space. It provides four stages:
|
|
29
|
+
|
|
30
|
+
1. **Preprocessing (FreeSurfer → MNI152)**
|
|
31
|
+
Export key FreeSurfer volumes/surfaces, register them to MNI152, and write outputs in a **BIDS-derivatives-style** layout.
|
|
32
|
+
|
|
33
|
+
2. **Segmentation (3D U-Net in MNI space)**
|
|
34
|
+
Train and apply a 3D U-Net to predict a **9-class segmentation** in **MNI152 space**, with inference and evaluation utilities.
|
|
35
|
+
|
|
36
|
+
3. **Initial Surfaces (InitSurf)**
|
|
37
|
+
Generate initial White Matter and Pial surfaces from segmentation predictions (plus ribbon SDF/probability outputs).
|
|
38
|
+
|
|
39
|
+
4. **Deformation (Deform)**
|
|
40
|
+
Deform the initial surfaces toward MNI-aligned FreeSurfer surfaces using geometric losses and optional collision metrics, and write **deformed surfaces** as BIDS-derivatives.
|
|
41
|
+
|
|
42
|
+
This README focuses on **how to run the pipeline correctly** (inputs, outputs, folder/file naming, and commands).
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Table of Contents
|
|
47
|
+
|
|
48
|
+
- [Installation](#installation)
|
|
49
|
+
- [Configuration](#configuration)
|
|
50
|
+
- [Data and Folder Conventions](#data-and-folder-conventions)
|
|
51
|
+
- [Split File Format](#split-file-format)
|
|
52
|
+
- [Stage 1 — Preprocessing: FreeSurfer → MNI152](#stage-1--preprocessing-freesurfer--mni152)
|
|
53
|
+
- [Stage 2 — Segmentation: 3D U-Net (MNI space)](#stage-2--segmentation-3d-u-net-mni-space)
|
|
54
|
+
- [Stage 3 — Initial Surfaces (InitSurf)](#stage-3--initial-surfaces-initsurf)
|
|
55
|
+
- [Stage 4 — Deformation (Deform)](#stage-4--deformation-deform)
|
|
56
|
+
- [License](#license)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
From the repository root:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e .
|
|
66
|
+
scpp --help
|
|
67
|
+
scpp seg --help
|
|
68
|
+
scpp initsurf --help
|
|
69
|
+
scpp deform --help
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Recommended environment
|
|
73
|
+
- Python 3.10+
|
|
74
|
+
- PyTorch + MONAI
|
|
75
|
+
- `nibabel`, `numpy`, `pandas`, `openpyxl`
|
|
76
|
+
- `trimesh`, `scipy`, `tqdm`
|
|
77
|
+
- External tools for Stage 1: **NiftyReg** (`reg_aladin`, `reg_resample`)
|
|
78
|
+
- Optional (Deform metrics):
|
|
79
|
+
- `python-fcl` for collision metrics
|
|
80
|
+
- `pymeshlab` for SIF (self-intersection fraction) in Deform evaluation
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
All stages use Hydra YAML configs shipped with the package (see `src/simcortexpp/configs/<stage>/*.yaml`).
|
|
87
|
+
|
|
88
|
+
You have **two** ways to configure a run:
|
|
89
|
+
|
|
90
|
+
1) **Edit the stage YAML** (recommended for longer runs / stable experiments), then run commands with no extra arguments, e.g.:
|
|
91
|
+
- `scpp deform eval`
|
|
92
|
+
|
|
93
|
+
2) **Use Hydra overrides on the CLI** (recommended for quick tests), e.g.:
|
|
94
|
+
- `scpp deform eval dataset.split_name=test outputs.out_dir=/tmp/deform_eval`
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Data and Folder Conventions
|
|
99
|
+
|
|
100
|
+
You will typically work with **two roots**:
|
|
101
|
+
|
|
102
|
+
1) **Code repository (this repository)**
|
|
103
|
+
Contains code, configs, and scripts (no data).
|
|
104
|
+
|
|
105
|
+
2) **Dataset root (BIDS + derivatives)**
|
|
106
|
+
Each dataset has its own root directory. Recommended structure:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
datasets/<dataset-name>/
|
|
110
|
+
bids/ # raw BIDS dataset
|
|
111
|
+
derivatives/ # processed outputs (BIDS derivatives)
|
|
112
|
+
freesurfer-7.4.1/
|
|
113
|
+
scpp-preproc-0.1/
|
|
114
|
+
scpp-seg-0.1/
|
|
115
|
+
scpp-initsurf-0.1/
|
|
116
|
+
scpp-deform-0.1/
|
|
117
|
+
splits/
|
|
118
|
+
<dataset>_split.csv
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
SCPP reads inputs from `derivatives/` and writes outputs back to `derivatives/` using BIDS-derivatives-style naming.
|
|
122
|
+
|
|
123
|
+
> Important: keep the dataset root naming consistent (e.g., use `datasets/...` everywhere).
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Split File Format
|
|
128
|
+
|
|
129
|
+
A split CSV is required for Segmentation, InitSurf, and Deform.
|
|
130
|
+
|
|
131
|
+
### Single-dataset split
|
|
132
|
+
Minimal columns:
|
|
133
|
+
- `subject` (e.g., `sub-0001`)
|
|
134
|
+
- `split` in `{train, val, test}`
|
|
135
|
+
|
|
136
|
+
### Multi-dataset split
|
|
137
|
+
Include an additional column:
|
|
138
|
+
- `dataset` (string key that matches config keys, e.g., `HCP_YA`, `OASIS1`)
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
```csv
|
|
142
|
+
subject,split,dataset
|
|
143
|
+
sub-100307,test,HCP_YA
|
|
144
|
+
sub-101915,test,HCP_YA
|
|
145
|
+
sub-0001,test,OASIS1
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Stage 1 — Preprocessing: FreeSurfer → MNI152
|
|
151
|
+
|
|
152
|
+
This stage exports key FreeSurfer outputs (volumes + surfaces), registers them to **MNI152**, and writes results to a **BIDS-derivatives-style** folder.
|
|
153
|
+
|
|
154
|
+
### Inputs
|
|
155
|
+
- FreeSurfer derivatives root (contains `sub-*` folders)
|
|
156
|
+
- MNI template (e.g., `src/MNI152_T1_1mm.nii.gz`)
|
|
157
|
+
|
|
158
|
+
### Dependencies (system tools)
|
|
159
|
+
- **NiftyReg**: `reg_aladin`, `reg_resample` must be in `PATH`
|
|
160
|
+
- **FreeSurfer** tools are recommended (e.g., `mri_convert`, `mris_convert`) for consistent conversions
|
|
161
|
+
|
|
162
|
+
### Run (all subjects discovered automatically)
|
|
163
|
+
```bash
|
|
164
|
+
scpp fs-to-mni --freesurfer-root /path/to/datasets/<dataset>/derivatives/freesurfer-7.4.1 --out-deriv-root /path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 --mni-template /path/to/SimCortexPP/src/MNI152_T1_1mm.nii.gz --decimate 0.3 -v
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Run (selected subjects)
|
|
168
|
+
```bash
|
|
169
|
+
scpp fs-to-mni --freesurfer-root /path/to/datasets/<dataset>/derivatives/freesurfer-7.4.1 --out-deriv-root /path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 --mni-template /path/to/SimCortexPP/src/MNI152_T1_1mm.nii.gz -p sub-0001 -p sub-0019 -v
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Output layout (example)
|
|
173
|
+
```text
|
|
174
|
+
scpp-preproc-0.1/
|
|
175
|
+
dataset_description.json
|
|
176
|
+
sub-XXXX/
|
|
177
|
+
ses-01/
|
|
178
|
+
anat/
|
|
179
|
+
sub-XXXX_ses-01_space-MNI152_desc-preproc_T1w.nii.gz
|
|
180
|
+
sub-XXXX_ses-01_space-MNI152_desc-aparc+aseg_dseg.nii.gz
|
|
181
|
+
sub-XXXX_ses-01_space-MNI152_desc-filled_T1w.nii.gz
|
|
182
|
+
sub-XXXX_ses-01_from-T1w_to-MNI152_mode-image_xfm.txt
|
|
183
|
+
surfaces/
|
|
184
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_white.surf.ply
|
|
185
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_pial.surf.ply
|
|
186
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_white.surf.ply
|
|
187
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_pial.surf.ply
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Stage 2 — Segmentation: 3D U-Net (MNI space)
|
|
193
|
+
|
|
194
|
+
This stage trains and applies a 3D U-Net to predict a **9-class segmentation** in **MNI152 space** using Stage 1 outputs.
|
|
195
|
+
|
|
196
|
+
### Expected inputs (from Stage 1)
|
|
197
|
+
Under `scpp-preproc-*`, for each subject:
|
|
198
|
+
- `..._desc-preproc_T1w.nii.gz`
|
|
199
|
+
- `..._desc-aparc+aseg_dseg.nii.gz`
|
|
200
|
+
- `..._desc-filled_T1w.nii.gz`
|
|
201
|
+
|
|
202
|
+
### Output naming (predictions)
|
|
203
|
+
Predictions are written under `scpp-seg-*`:
|
|
204
|
+
- `sub-XXXX/ses-01/anat/sub-XXXX_ses-01_space-MNI152_desc-seg9_dseg.nii.gz`
|
|
205
|
+
|
|
206
|
+
### Train (single GPU)
|
|
207
|
+
```bash
|
|
208
|
+
scpp seg train dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv outputs.root=/path/to/scpp-runs/seg/exp01 trainer.use_ddp=false
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Train (multi-GPU, torchrun)
|
|
212
|
+
```bash
|
|
213
|
+
scpp seg train --torchrun --nproc-per-node 2 dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv outputs.root=/path/to/scpp-runs/seg/exp01 trainer.use_ddp=true
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Inference
|
|
217
|
+
```bash
|
|
218
|
+
scpp seg infer dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv dataset.split_name=test model.ckpt_path=/path/to/seg_best_dice.pt outputs.out_root=/path/to/datasets/<dataset>/derivatives/scpp-seg-0.1
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Evaluation (multi-dataset example)
|
|
222
|
+
```bash
|
|
223
|
+
scpp seg eval dataset.split_file=/path/to/datasets/splits/dataset_split.csv dataset.split_name=test dataset.roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-preproc-0.1 dataset.roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-preproc-0.1 outputs.pred_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-seg-0.1 outputs.pred_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-seg-0.1 outputs.eval_csv=/path/to/scpp-runs/seg/exp01/evals/seg_eval_test.csv outputs.eval_xlsx=/path/to/scpp-runs/seg/exp01/evals/seg_eval_test.xlsx
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Stage 3 — Initial Surfaces (InitSurf)
|
|
229
|
+
|
|
230
|
+
This stage generates initial cortical surfaces from saved segmentation predictions (not end-to-end).
|
|
231
|
+
|
|
232
|
+
### Inputs
|
|
233
|
+
- Preproc roots (`scpp-preproc-*`) for MNI T1
|
|
234
|
+
- Seg roots (`scpp-seg-*`) for `..._desc-seg9_dseg.nii.gz`
|
|
235
|
+
- Split CSV (same format as Stage 2)
|
|
236
|
+
|
|
237
|
+
### Outputs
|
|
238
|
+
BIDS-derivatives-style outputs under `scpp-initsurf-*` (meshes + SDF volumes + ribbon prob):
|
|
239
|
+
```text
|
|
240
|
+
scpp-initsurf-0.1/
|
|
241
|
+
dataset_description.json
|
|
242
|
+
sub-XXXX/
|
|
243
|
+
ses-01/
|
|
244
|
+
anat/
|
|
245
|
+
sub-XXXX_ses-01_space-MNI152_desc-lh_white_sdf.nii.gz
|
|
246
|
+
sub-XXXX_ses-01_space-MNI152_desc-rh_white_sdf.nii.gz
|
|
247
|
+
sub-XXXX_ses-01_space-MNI152_desc-lh_pial_sdf.nii.gz
|
|
248
|
+
sub-XXXX_ses-01_space-MNI152_desc-rh_pial_sdf.nii.gz
|
|
249
|
+
sub-XXXX_ses-01_space-MNI152_desc-ribbon_sdf.nii.gz
|
|
250
|
+
sub-XXXX_ses-01_space-MNI152_desc-ribbon_prob.nii.gz
|
|
251
|
+
surfaces/
|
|
252
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_white.surf.ply
|
|
253
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_pial.surf.ply
|
|
254
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_white.surf.ply
|
|
255
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_pial.surf.ply
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Run (multi-dataset example)
|
|
259
|
+
```bash
|
|
260
|
+
scpp initsurf generate dataset.split_file=/path/to/datasets/splits/dataset_split.csv dataset.split_name=all dataset.roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-preproc-0.1 dataset.roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-preproc-0.1 dataset.seg_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-seg-0.1 dataset.seg_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-seg-0.1 outputs.out_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-initsurf-0.1 outputs.out_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-initsurf-0.1 outputs.log_dir=/path/to/scpp-runs/initsurf/exp01/logs_generate
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Typical runtime: ~31 s/subject (hardware-dependent).
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Stage 4 — Deformation (Deform)
|
|
268
|
+
|
|
269
|
+
This stage deforms InitSurf meshes using input volumes and geometric losses, and writes **deformed** surfaces to a BIDS-derivatives folder.
|
|
270
|
+
|
|
271
|
+
### Inputs
|
|
272
|
+
- Preproc root (`scpp-preproc-*`): MNI T1 + GT FreeSurfer surfaces in MNI space
|
|
273
|
+
- InitSurf root (`scpp-initsurf-*`): ribbon probability + initial surfaces
|
|
274
|
+
- Split CSV (same format as Stage 2)
|
|
275
|
+
|
|
276
|
+
### Outputs
|
|
277
|
+
Deformed surfaces under `scpp-deform-*`:
|
|
278
|
+
```text
|
|
279
|
+
scpp-deform-0.1/
|
|
280
|
+
dataset_description.json
|
|
281
|
+
sub-XXXX/
|
|
282
|
+
ses-01/
|
|
283
|
+
surfaces/
|
|
284
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-L_white.surf.ply
|
|
285
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-L_pial.surf.ply
|
|
286
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-R_white.surf.ply
|
|
287
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-R_pial.surf.ply
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Train (multi-GPU example)
|
|
291
|
+
```bash
|
|
292
|
+
scpp deform train --torchrun --nproc-per-node 2 outputs.root=/path/to/scpp-runs/deform/exp01
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Inference
|
|
296
|
+
```bash
|
|
297
|
+
scpp deform infer
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Evaluation
|
|
301
|
+
```bash
|
|
302
|
+
scpp deform eval
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Evaluation writes four Excel files:
|
|
306
|
+
- `surface_metrics.xlsx`
|
|
307
|
+
- `collision_metrics.xlsx`
|
|
308
|
+
- `collision_metrics_enhanced.xlsx`
|
|
309
|
+
- `collision_summary.xlsx`
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Outputs Summary
|
|
314
|
+
|
|
315
|
+
For each dataset root:
|
|
316
|
+
|
|
317
|
+
- `derivatives/scpp-preproc-0.1/`
|
|
318
|
+
MNI T1, aparc+aseg, filled, transforms, and MNI-aligned FreeSurfer surfaces.
|
|
319
|
+
|
|
320
|
+
- `derivatives/scpp-seg-0.1/`
|
|
321
|
+
9-class segmentation predictions (`*_desc-seg9_dseg.nii.gz`).
|
|
322
|
+
|
|
323
|
+
- `derivatives/scpp-initsurf-0.1/`
|
|
324
|
+
Initial surfaces (`*.surf.ply`) + SDF volumes + ribbon SDF/probability.
|
|
325
|
+
|
|
326
|
+
- `derivatives/scpp-deform-0.1/`
|
|
327
|
+
Deformed surfaces (`*_desc-deform_*.surf.ply`).
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
Add your license and citation details here if needed.
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# SimCortexPP (SCPP)
|
|
2
|
+
|
|
3
|
+
SimCortexPP (SCPP) is a **CLI-first** Python package for cortical surface reconstruction in MNI space. It provides four stages:
|
|
4
|
+
|
|
5
|
+
1. **Preprocessing (FreeSurfer → MNI152)**
|
|
6
|
+
Export key FreeSurfer volumes/surfaces, register them to MNI152, and write outputs in a **BIDS-derivatives-style** layout.
|
|
7
|
+
|
|
8
|
+
2. **Segmentation (3D U-Net in MNI space)**
|
|
9
|
+
Train and apply a 3D U-Net to predict a **9-class segmentation** in **MNI152 space**, with inference and evaluation utilities.
|
|
10
|
+
|
|
11
|
+
3. **Initial Surfaces (InitSurf)**
|
|
12
|
+
Generate initial White Matter and Pial surfaces from segmentation predictions (plus ribbon SDF/probability outputs).
|
|
13
|
+
|
|
14
|
+
4. **Deformation (Deform)**
|
|
15
|
+
Deform the initial surfaces toward MNI-aligned FreeSurfer surfaces using geometric losses and optional collision metrics, and write **deformed surfaces** as BIDS-derivatives.
|
|
16
|
+
|
|
17
|
+
This README focuses on **how to run the pipeline correctly** (inputs, outputs, folder/file naming, and commands).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Table of Contents
|
|
22
|
+
|
|
23
|
+
- [Installation](#installation)
|
|
24
|
+
- [Configuration](#configuration)
|
|
25
|
+
- [Data and Folder Conventions](#data-and-folder-conventions)
|
|
26
|
+
- [Split File Format](#split-file-format)
|
|
27
|
+
- [Stage 1 — Preprocessing: FreeSurfer → MNI152](#stage-1--preprocessing-freesurfer--mni152)
|
|
28
|
+
- [Stage 2 — Segmentation: 3D U-Net (MNI space)](#stage-2--segmentation-3d-u-net-mni-space)
|
|
29
|
+
- [Stage 3 — Initial Surfaces (InitSurf)](#stage-3--initial-surfaces-initsurf)
|
|
30
|
+
- [Stage 4 — Deformation (Deform)](#stage-4--deformation-deform)
|
|
31
|
+
- [License](#license)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
From the repository root:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e .
|
|
41
|
+
scpp --help
|
|
42
|
+
scpp seg --help
|
|
43
|
+
scpp initsurf --help
|
|
44
|
+
scpp deform --help
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Recommended environment
|
|
48
|
+
- Python 3.10+
|
|
49
|
+
- PyTorch + MONAI
|
|
50
|
+
- `nibabel`, `numpy`, `pandas`, `openpyxl`
|
|
51
|
+
- `trimesh`, `scipy`, `tqdm`
|
|
52
|
+
- External tools for Stage 1: **NiftyReg** (`reg_aladin`, `reg_resample`)
|
|
53
|
+
- Optional (Deform metrics):
|
|
54
|
+
- `python-fcl` for collision metrics
|
|
55
|
+
- `pymeshlab` for SIF (self-intersection fraction) in Deform evaluation
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
All stages use Hydra YAML configs shipped with the package (see `src/simcortexpp/configs/<stage>/*.yaml`).
|
|
62
|
+
|
|
63
|
+
You have **two** ways to configure a run:
|
|
64
|
+
|
|
65
|
+
1) **Edit the stage YAML** (recommended for longer runs / stable experiments), then run commands with no extra arguments, e.g.:
|
|
66
|
+
- `scpp deform eval`
|
|
67
|
+
|
|
68
|
+
2) **Use Hydra overrides on the CLI** (recommended for quick tests), e.g.:
|
|
69
|
+
- `scpp deform eval dataset.split_name=test outputs.out_dir=/tmp/deform_eval`
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Data and Folder Conventions
|
|
74
|
+
|
|
75
|
+
You will typically work with **two roots**:
|
|
76
|
+
|
|
77
|
+
1) **Code repository (this repository)**
|
|
78
|
+
Contains code, configs, and scripts (no data).
|
|
79
|
+
|
|
80
|
+
2) **Dataset root (BIDS + derivatives)**
|
|
81
|
+
Each dataset has its own root directory. Recommended structure:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
datasets/<dataset-name>/
|
|
85
|
+
bids/ # raw BIDS dataset
|
|
86
|
+
derivatives/ # processed outputs (BIDS derivatives)
|
|
87
|
+
freesurfer-7.4.1/
|
|
88
|
+
scpp-preproc-0.1/
|
|
89
|
+
scpp-seg-0.1/
|
|
90
|
+
scpp-initsurf-0.1/
|
|
91
|
+
scpp-deform-0.1/
|
|
92
|
+
splits/
|
|
93
|
+
<dataset>_split.csv
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
SCPP reads inputs from `derivatives/` and writes outputs back to `derivatives/` using BIDS-derivatives-style naming.
|
|
97
|
+
|
|
98
|
+
> Important: keep the dataset root naming consistent (e.g., use `datasets/...` everywhere).
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Split File Format
|
|
103
|
+
|
|
104
|
+
A split CSV is required for Segmentation, InitSurf, and Deform.
|
|
105
|
+
|
|
106
|
+
### Single-dataset split
|
|
107
|
+
Minimal columns:
|
|
108
|
+
- `subject` (e.g., `sub-0001`)
|
|
109
|
+
- `split` in `{train, val, test}`
|
|
110
|
+
|
|
111
|
+
### Multi-dataset split
|
|
112
|
+
Include an additional column:
|
|
113
|
+
- `dataset` (string key that matches config keys, e.g., `HCP_YA`, `OASIS1`)
|
|
114
|
+
|
|
115
|
+
Example:
|
|
116
|
+
```csv
|
|
117
|
+
subject,split,dataset
|
|
118
|
+
sub-100307,test,HCP_YA
|
|
119
|
+
sub-101915,test,HCP_YA
|
|
120
|
+
sub-0001,test,OASIS1
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Stage 1 — Preprocessing: FreeSurfer → MNI152
|
|
126
|
+
|
|
127
|
+
This stage exports key FreeSurfer outputs (volumes + surfaces), registers them to **MNI152**, and writes results to a **BIDS-derivatives-style** folder.
|
|
128
|
+
|
|
129
|
+
### Inputs
|
|
130
|
+
- FreeSurfer derivatives root (contains `sub-*` folders)
|
|
131
|
+
- MNI template (e.g., `src/MNI152_T1_1mm.nii.gz`)
|
|
132
|
+
|
|
133
|
+
### Dependencies (system tools)
|
|
134
|
+
- **NiftyReg**: `reg_aladin`, `reg_resample` must be in `PATH`
|
|
135
|
+
- **FreeSurfer** tools are recommended (e.g., `mri_convert`, `mris_convert`) for consistent conversions
|
|
136
|
+
|
|
137
|
+
### Run (all subjects discovered automatically)
|
|
138
|
+
```bash
|
|
139
|
+
scpp fs-to-mni --freesurfer-root /path/to/datasets/<dataset>/derivatives/freesurfer-7.4.1 --out-deriv-root /path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 --mni-template /path/to/SimCortexPP/src/MNI152_T1_1mm.nii.gz --decimate 0.3 -v
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Run (selected subjects)
|
|
143
|
+
```bash
|
|
144
|
+
scpp fs-to-mni --freesurfer-root /path/to/datasets/<dataset>/derivatives/freesurfer-7.4.1 --out-deriv-root /path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 --mni-template /path/to/SimCortexPP/src/MNI152_T1_1mm.nii.gz -p sub-0001 -p sub-0019 -v
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Output layout (example)
|
|
148
|
+
```text
|
|
149
|
+
scpp-preproc-0.1/
|
|
150
|
+
dataset_description.json
|
|
151
|
+
sub-XXXX/
|
|
152
|
+
ses-01/
|
|
153
|
+
anat/
|
|
154
|
+
sub-XXXX_ses-01_space-MNI152_desc-preproc_T1w.nii.gz
|
|
155
|
+
sub-XXXX_ses-01_space-MNI152_desc-aparc+aseg_dseg.nii.gz
|
|
156
|
+
sub-XXXX_ses-01_space-MNI152_desc-filled_T1w.nii.gz
|
|
157
|
+
sub-XXXX_ses-01_from-T1w_to-MNI152_mode-image_xfm.txt
|
|
158
|
+
surfaces/
|
|
159
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_white.surf.ply
|
|
160
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_pial.surf.ply
|
|
161
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_white.surf.ply
|
|
162
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_pial.surf.ply
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Stage 2 — Segmentation: 3D U-Net (MNI space)
|
|
168
|
+
|
|
169
|
+
This stage trains and applies a 3D U-Net to predict a **9-class segmentation** in **MNI152 space** using Stage 1 outputs.
|
|
170
|
+
|
|
171
|
+
### Expected inputs (from Stage 1)
|
|
172
|
+
Under `scpp-preproc-*`, for each subject:
|
|
173
|
+
- `..._desc-preproc_T1w.nii.gz`
|
|
174
|
+
- `..._desc-aparc+aseg_dseg.nii.gz`
|
|
175
|
+
- `..._desc-filled_T1w.nii.gz`
|
|
176
|
+
|
|
177
|
+
### Output naming (predictions)
|
|
178
|
+
Predictions are written under `scpp-seg-*`:
|
|
179
|
+
- `sub-XXXX/ses-01/anat/sub-XXXX_ses-01_space-MNI152_desc-seg9_dseg.nii.gz`
|
|
180
|
+
|
|
181
|
+
### Train (single GPU)
|
|
182
|
+
```bash
|
|
183
|
+
scpp seg train dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv outputs.root=/path/to/scpp-runs/seg/exp01 trainer.use_ddp=false
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Train (multi-GPU, torchrun)
|
|
187
|
+
```bash
|
|
188
|
+
scpp seg train --torchrun --nproc-per-node 2 dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv outputs.root=/path/to/scpp-runs/seg/exp01 trainer.use_ddp=true
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Inference
|
|
192
|
+
```bash
|
|
193
|
+
scpp seg infer dataset.path=/path/to/datasets/<dataset>/derivatives/scpp-preproc-0.1 dataset.split_file=/path/to/datasets/<dataset>/splits/<dataset>_split.csv dataset.split_name=test model.ckpt_path=/path/to/seg_best_dice.pt outputs.out_root=/path/to/datasets/<dataset>/derivatives/scpp-seg-0.1
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Evaluation (multi-dataset example)
|
|
197
|
+
```bash
|
|
198
|
+
scpp seg eval dataset.split_file=/path/to/datasets/splits/dataset_split.csv dataset.split_name=test dataset.roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-preproc-0.1 dataset.roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-preproc-0.1 outputs.pred_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-seg-0.1 outputs.pred_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-seg-0.1 outputs.eval_csv=/path/to/scpp-runs/seg/exp01/evals/seg_eval_test.csv outputs.eval_xlsx=/path/to/scpp-runs/seg/exp01/evals/seg_eval_test.xlsx
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Stage 3 — Initial Surfaces (InitSurf)
|
|
204
|
+
|
|
205
|
+
This stage generates initial cortical surfaces from saved segmentation predictions (not end-to-end).
|
|
206
|
+
|
|
207
|
+
### Inputs
|
|
208
|
+
- Preproc roots (`scpp-preproc-*`) for MNI T1
|
|
209
|
+
- Seg roots (`scpp-seg-*`) for `..._desc-seg9_dseg.nii.gz`
|
|
210
|
+
- Split CSV (same format as Stage 2)
|
|
211
|
+
|
|
212
|
+
### Outputs
|
|
213
|
+
BIDS-derivatives-style outputs under `scpp-initsurf-*` (meshes + SDF volumes + ribbon prob):
|
|
214
|
+
```text
|
|
215
|
+
scpp-initsurf-0.1/
|
|
216
|
+
dataset_description.json
|
|
217
|
+
sub-XXXX/
|
|
218
|
+
ses-01/
|
|
219
|
+
anat/
|
|
220
|
+
sub-XXXX_ses-01_space-MNI152_desc-lh_white_sdf.nii.gz
|
|
221
|
+
sub-XXXX_ses-01_space-MNI152_desc-rh_white_sdf.nii.gz
|
|
222
|
+
sub-XXXX_ses-01_space-MNI152_desc-lh_pial_sdf.nii.gz
|
|
223
|
+
sub-XXXX_ses-01_space-MNI152_desc-rh_pial_sdf.nii.gz
|
|
224
|
+
sub-XXXX_ses-01_space-MNI152_desc-ribbon_sdf.nii.gz
|
|
225
|
+
sub-XXXX_ses-01_space-MNI152_desc-ribbon_prob.nii.gz
|
|
226
|
+
surfaces/
|
|
227
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_white.surf.ply
|
|
228
|
+
sub-XXXX_ses-01_space-MNI152_hemi-L_pial.surf.ply
|
|
229
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_white.surf.ply
|
|
230
|
+
sub-XXXX_ses-01_space-MNI152_hemi-R_pial.surf.ply
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Run (multi-dataset example)
|
|
234
|
+
```bash
|
|
235
|
+
scpp initsurf generate dataset.split_file=/path/to/datasets/splits/dataset_split.csv dataset.split_name=all dataset.roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-preproc-0.1 dataset.roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-preproc-0.1 dataset.seg_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-seg-0.1 dataset.seg_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-seg-0.1 outputs.out_roots.HCP_YA=/path/to/datasets/hcpya-u100/derivatives/scpp-initsurf-0.1 outputs.out_roots.OASIS1=/path/to/datasets/oasis-1/derivatives/scpp-initsurf-0.1 outputs.log_dir=/path/to/scpp-runs/initsurf/exp01/logs_generate
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Typical runtime: ~31 s/subject (hardware-dependent).
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Stage 4 — Deformation (Deform)
|
|
243
|
+
|
|
244
|
+
This stage deforms InitSurf meshes using input volumes and geometric losses, and writes **deformed** surfaces to a BIDS-derivatives folder.
|
|
245
|
+
|
|
246
|
+
### Inputs
|
|
247
|
+
- Preproc root (`scpp-preproc-*`): MNI T1 + GT FreeSurfer surfaces in MNI space
|
|
248
|
+
- InitSurf root (`scpp-initsurf-*`): ribbon probability + initial surfaces
|
|
249
|
+
- Split CSV (same format as Stage 2)
|
|
250
|
+
|
|
251
|
+
### Outputs
|
|
252
|
+
Deformed surfaces under `scpp-deform-*`:
|
|
253
|
+
```text
|
|
254
|
+
scpp-deform-0.1/
|
|
255
|
+
dataset_description.json
|
|
256
|
+
sub-XXXX/
|
|
257
|
+
ses-01/
|
|
258
|
+
surfaces/
|
|
259
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-L_white.surf.ply
|
|
260
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-L_pial.surf.ply
|
|
261
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-R_white.surf.ply
|
|
262
|
+
sub-XXXX_ses-01_space-MNI152_desc-deform_hemi-R_pial.surf.ply
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Train (multi-GPU example)
|
|
266
|
+
```bash
|
|
267
|
+
scpp deform train --torchrun --nproc-per-node 2 outputs.root=/path/to/scpp-runs/deform/exp01
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Inference
|
|
271
|
+
```bash
|
|
272
|
+
scpp deform infer
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Evaluation
|
|
276
|
+
```bash
|
|
277
|
+
scpp deform eval
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Evaluation writes four Excel files:
|
|
281
|
+
- `surface_metrics.xlsx`
|
|
282
|
+
- `collision_metrics.xlsx`
|
|
283
|
+
- `collision_metrics_enhanced.xlsx`
|
|
284
|
+
- `collision_summary.xlsx`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Outputs Summary
|
|
289
|
+
|
|
290
|
+
For each dataset root:
|
|
291
|
+
|
|
292
|
+
- `derivatives/scpp-preproc-0.1/`
|
|
293
|
+
MNI T1, aparc+aseg, filled, transforms, and MNI-aligned FreeSurfer surfaces.
|
|
294
|
+
|
|
295
|
+
- `derivatives/scpp-seg-0.1/`
|
|
296
|
+
9-class segmentation predictions (`*_desc-seg9_dseg.nii.gz`).
|
|
297
|
+
|
|
298
|
+
- `derivatives/scpp-initsurf-0.1/`
|
|
299
|
+
Initial surfaces (`*.surf.ply`) + SDF volumes + ribbon SDF/probability.
|
|
300
|
+
|
|
301
|
+
- `derivatives/scpp-deform-0.1/`
|
|
302
|
+
Deformed surfaces (`*_desc-deform_*.surf.ply`).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
Add your license and citation details here if needed.
|