Skip to content

Commit 22f3daf

Browse files
committed
updated to be more bids-app like
1 parent 5779123 commit 22f3daf

File tree

3 files changed

+80
-75
lines changed

3 files changed

+80
-75
lines changed

README.md

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,43 @@ This software can be installed via source or via pip from PyPi with `pip install
3535
**_NOTE:_** This project is currently in beta release, some features listed below may not be available for version numbers < 1.0.0
3636

3737
```bash
38-
usage: petdeface.py [-h] [--output_dir OUTPUT_DIR] [--anat_only]
39-
[--subject SUBJECT] [--session SESSION] [--docker]
40-
[--singularity] [--n_procs N_PROCS] [--skip_bids_validator]
41-
[--version] [--placement PLACEMENT] [--remove_existing]
42-
[--excludesubject] input_dir
38+
usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics]
39+
[--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]]
40+
bids_dir [output_dir] [analysis_level]
4341

4442
PetDeface
4543

4644
positional arguments:
47-
input_dir The directory with the input dataset
45+
bids_dir The directory with the input dataset
46+
output_dir The directory where the output files should be stored, if not supplied will default to <bids_dir>/derivatives/petdeface
47+
analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis
4848

4949
options:
5050
-h, --help show this help message and exit
51-
--output_dir OUTPUT_DIR, -o OUTPUT_DIR
52-
The directory where the output files should be stored
5351
--anat_only, -a Only deface anatomical images
54-
--subject SUBJECT, -s SUBJECT
55-
The label of the subject to be processed.
52+
--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]
53+
The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces.
5654
--session SESSION, -ses SESSION
5755
The label of the session to be processed.
5856
--docker, -d Run in docker container
5957
--singularity, -si Run in singularity container
6058
--n_procs N_PROCS Number of processors to use when running the workflow
6159
--skip_bids_validator
62-
--version, -v show programs version number and exit
60+
--version, -v show program's version number and exit
6361
--placement PLACEMENT, -p PLACEMENT
64-
Where to place the defaced images. Options are
65-
'adjacent': next to the input_dir (default) in a folder appended with _defaced
66-
'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images
67-
w/ defaced at input_dir
68-
'derivatives': does all of the defacing within the derivatives folder in input_dir.
69-
--remove_existing, -r Remove existing output files in output_dir.
70-
--excludesubject EXCLUDESUBJECT [EXCLUDESUBJECT ...]
71-
Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02
62+
Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the
63+
defacing within the derivatives folder in bids_dir.
64+
--remove_existing, -r
65+
Remove existing output files in output_dir.
66+
--preview_pics Create preview pictures of defacing, defaults to false for docker
67+
--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]
68+
Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02
7269
```
7370
7471
Working example usage:
7572
7673
```bash
77-
petdeface /inputfolder --output_dir /outputfolder --n_procs 16 --skip_bids_validator --placement adjacent
74+
petdeface /inputfolder /outputfolder --n_procs 16 --skip_bids_validator --placement adjacent
7875
```
7976
8077
### Docker Usage
@@ -107,7 +104,7 @@ docker run --user=$UID:$GID -a stderr -a stdout --rm \
107104
-v /Data/defaced_pet_data/:/output \
108105
-v /home/freesurfer/license.txt:/opt/freesurfer/license.txt \
109106
--platform linux/amd64 \
110-
petdeface:latest /input --output_dir /output --n_procs 16 --skip_bids_validator --placement adjacent --user=$UID:$GID system_platform=Linux
107+
petdeface:latest /input /output --n_procs 16 --skip_bids_validator --placement adjacent --user=$UID:$GID system_platform=Linux
111108
```
112109
113110
### Singularity Usage
@@ -127,7 +124,7 @@ Otherwise, one can run and execute petdeface with the same syntax as calling it
127124
with `singularity exec -e`
128125

129126
```bash
130-
singularity exec -e --bind license.txt:/opt/freesurfer/license.txt docker://openneuropet/petdeface:0.1.1 petdeface /input --output-dir /output --n_procs 10
127+
singularity exec -e --bind license.txt:/opt/freesurfer/license.txt docker://openneuropet/petdeface:0.1.1 petdeface /input /output --n_procs 10
131128
```
132129

133130
**_NOTE_**: Testing with singularity has been limited to version singularity-ce 4.2.0, please let us know in the issues section of this repo if you have

docs/usage.rst

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,40 +81,42 @@ When viewed, a succesfully defaced PET image will have varying intensities in th
8181

8282
The number of processors made available to PETdeface can be set by the `--n_procs` flag e.g.::
8383

84-
petdeface /inputfolder --output_dir /outputfolder --n_procs 4
84+
petdeface /inputfolder /outputfolder --n_procs 4
8585

8686
Additional options can be found in the help menu::
8787

8888
petdeface -h
89-
usage: petdeface [-h] [--output_dir OUTPUT_DIR] [--anat_only] [--subject SUBJECT] [--session SESSION] [--docker] [--n_procs N_PROCS] [--skip_bids_validator] [--version]
90-
[--placement PLACEMENT] [--remove_existing]
91-
input_dir
89+
usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics]
90+
[--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]]
91+
bids_dir [output_dir] [analysis_level]
9292

9393
PetDeface
9494

9595
positional arguments:
96-
input_dir The directory with the input dataset
96+
bids_dir The directory with the input dataset
97+
output_dir The directory where the output files should be stored, if not supplied will default to <bids_dir>/derivatives/petdeface
98+
analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis
9799

98100
options:
99101
-h, --help show this help message and exit
100-
--output_dir OUTPUT_DIR, -o OUTPUT_DIR
101-
The directory where the output files should be stored
102102
--anat_only, -a Only deface anatomical images
103-
--subject SUBJECT, -s SUBJECT
104-
The label of the subject to be processed.
103+
--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]
104+
The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces.
105105
--session SESSION, -ses SESSION
106106
The label of the session to be processed.
107107
--docker, -d Run in docker container
108+
--singularity, -si Run in singularity container
108109
--n_procs N_PROCS Number of processors to use when running the workflow
109110
--skip_bids_validator
110111
--version, -v show program's version number and exit
111112
--placement PLACEMENT, -p PLACEMENT
112-
Where to place the defaced images. Options are 'adjacent': next to the input_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place,
113-
e.g. replaces faced PET and T1w images w/ defaced at input_dir'derivatives': does all of the defacing within the derivatives folder in input_dir.
113+
Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the
114+
defacing within the derivatives folder in bids_dir.
114115
--remove_existing, -r
115116
Remove existing output files in output_dir.
116-
--excludesubject EXCLUDESUBJECT [EXCLUDESUBJECT ...]
117-
Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02
117+
--preview_pics Create preview pictures of defacing, defaults to false for docker
118+
--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]
119+
Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02
118120

119121
Docker Based
120122
------------

petdeface/petdeface.py

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ def deface(args: Union[dict, argparse.Namespace]) -> None:
223223
if not check_valid_fs_license() and not locate_freesurfer_license().exists():
224224
raise Exception("You need a valid FreeSurfer license to proceed!")
225225

226-
if args.subject:
227-
subjects = args.subject
226+
if args.participant_label:
227+
subjects = args.participant_label
228228
# if subject contains the string sub-, remove it to avoid redundancy as pybids will add it uses the
229229
# right side of the sub- string as the subject label
230230
if any("sub-" in subject for subject in subjects):
@@ -247,15 +247,15 @@ def deface(args: Union[dict, argparse.Namespace]) -> None:
247247
)
248248

249249
# check to see if any subjects are excluded from the defacing workflow
250-
if args.excludesubject != []:
250+
if args.excludeparticipant != []:
251251
print(
252-
f"Removing the following subjects {args.excludesubject} from the defacing workflow"
252+
f"Removing the following subjects {args.excludeparticipant} from the defacing workflow"
253253
)
254-
args.excludesubject = [
255-
subject.replace("sub-", "") for subject in args.excludesubject
254+
args.excludeparticipant = [
255+
subject.replace("sub-", "") for subject in args.excludeparticipant
256256
]
257257
subjects = [
258-
subject for subject in subjects if subject not in args.excludesubject
258+
subject for subject in subjects if subject not in args.excludeparticipant
259259
]
260260

261261
print(f"Subjects remaining in the defacing workflow: {subjects}")
@@ -540,7 +540,7 @@ def wrap_up_defacing(
540540
:param path_to_dataset: Path to original dataset
541541
:type path_to_dataset: path like object (str or pathlib.Path)
542542
:param output_dir: Specific directory to place output, arguably redundant given placemnent, defaults to
543-
input_dir/derivatives/petdeface
543+
bids_dir/derivatives/petdeface
544544
:type output_dir: path like object (str or pathlib.Path), optional
545545
:param placement: str, optional
546546
Can be one of three values
@@ -726,7 +726,7 @@ def __init__(
726726
remove_existing=True, # TODO: currently not implemented
727727
placement="adjacent", # TODO: currently not implemented
728728
preview_pics=True,
729-
excludesubject=[],
729+
excludeparticipant=[],
730730
):
731731
self.bids_dir = bids_dir
732732
self.remove_existing = remove_existing
@@ -738,7 +738,7 @@ def __init__(
738738
self.n_procs = n_procs
739739
self.skip_bids_validator = skip_bids_validator
740740
self.preview_pics = preview_pics
741-
self.excludesubject = excludesubject
741+
self.excludeparticipant = excludeparticipant
742742

743743
# check if freesurfer license is valid
744744
self.fs_license = check_valid_fs_license()
@@ -767,7 +767,7 @@ def run(self):
767767
"placement": self.placement,
768768
"remove_existing": self.remove_existing,
769769
"preview_pics": self.preview_pics,
770-
"excludesubject": self.excludesubject,
770+
"excludeparticipant": self.excludeparticipant,
771771
}
772772
)
773773
wrap_up_defacing(
@@ -785,16 +785,22 @@ def cli():
785785
parser = argparse.ArgumentParser(description="PetDeface")
786786

787787
parser.add_argument(
788-
"input_dir", help="The directory with the input dataset", type=pathlib.Path
788+
"bids_dir", help="The directory with the input dataset", type=pathlib.Path
789789
)
790790
parser.add_argument(
791-
"--output_dir",
792-
"-o",
793-
help="The directory where the output files should be stored",
791+
"output_dir",
792+
nargs="?",
793+
help="The directory where the output files should be stored, if not supplied will default to <bids_dir>/derivatives/petdeface",
794794
type=pathlib.Path,
795-
required=False,
796795
default=None,
797796
)
797+
parser.add_argument(
798+
'analysis_level',
799+
nargs='?',
800+
default='participant',
801+
help="This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as "
802+
"a participant level analysis",
803+
)
798804
parser.add_argument(
799805
"--anat_only",
800806
"-a",
@@ -803,9 +809,9 @@ def cli():
803809
help="Only deface anatomical images",
804810
)
805811
parser.add_argument(
806-
"--subject",
807-
"-s",
808-
help="The label of the subject to be processed.",
812+
"--participant_label",
813+
"-pl",
814+
help="The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces.",
809815
type=str,
810816
nargs="+",
811817
required=False,
@@ -849,9 +855,9 @@ def cli():
849855
"--placement",
850856
"-p",
851857
help="Where to place the defaced images. Options are "
852-
"'adjacent': next to the input_dir (default) in a folder appended with _defaced"
853-
"'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at input_dir"
854-
"'derivatives': does all of the defacing within the derivatives folder in input_dir.",
858+
"'adjacent': next to the bids_dir (default) in a folder appended with _defaced"
859+
"'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir"
860+
"'derivatives': does all of the defacing within the derivatives folder in bids_dir.",
855861
type=str,
856862
required=False,
857863
default="adjacent",
@@ -870,8 +876,8 @@ def cli():
870876
default=False,
871877
)
872878
parser.add_argument(
873-
"--excludesubject",
874-
help="Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02",
879+
"--excludeparticipant",
880+
help="Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02",
875881
type=str,
876882
nargs="+",
877883
required=False,
@@ -900,10 +906,10 @@ def main(): # noqa: max-complexity: 12
900906

901907
args = cli()
902908

903-
if isinstance(args.input_dir, pathlib.PosixPath) and "~" in str(args.input_dir):
904-
args.input_dir = args.input_dir.expanduser().resolve()
909+
if isinstance(args.bids_dir, pathlib.PosixPath) and "~" in str(args.bids_dir):
910+
args.bids_dir = args.bids_dir.expanduser().resolve()
905911
else:
906-
args.input_dir = args.input_dir.absolute()
912+
args.bids_dir = args.bids_dir.absolute()
907913
if isinstance(args.output_dir, pathlib.PosixPath) and "~" in str(args.output_dir):
908914
args.output_dir = args.output_dir.expanduser().resolve()
909915
else:
@@ -920,22 +926,22 @@ def main(): # noqa: max-complexity: 12
920926
gid = os.getegid()
921927
system_platform = system()
922928

923-
input_mount_point = str(args.input_dir)
929+
input_mount_point = str(args.bids_dir)
924930
output_mount_point = str(args.output_dir)
925931

926932
if output_mount_point == "None" or output_mount_point is None:
927-
output_mount_point = str(args.input_dir / "derivatives" / "petdeface")
933+
output_mount_point = str(args.bids_dir / "derivatives" / "petdeface")
928934

929935
# create output directory if it doesn't exist
930936
if not pathlib.Path(output_mount_point).exists():
931937
pathlib.Path(output_mount_point).mkdir(parents=True, exist_ok=True)
932938
subprocess.run(f"chown -R {uid}:{gid} {str(output_mount_point)}", shell=True)
933939

934-
args.input_dir = pathlib.Path("/input")
940+
args.bids_dir = pathlib.Path("/input")
935941
args.output_dir = pathlib.Path("/output")
936942
print(
937943
"Attempting to run in docker container, mounting {} to {} and {} to {}".format(
938-
input_mount_point, args.input_dir, output_mount_point, args.output_dir
944+
input_mount_point, args.bids_dir, output_mount_point, args.output_dir
939945
)
940946
)
941947
# convert args to dictionary
@@ -957,9 +963,9 @@ def main(): # noqa: max-complexity: 12
957963
)
958964
args_string = args_string.replace("empty_str", "")
959965

960-
# remove --input_dir from args_string as input dir is positional, we
966+
# remove --bids_dir from args_string as input dir is positional, we
961967
# we're simply removing an artifact of argparse
962-
args_string = args_string.replace("--input_dir", "")
968+
args_string = args_string.replace("--bids_dir", "")
963969

964970
# invoke docker run command to run petdeface in container, while redirecting stdout and stderr to terminal
965971
docker_command = f"docker run "
@@ -969,7 +975,7 @@ def main(): # noqa: max-complexity: 12
969975

970976
docker_command += (
971977
f"-a stderr -a stdout --rm "
972-
f"-v {input_mount_point}:{args.input_dir} "
978+
f"-v {input_mount_point}:{args.bids_dir} "
973979
f"-v {output_mount_point}:{args.output_dir} "
974980
)
975981
if code_dir:
@@ -1005,7 +1011,7 @@ def main(): # noqa: max-complexity: 12
10051011
singularity_command = f"singularity exec -e"
10061012

10071013
if args.output_dir == "None" or args.output_dir is None or args.output_dir == "":
1008-
args.output_dir = args.input_dir / "derivatives" / "petdeface"
1014+
args.output_dir = args.bids_dir / "derivatives" / "petdeface"
10091015

10101016
# create output directory if it doesn't exist
10111017
if not args.output_dir.exists():
@@ -1030,9 +1036,9 @@ def main(): # noqa: max-complexity: 12
10301036
)
10311037
args_string = args_string.replace("empty_str", "")
10321038

1033-
# remove --input_dir from args_string as input dir is positional, we
1039+
# remove --bids_dir from args_string as input dir is positional, we
10341040
# we're simply removing an artifact of argparse
1035-
args_string = args_string.replace("--input_dir", "")
1041+
args_string = args_string.replace("--bids_dir", "")
10361042

10371043
# collect location of freesurfer license if it's installed and working
10381044
try:
@@ -1057,17 +1063,17 @@ def main(): # noqa: max-complexity: 12
10571063

10581064
else:
10591065
petdeface = PetDeface(
1060-
bids_dir=args.input_dir,
1066+
bids_dir=args.bids_dir,
10611067
output_dir=args.output_dir,
10621068
anat_only=args.anat_only,
1063-
subject=args.subject,
1069+
subject=args.participant_label,
10641070
session=args.session,
10651071
n_procs=args.n_procs,
10661072
skip_bids_validator=args.skip_bids_validator,
10671073
remove_existing=args.remove_existing,
10681074
placement=args.placement,
10691075
preview_pics=args.preview_pics,
1070-
excludesubject=args.excludesubject,
1076+
excludeparticipant=args.excludeparticipant,
10711077
)
10721078
petdeface.run()
10731079

0 commit comments

Comments
 (0)