caideface 0.1.3__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.
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025-present cai4cai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: caideface
3
+ Version: 0.1.3
4
+ Summary: MRI defacing pipeline with skull-stripping and affine registration from cai4cai
5
+ Author-email: Lorena Garcia-Foncillas <lorenagarfon00@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/LorenaGarcia-Foncillas/caideface
8
+ Project-URL: Repository, https://github.com/LorenaGarcia-Foncillas/caideface
9
+ Keywords: MRI,defacing,anonymisation,skull-stripping,neuroimaging
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE.md
17
+ Requires-Dist: nibabel>=4.0
18
+ Requires-Dist: numpy<2,>=1.22
19
+ Requires-Dist: scipy>=1.9
20
+ Requires-Dist: SimpleITK>=2.2
21
+ Requires-Dist: pandas>=1.5
22
+ Requires-Dist: natsort>=8.0
23
+ Requires-Dist: tqdm>=4.60
24
+ Requires-Dist: hd-bet
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest; extra == "dev"
27
+ Requires-Dist: ruff; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # caideface
31
+
32
+ **MRI defacing pipeline with skull-stripping and affine registration** from the [cai4cai](https://cai4cai.ml/) research group (Contextual Artificial Intelligence for Computer Assisted Interventions).
33
+
34
+ This pipeline anonymises head MRI scans by removing facial features while preserving brain structures, as described in the paper *"A Generalisable Head MRI Defacing Pipeline: Evaluation on 2,566 Meningioma Scans"* ([arXiv:2505.12999](https://arxiv.org/abs/2505.12999)).
35
+
36
+ ## Pipeline overview
37
+
38
+ The pipeline consists of three steps:
39
+
40
+ 1. **Reorientation** -- Aligns NIfTI scans to LAS canonical orientation (MNI152 standard) using nibabel.
41
+ 2. **Skull-stripping** -- Extracts brain masks using [HD-BET](https://github.com/MIC-DKFZ/HD-BET), then applies dynamic dilation to preserve peripheral brain structures.
42
+ 3. **Registration & Defacing** -- Registers each scan to the MNI152 template using BRAINSFit (affine), warps a face mask into the scan's space, and applies it to remove facial features.
43
+
44
+ The MNI152 skull-stripped template and face mask are **bundled with the package**, so no additional downloads are needed.
45
+
46
+ ## Requirements
47
+
48
+ ### Python
49
+
50
+ - Python >= 3.9
51
+
52
+ ### External tools (not pip-installable)
53
+
54
+ | Tool | Used in | Install |
55
+ |------|---------|---------|
56
+ | **BRAINSFit** & **BRAINSResample** | Step 3 | Bundled with [3D Slicer](https://www.slicer.org/) |
57
+
58
+ > **Note:** Step 1 (reorientation) no longer requires FSL -- it uses nibabel's orientation tools to reorient scans to LAS (equivalent to `fslreorient2std`).
59
+
60
+ #### Finding BRAINSFit and BRAINSResample
61
+
62
+ These executables are included with 3D Slicer. Common locations:
63
+
64
+ - **macOS**: `/Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit`
65
+ - **Linux**: `/path/to/Slicer/lib/Slicer-5.8/cli-modules/BRAINSFit`
66
+
67
+ Replace `5.8` with your installed Slicer version if different. To verify the executables are found and working:
68
+
69
+ ```bash
70
+ # Check they exist
71
+ ls /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit
72
+ ls /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSResample
73
+
74
+ # Check they run (should print usage/help info)
75
+ /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit --help
76
+ /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSResample --help
77
+ ```
78
+
79
+ You can also build them from source via [BRAINSTools](https://github.com/BRAINSia/BRAINSTools).
80
+
81
+ ## Installation
82
+
83
+ We recommend using a conda environment:
84
+
85
+ ```bash
86
+ conda create -n caideface python=3.10 -y
87
+ conda activate caideface
88
+ pip install caideface
89
+ ```
90
+
91
+ Or install from source:
92
+
93
+ ```bash
94
+ git clone https://github.com/cai4cai/caideface.git
95
+ cd caideface
96
+ pip install -e .
97
+ ```
98
+
99
+ > **Note:** caideface requires `numpy<2` (enforced automatically). Some dependencies (HD-BET / nnU-Net) are not yet compatible with NumPy 2.x.
100
+
101
+ ## Usage
102
+
103
+ ### CLI -- Full pipeline
104
+
105
+ Run all three steps in one command:
106
+
107
+ ```bash
108
+ caideface run ./input_nifti ./output \
109
+ --brainsfit /path/to/BRAINSFit \
110
+ --brainsresample /path/to/BRAINSResample
111
+ ```
112
+
113
+ This creates three subdirectories under `./output`:
114
+ - `reoriented/` -- Step 1 outputs
115
+ - `hdbet/` -- Step 2 outputs (skull-stripped, masks, dilated)
116
+ - `defaced/` -- Step 3 outputs (final defaced scans)
117
+
118
+ #### Options
119
+
120
+ | Flag | Default | Description |
121
+ |------|---------|-------------|
122
+ | `--device` | auto-detected | `cpu` or `cuda` for HD-BET |
123
+ | `--no-tta` | on | Disable HD-BET test-time augmentation (faster but less accurate) |
124
+ | `--dilation-mm` | `14.0` | Brain mask dilation in mm |
125
+ | `--background` | `0` | Fill value for defaced regions (0 for MRI, -1024 for CT) |
126
+ | `--template` | bundled | Custom MNI152 skull-stripped template |
127
+ | `--face-mask` | bundled | Custom face mask in MNI152 space |
128
+ | `--steps` | `all` | Run specific steps: `reorient`, `skull_strip`, `deface` (comma-separated) |
129
+ | `-v` | off | Verbose/debug logging |
130
+
131
+ ### CLI -- Individual steps
132
+
133
+ Run each step separately for more control:
134
+
135
+ ```bash
136
+ # Step 1: Reorientation
137
+ caideface reorient ./raw_nifti ./reoriented
138
+
139
+ # Step 2: Skull-stripping
140
+ caideface skull-strip ./reoriented ./hdbet --device cpu
141
+
142
+ # Step 3: Registration & Defacing
143
+ caideface deface ./reoriented ./hdbet ./defaced \
144
+ --brainsfit /path/to/BRAINSFit \
145
+ --brainsresample /path/to/BRAINSResample
146
+ ```
147
+
148
+ ## Output structure
149
+
150
+ ```
151
+ output/
152
+ ├── reoriented/
153
+ │ ├── reorientation_log.csv
154
+ │ └── <subject>/<scan>.nii.gz
155
+ ├── hdbet/
156
+ │ ├── hd_bet_log.csv
157
+ │ └── <subject>/
158
+ │ ├── hd_bet_<scan>.nii.gz # Skull-stripped
159
+ │ ├── hd_bet_mask_<scan>.nii.gz # Dilated brain mask
160
+ │ └── hd_bet_dilated_<scan>.nii.gz # Dilated skull-stripped
161
+ └── defaced/
162
+ ├── not_defaced_scans.csv # Only if failures occurred
163
+ └── <subject>/
164
+ └── hd_bet_dilated_<scan>_masked.nii.gz # Final defaced scan
165
+ ```
166
+
167
+ ## Existing transforms
168
+
169
+ If you have pre-computed registration transforms (e.g. from 3D Slicer), place a file named `Transform_to_template.txt` in the same directory as the dilated skull-stripped scan. The pipeline will use it instead of running BRAINSFit. Both plain 4x4 text matrices and ITK/Slicer transform formats are supported.
170
+
171
+ ## Citation
172
+
173
+ If you use this tool, please cite:
174
+
175
+ ```bibtex
176
+ @article{caideface2025,
177
+ title={A Generalisable Head MRI Defacing Pipeline: Evaluation on 2,566 Meningioma Scans},
178
+ year={2025},
179
+ url={https://arxiv.org/abs/2505.12999}
180
+ }
181
+ ```
182
+
183
+ If you use HD-BET (skull-stripping, Step 2), please also cite:
184
+
185
+ ```bibtex
186
+ @article{Isensee2019,
187
+ author={Isensee, F. and Schell, M. and Tursunova, I. and Brugnara, G. and Bonekamp, D. and Neuberger, U. and Wick, A. and Schlemmer, H. P. and Heiland, S. and Wick, W. and Bendszus, M. and Maier-Hein, K. H. and Kickingereder, P.},
188
+ title={Automated brain extraction of multi-sequence MRI using artificial neural networks},
189
+ journal={Human Brain Mapping},
190
+ year={2019},
191
+ pages={1--13},
192
+ doi={10.1002/hbm.24750}
193
+ }
194
+ ```
195
+
196
+ ## License
197
+
198
+ This project is licensed under the MIT License -- see the [LICENSE](LICENSE.md) file for details.
@@ -0,0 +1,169 @@
1
+ # caideface
2
+
3
+ **MRI defacing pipeline with skull-stripping and affine registration** from the [cai4cai](https://cai4cai.ml/) research group (Contextual Artificial Intelligence for Computer Assisted Interventions).
4
+
5
+ This pipeline anonymises head MRI scans by removing facial features while preserving brain structures, as described in the paper *"A Generalisable Head MRI Defacing Pipeline: Evaluation on 2,566 Meningioma Scans"* ([arXiv:2505.12999](https://arxiv.org/abs/2505.12999)).
6
+
7
+ ## Pipeline overview
8
+
9
+ The pipeline consists of three steps:
10
+
11
+ 1. **Reorientation** -- Aligns NIfTI scans to LAS canonical orientation (MNI152 standard) using nibabel.
12
+ 2. **Skull-stripping** -- Extracts brain masks using [HD-BET](https://github.com/MIC-DKFZ/HD-BET), then applies dynamic dilation to preserve peripheral brain structures.
13
+ 3. **Registration & Defacing** -- Registers each scan to the MNI152 template using BRAINSFit (affine), warps a face mask into the scan's space, and applies it to remove facial features.
14
+
15
+ The MNI152 skull-stripped template and face mask are **bundled with the package**, so no additional downloads are needed.
16
+
17
+ ## Requirements
18
+
19
+ ### Python
20
+
21
+ - Python >= 3.9
22
+
23
+ ### External tools (not pip-installable)
24
+
25
+ | Tool | Used in | Install |
26
+ |------|---------|---------|
27
+ | **BRAINSFit** & **BRAINSResample** | Step 3 | Bundled with [3D Slicer](https://www.slicer.org/) |
28
+
29
+ > **Note:** Step 1 (reorientation) no longer requires FSL -- it uses nibabel's orientation tools to reorient scans to LAS (equivalent to `fslreorient2std`).
30
+
31
+ #### Finding BRAINSFit and BRAINSResample
32
+
33
+ These executables are included with 3D Slicer. Common locations:
34
+
35
+ - **macOS**: `/Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit`
36
+ - **Linux**: `/path/to/Slicer/lib/Slicer-5.8/cli-modules/BRAINSFit`
37
+
38
+ Replace `5.8` with your installed Slicer version if different. To verify the executables are found and working:
39
+
40
+ ```bash
41
+ # Check they exist
42
+ ls /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit
43
+ ls /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSResample
44
+
45
+ # Check they run (should print usage/help info)
46
+ /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSFit --help
47
+ /Applications/Slicer.app/Contents/lib/Slicer-5.8/cli-modules/BRAINSResample --help
48
+ ```
49
+
50
+ You can also build them from source via [BRAINSTools](https://github.com/BRAINSia/BRAINSTools).
51
+
52
+ ## Installation
53
+
54
+ We recommend using a conda environment:
55
+
56
+ ```bash
57
+ conda create -n caideface python=3.10 -y
58
+ conda activate caideface
59
+ pip install caideface
60
+ ```
61
+
62
+ Or install from source:
63
+
64
+ ```bash
65
+ git clone https://github.com/cai4cai/caideface.git
66
+ cd caideface
67
+ pip install -e .
68
+ ```
69
+
70
+ > **Note:** caideface requires `numpy<2` (enforced automatically). Some dependencies (HD-BET / nnU-Net) are not yet compatible with NumPy 2.x.
71
+
72
+ ## Usage
73
+
74
+ ### CLI -- Full pipeline
75
+
76
+ Run all three steps in one command:
77
+
78
+ ```bash
79
+ caideface run ./input_nifti ./output \
80
+ --brainsfit /path/to/BRAINSFit \
81
+ --brainsresample /path/to/BRAINSResample
82
+ ```
83
+
84
+ This creates three subdirectories under `./output`:
85
+ - `reoriented/` -- Step 1 outputs
86
+ - `hdbet/` -- Step 2 outputs (skull-stripped, masks, dilated)
87
+ - `defaced/` -- Step 3 outputs (final defaced scans)
88
+
89
+ #### Options
90
+
91
+ | Flag | Default | Description |
92
+ |------|---------|-------------|
93
+ | `--device` | auto-detected | `cpu` or `cuda` for HD-BET |
94
+ | `--no-tta` | on | Disable HD-BET test-time augmentation (faster but less accurate) |
95
+ | `--dilation-mm` | `14.0` | Brain mask dilation in mm |
96
+ | `--background` | `0` | Fill value for defaced regions (0 for MRI, -1024 for CT) |
97
+ | `--template` | bundled | Custom MNI152 skull-stripped template |
98
+ | `--face-mask` | bundled | Custom face mask in MNI152 space |
99
+ | `--steps` | `all` | Run specific steps: `reorient`, `skull_strip`, `deface` (comma-separated) |
100
+ | `-v` | off | Verbose/debug logging |
101
+
102
+ ### CLI -- Individual steps
103
+
104
+ Run each step separately for more control:
105
+
106
+ ```bash
107
+ # Step 1: Reorientation
108
+ caideface reorient ./raw_nifti ./reoriented
109
+
110
+ # Step 2: Skull-stripping
111
+ caideface skull-strip ./reoriented ./hdbet --device cpu
112
+
113
+ # Step 3: Registration & Defacing
114
+ caideface deface ./reoriented ./hdbet ./defaced \
115
+ --brainsfit /path/to/BRAINSFit \
116
+ --brainsresample /path/to/BRAINSResample
117
+ ```
118
+
119
+ ## Output structure
120
+
121
+ ```
122
+ output/
123
+ ├── reoriented/
124
+ │ ├── reorientation_log.csv
125
+ │ └── <subject>/<scan>.nii.gz
126
+ ├── hdbet/
127
+ │ ├── hd_bet_log.csv
128
+ │ └── <subject>/
129
+ │ ├── hd_bet_<scan>.nii.gz # Skull-stripped
130
+ │ ├── hd_bet_mask_<scan>.nii.gz # Dilated brain mask
131
+ │ └── hd_bet_dilated_<scan>.nii.gz # Dilated skull-stripped
132
+ └── defaced/
133
+ ├── not_defaced_scans.csv # Only if failures occurred
134
+ └── <subject>/
135
+ └── hd_bet_dilated_<scan>_masked.nii.gz # Final defaced scan
136
+ ```
137
+
138
+ ## Existing transforms
139
+
140
+ If you have pre-computed registration transforms (e.g. from 3D Slicer), place a file named `Transform_to_template.txt` in the same directory as the dilated skull-stripped scan. The pipeline will use it instead of running BRAINSFit. Both plain 4x4 text matrices and ITK/Slicer transform formats are supported.
141
+
142
+ ## Citation
143
+
144
+ If you use this tool, please cite:
145
+
146
+ ```bibtex
147
+ @article{caideface2025,
148
+ title={A Generalisable Head MRI Defacing Pipeline: Evaluation on 2,566 Meningioma Scans},
149
+ year={2025},
150
+ url={https://arxiv.org/abs/2505.12999}
151
+ }
152
+ ```
153
+
154
+ If you use HD-BET (skull-stripping, Step 2), please also cite:
155
+
156
+ ```bibtex
157
+ @article{Isensee2019,
158
+ author={Isensee, F. and Schell, M. and Tursunova, I. and Brugnara, G. and Bonekamp, D. and Neuberger, U. and Wick, A. and Schlemmer, H. P. and Heiland, S. and Wick, W. and Bendszus, M. and Maier-Hein, K. H. and Kickingereder, P.},
159
+ title={Automated brain extraction of multi-sequence MRI using artificial neural networks},
160
+ journal={Human Brain Mapping},
161
+ year={2019},
162
+ pages={1--13},
163
+ doi={10.1002/hbm.24750}
164
+ }
165
+ ```
166
+
167
+ ## License
168
+
169
+ This project is licensed under the MIT License -- see the [LICENSE](LICENSE.md) file for details.
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "caideface"
7
+ version = "0.1.3"
8
+ description = "MRI defacing pipeline with skull-stripping and affine registration from cai4cai"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Lorena Garcia-Foncillas", email = "lorenagarfon00@gmail.com"},
14
+ ]
15
+ keywords = ["MRI", "defacing", "anonymisation", "skull-stripping", "neuroimaging"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Science/Research",
19
+
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Scientific/Engineering :: Medical Science Apps.",
22
+ ]
23
+ dependencies = [
24
+ "nibabel>=4.0",
25
+ "numpy>=1.22,<2",
26
+ "scipy>=1.9",
27
+ "SimpleITK>=2.2",
28
+ "pandas>=1.5",
29
+ "natsort>=8.0",
30
+ "tqdm>=4.60",
31
+ "hd-bet",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest",
37
+ "ruff",
38
+ ]
39
+
40
+ [project.scripts]
41
+ caideface = "caideface.cli:main"
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/LorenaGarcia-Foncillas/caideface"
45
+ Repository = "https://github.com/LorenaGarcia-Foncillas/caideface"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
49
+
50
+ [tool.setuptools.package-data]
51
+ caideface = ["data/*.nii.gz"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,24 @@
1
+ """caideface - MRI defacing pipeline from cai4cai.
2
+
3
+ A three-step pipeline for anonymising head MRI scans:
4
+ 1. Reorientation to MNI152 atlas reference (nibabel)
5
+ 2. Skull-stripping with HD-BET and dynamic dilation
6
+ 3. Affine registration and defacing (BRAINSFit)
7
+ """
8
+
9
+ __version__ = "0.1.3"
10
+
11
+ from .pipeline import DefacePipeline
12
+ from .reorient import reorient_batch, reorient_single
13
+ from .skull_strip import skull_strip_batch, skull_strip_single
14
+ from .register import deface_batch, deface_single
15
+
16
+ __all__ = [
17
+ "DefacePipeline",
18
+ "reorient_batch",
19
+ "reorient_single",
20
+ "skull_strip_batch",
21
+ "skull_strip_single",
22
+ "deface_batch",
23
+ "deface_single",
24
+ ]
@@ -0,0 +1,127 @@
1
+ """Command-line interface for caideface."""
2
+
3
+ import argparse
4
+ import logging
5
+ import sys
6
+
7
+ from .pipeline import DefacePipeline
8
+ from .reorient import reorient_batch
9
+ from .skull_strip import skull_strip_batch, get_default_device
10
+ from .register import deface_batch
11
+
12
+
13
+ def _setup_logging(verbose: bool):
14
+ level = logging.DEBUG if verbose else logging.INFO
15
+ logging.basicConfig(
16
+ level=level,
17
+ format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
18
+ datefmt="%H:%M:%S",
19
+ )
20
+
21
+
22
+ def main():
23
+ # Shared parent so -v works on any subcommand
24
+ parent = argparse.ArgumentParser(add_help=False)
25
+ parent.add_argument("-v", "--verbose", action="store_true", help="Enable debug logging")
26
+
27
+ parser = argparse.ArgumentParser(
28
+ prog="caideface",
29
+ description="MRI defacing pipeline from cai4cai: reorientation, skull-stripping, and affine-based defacing.",
30
+ parents=[parent],
31
+ )
32
+
33
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
34
+
35
+ # --- run: full pipeline ---
36
+ run_parser = subparsers.add_parser("run", help="Run the full defacing pipeline", parents=[parent])
37
+ run_parser.add_argument("input_dir", help="Directory containing raw NIfTI files")
38
+ run_parser.add_argument("output_dir", help="Root output directory")
39
+ run_parser.add_argument("--brainsfit", required=True, help="Path to BRAINSFit executable")
40
+ run_parser.add_argument("--brainsresample", required=True, help="Path to BRAINSResample executable")
41
+ run_parser.add_argument("--device", default=None, choices=["cpu", "cuda"], help="Device for HD-BET (auto-detected if omitted)")
42
+ run_parser.add_argument("--no-tta", action="store_true", default=True, help="Disable HD-BET test-time augmentation (default: disabled)")
43
+ run_parser.add_argument("--dilation-mm", type=float, default=14.0, help="Brain mask dilation in mm (default: 14)")
44
+ run_parser.add_argument("--background", type=float, default=0, help="Background value for defaced voxels (default: 0 for MRI, use -1024 for CT)")
45
+ run_parser.add_argument("--template", default=None, help="Custom MNI152 skull-stripped template (uses bundled if omitted)")
46
+ run_parser.add_argument("--face-mask", default=None, help="Custom face mask in MNI152 space (uses bundled if omitted)")
47
+ run_parser.add_argument("--steps", default="all", help="Steps to run: all, or comma-separated: reorient,skull_strip,deface")
48
+
49
+ # --- reorient ---
50
+ reorient_parser = subparsers.add_parser("reorient", help="Step 1: Reorient NIfTI scans to MNI152", parents=[parent])
51
+ reorient_parser.add_argument("input_dir", help="Directory with NIfTI files")
52
+ reorient_parser.add_argument("output_dir", help="Output directory for reoriented files")
53
+
54
+ # --- skull-strip ---
55
+ ss_parser = subparsers.add_parser("skull-strip", help="Step 2: Skull-strip with HD-BET", parents=[parent])
56
+ ss_parser.add_argument("input_dir", help="Directory with reoriented NIfTI files")
57
+ ss_parser.add_argument("output_dir", help="Output directory for HD-BET results")
58
+ ss_parser.add_argument("--device", default=None, choices=["cpu", "cuda"], help="Device for HD-BET")
59
+ ss_parser.add_argument("--no-tta", action="store_true", default=True, help="Disable test-time augmentation")
60
+ ss_parser.add_argument("--dilation-mm", type=float, default=14.0, help="Dilation in mm")
61
+
62
+ # --- deface ---
63
+ deface_parser = subparsers.add_parser("deface", help="Step 3: Register and deface", parents=[parent])
64
+ deface_parser.add_argument("reoriented_dir", help="Directory with reoriented scans (Step 1 output)")
65
+ deface_parser.add_argument("hdbet_dir", help="Directory with HD-BET results (Step 2 output)")
66
+ deface_parser.add_argument("output_dir", help="Output directory for defaced scans")
67
+ deface_parser.add_argument("--brainsfit", required=True, help="Path to BRAINSFit executable")
68
+ deface_parser.add_argument("--brainsresample", required=True, help="Path to BRAINSResample executable")
69
+ deface_parser.add_argument("--template", default=None, help="Custom MNI152 skull-stripped template")
70
+ deface_parser.add_argument("--face-mask", default=None, help="Custom face mask in MNI152 space")
71
+ deface_parser.add_argument("--background", type=float, default=0, help="Background value (default: 0 for MRI, use -1024 for CT)")
72
+
73
+ args = parser.parse_args()
74
+
75
+ if not args.command:
76
+ parser.print_help()
77
+ sys.exit(1)
78
+
79
+ _setup_logging(args.verbose)
80
+
81
+ if args.command == "run":
82
+ pipeline = DefacePipeline(
83
+ brainsfit_path=args.brainsfit,
84
+ brainsresample_path=args.brainsresample,
85
+ device=args.device,
86
+ disable_tta=args.no_tta,
87
+ desired_dilation_mm=args.dilation_mm,
88
+ background_value=args.background,
89
+ target_path=args.template,
90
+ face_mask_path=args.face_mask,
91
+ )
92
+ results = pipeline.run(args.input_dir, args.output_dir, steps=args.steps)
93
+ failed = results.get("failed_defacing", [])
94
+ if failed:
95
+ print(f"\n{len(failed)} scan(s) failed to deface. See output log for details.")
96
+ sys.exit(1)
97
+
98
+ elif args.command == "reorient":
99
+ reorient_batch(args.input_dir, args.output_dir)
100
+
101
+ elif args.command == "skull-strip":
102
+ skull_strip_batch(
103
+ args.input_dir,
104
+ args.output_dir,
105
+ device=args.device,
106
+ disable_tta=args.no_tta,
107
+ desired_dilation_mm=args.dilation_mm,
108
+ )
109
+
110
+ elif args.command == "deface":
111
+ failed = deface_batch(
112
+ reoriented_dir=args.reoriented_dir,
113
+ hdbet_dir=args.hdbet_dir,
114
+ output_dir=args.output_dir,
115
+ brainsfit_path=args.brainsfit,
116
+ brainsresample_path=args.brainsresample,
117
+ target_path=args.template,
118
+ face_mask_path=args.face_mask,
119
+ background_value=args.background,
120
+ )
121
+ if failed:
122
+ print(f"\n{len(failed)} scan(s) failed. See output log.")
123
+ sys.exit(1)
124
+
125
+
126
+ if __name__ == "__main__":
127
+ main()