Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 440a876

Browse files
authored
Merge pull request #1 from flywheel-apps/dev
First iteration with gear-toolkit...With reviews
2 parents cd7d5bc + 771ff53 commit 440a876

File tree

8 files changed

+237
-0
lines changed

8 files changed

+237
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,4 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
.DS_Store

Dockerfile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Inheriting from established docker image:
2+
FROM poldracklab/pydeface:37-2e0c2d
3+
4+
# Inheriting from established docker image:
5+
LABEL maintainer="Flywheel <[email protected]>"
6+
7+
# Flywheel gears are run as root
8+
# poldracklab/pydeface:37-2e0c2d leaves it in the "neuro" user
9+
USER root
10+
11+
# For interactive docker... Not needed in gear execution
12+
RUN head -n 7 /neurodocker/startup.sh >> ~/.bashrc
13+
14+
ENV FLYWHEEL /flywheel/v0
15+
WORKDIR ${FLYWHEEL}
16+
17+
ENV PATH=/opt/conda/envs/neuro/bin/:$PATH
18+
COPY requirements.txt $FLYWHEEL/
19+
RUN pip install -r requirements.txt
20+
21+
# Copy executable, manifest, and tools to Gear
22+
COPY run.py manifest.json ${FLYWHEEL}/
23+
COPY utils ${FLYWHEEL}/utils
24+
RUN chmod a+x ${FLYWHEEL}/run.py
25+
26+
# Configure entrypoint
27+
ENTRYPOINT ["/flywheel/v0/run.py"]

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,28 @@
11
# pydeface-gear
2+
23
A flywheel gear to remove facial structure from MRI images.
4+
5+
Leverages [FSL](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FSL),
6+
[Python 3](https://www.python.org/downloads/),
7+
[NumPy](http://www.numpy.org/),
8+
[NiBabel](http://nipy.org/nibabel/), and
9+
[Nipype](http://nipype.readthedocs.io/en/latest/)
10+
to coregister a provided image to a template and removes facial features by removing the facial structure in accordance with the registration template and face mask. User may provide a template and face mask.
11+
12+
## Website
13+
14+
The source code of pydeface can be found at [github](https://github.com/poldracklab/pydeface)
15+
16+
## Usage Notes
17+
18+
### inputs
19+
20+
* infile (required): The NIfTI file to remove facial structure from
21+
* template (optional): The optional template image that will be used as the registration target instead of the default.
22+
* facemask (optional): The optional face mask image that will be used instead of the default.
23+
24+
### parameters
25+
26+
* cost: FSL-FLIRT cost function. "mutualinfo" default.
27+
* nocleanup: Do not cleanup temporary files. Off by default.
28+
* verbose: Show additional status prints. Off by default.

manifest.json

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"name": "pydeface-gear",
3+
"label": "Pydeface Gear",
4+
"description": "A gear to remove facial structure from MRI images.",
5+
"author": "Flywheel",
6+
"maintainer": "Flywheel <[email protected]>",
7+
"license": "MIT",
8+
"url": "https://github.com/flywheel-apps/test-gear",
9+
"source": "https://github.com/flywheel-apps/pydeface-gear",
10+
"cite": "https://github.com/poldracklab/pydeface",
11+
"version": "0.1.0",
12+
"custom": {
13+
"docker-image": "flywheel/pydeface-gear:0.1.0",
14+
"gear-builder": {
15+
"category": "analysis",
16+
"image": "flywheel/pydeface-gear:0.1.0"
17+
}
18+
},
19+
"inputs": {
20+
"infile": {
21+
"base": "file",
22+
"description": "input nifti",
23+
"optional": false,
24+
"type": {
25+
"enum": [
26+
"nifti"
27+
]
28+
}
29+
},
30+
"template": {
31+
"base": "file",
32+
"description": "Optional template image that will be used as the registration target instead of the default.",
33+
"optional": true,
34+
"type": {
35+
"enum": [
36+
"nifti"
37+
]
38+
}
39+
},
40+
"facemask": {
41+
"base": "file",
42+
"description": "Optional face mask image that will be used instead of the default.",
43+
"optional": true,
44+
"type": {
45+
"enum": [
46+
"nifti"
47+
]
48+
}
49+
}
50+
},
51+
"config": {
52+
"cost": {
53+
"type": "string",
54+
"default": "mutualinfo",
55+
"description": "FSL-FLIRT cost function",
56+
"enum": [
57+
"mutualinfo",
58+
"corratio",
59+
"normcorr",
60+
"normmi",
61+
"leastsq",
62+
"labeldiff",
63+
"bbr"
64+
]
65+
},
66+
"nocleanup": {
67+
"type": "boolean",
68+
"description": "Do not cleanup temporary files. True by default.",
69+
"default": "true"
70+
},
71+
"verbose": {
72+
"type": "boolean",
73+
"description": "Show additional status prints. True by default.",
74+
"default": "true"
75+
}
76+
},
77+
"command": "/flywheel/v0/run.py",
78+
"environment":{
79+
"CONDA_SHLVL": "1",
80+
"LC_ALL": "C.UTF-8",
81+
"CONDA_EXE": "/opt/conda/bin/conda",
82+
"FSLWISH": "/opt/fsl/bin/fslwish",
83+
"FSLDIR": "/opt/fsl",
84+
"LANG": "en_US.UTF-8",
85+
"HOSTNAME": "d8012530f084",
86+
"FSLMACHINELIST": "",
87+
"CONDA_PREFIX": "/opt/conda/envs/neuro",
88+
"CONDA_DIR": "/opt/conda",
89+
"FSLTCLSH": "/opt/fsl/bin/fsltclsh",
90+
"FSLREMOTECALL": "",
91+
"_CE_M": "",
92+
"PWD": "/flywheel/v0",
93+
"HOME": "/root",
94+
"CONDA_PYTHON_EXE": "/opt/conda/bin/python",
95+
"FSLLOCKDIR": "",
96+
"_CE_CONDA": "",
97+
"FLYWHEEL": "/flywheel/v0",
98+
"CONDA_PROMPT_MODIFIER": "(neuro) ",
99+
"FSLGECUDAQ": "cuda.q",
100+
"ND_ENTRYPOINT": "/neurodocker/startup.sh",
101+
"TERM": "xterm",
102+
"SHLVL": "1",
103+
"PATH": "/opt/conda/envs/neuro/bin:/opt/conda/condabin:/opt/conda/bin:/opt/fsl/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
104+
"CONDA_DEFAULT_ENV": "neuro",
105+
"FSLOUTPUTTYPE": "NIFTI_GZ",
106+
"FSLMULTIFILEQUIT": "TRUE",
107+
"_": "/opt/conda/envs/neuro/bin/python"
108+
}
109+
}

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flywheel-sdk==10.7.4
2+
flywheel-gear-toolkit==0.1.0.rc1

run.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import os.path as op
4+
import json
5+
import logging
6+
7+
from gear_toolkit import gear_toolkit_context
8+
from utils import args
9+
10+
11+
log = logging.getLogger(__name__)
12+
13+
14+
def main(context):
15+
# Build and Execute Parameters
16+
try:
17+
# build the command string
18+
params = args.build(context)
19+
20+
# Execute on those parameters.
21+
args.execute(context, params)
22+
23+
except Exception as e:
24+
context.log.exception(e)
25+
context.log.fatal('Error executing pydeface-gear.')
26+
return 1
27+
28+
context.log.info("pydeface-gear completed Successfully!")
29+
return 0
30+
31+
32+
if __name__ == '__main__':
33+
with gear_toolkit_context.GearToolkitContext() as gear_context:
34+
gear_context.init_logging()
35+
gear_context.log_config()
36+
exit_status = main(gear_context)
37+
38+
log.info('exit_status is %s', exit_status)
39+
os.sys.exit(exit_status)

utils/__init__.py

Whitespace-only changes.

utils/args.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from collections import OrderedDict
2+
import os.path as op
3+
from pathlib import Path
4+
5+
from gear_toolkit.command_line import build_command_list, exec_command
6+
7+
8+
def build(context):
9+
# use Ordered Dictionary to keep the order created.
10+
# Default in Python 3.6 onward
11+
params = OrderedDict()
12+
config = context.config
13+
for key in config.keys():
14+
params[key] = config[key]
15+
16+
infile = Path(context.get_input_path('infile'))
17+
18+
params['outfile'] = context.output_dir / \
19+
infile.name.replace('.nii.gz', '_defaced.nii.gz')
20+
return params
21+
22+
23+
def execute(context, params, dry_run=False):
24+
# Get Params
25+
command = ['pydeface']
26+
27+
# Build command-line parameters
28+
command = build_command_list(command, params)
29+
30+
# Extend with positional argument
31+
command.append(context.get_input_path('infile'))
32+
33+
exec_command(command, dry_run=dry_run)

0 commit comments

Comments
 (0)