|
1 | 1 | from nipype.interfaces.base import CommandLineInputSpec, File, traits, TraitedSpec, Str
|
2 |
| -from nipype.interfaces.base.traits_extension import InputMultiObject |
| 2 | +from nipype.interfaces.base.traits_extension import InputMultiObject, OutputMultiObject, isdefined |
3 | 3 | from nipype.interfaces.workbench.base import WBCommand
|
4 | 4 |
|
5 | 5 |
|
@@ -940,6 +940,173 @@ class CiftiResample(WBCommand):
|
940 | 940 | _cmd = "wb_command -cifti-resample"
|
941 | 941 |
|
942 | 942 |
|
| 943 | +class CiftiSeparateInputSpec(CommandLineInputSpec): |
| 944 | + in_file = File( |
| 945 | + exists=True, |
| 946 | + mandatory=True, |
| 947 | + argstr="%s", |
| 948 | + position=0, |
| 949 | + desc="the cifti to separate a component of", |
| 950 | + ) |
| 951 | + direction = traits.Enum( |
| 952 | + "ROW", |
| 953 | + "COLUMN", |
| 954 | + mandatory=True, |
| 955 | + argstr="%s", |
| 956 | + position=1, |
| 957 | + desc="which dimension to smooth along, ROW or COLUMN", |
| 958 | + ) |
| 959 | + volume_all_file = File( |
| 960 | + argstr="-volume-all %s", |
| 961 | + position=2, |
| 962 | + desc="separate all volume structures into a volume file", |
| 963 | + ) |
| 964 | + volume_all_roi = File( |
| 965 | + argstr="-roi %s", |
| 966 | + position=3, |
| 967 | + requires=["volume_all_file"], |
| 968 | + desc="output the roi of which voxels have data", |
| 969 | + ) |
| 970 | + volume_all_label = File( |
| 971 | + argstr="-label %s", |
| 972 | + position=4, |
| 973 | + requires=["volume_all_file"], |
| 974 | + desc="output a volume label file indicating the location of structures", |
| 975 | + ) |
| 976 | + volume_all_crop = traits.Bool( |
| 977 | + argstr="-crop", |
| 978 | + position=5, |
| 979 | + requires=["volume_all_file"], |
| 980 | + desc="crop volume to the size of the data rather than using the original volume size", |
| 981 | + ) |
| 982 | + # the following can be repeated |
| 983 | + label = InputMultiObject( |
| 984 | + traits.Either( |
| 985 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File()), |
| 986 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File(), File()), |
| 987 | + ), |
| 988 | + argstr="%s", |
| 989 | + position=6, |
| 990 | + desc="separate one or more surface models into a surface label file", |
| 991 | + ) |
| 992 | + metric = InputMultiObject( |
| 993 | + traits.Either( |
| 994 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File()), |
| 995 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File(), File()), # -roi |
| 996 | + ), |
| 997 | + argstr="%s", |
| 998 | + position=7, |
| 999 | + desc="separate one or more surface models into a metric file", |
| 1000 | + ) |
| 1001 | + volume = InputMultiObject( |
| 1002 | + traits.Either( |
| 1003 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File()), |
| 1004 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File(), File()), # -roi |
| 1005 | + traits.Tuple(traits.Enum(VALID_STRUCTURES, File(), traits.Bool)), # -crop |
| 1006 | + traits.Tuple(traits.Enum(VALID_STRUCTURES), File(), File(), traits.Bool), # -roi -crop |
| 1007 | + ), |
| 1008 | + argstr="%s", |
| 1009 | + position=8, |
| 1010 | + desc="separate one or more volume structures into a volume file", |
| 1011 | + ) |
| 1012 | + |
| 1013 | + |
| 1014 | +class CiftiSeparateOutputSpec(TraitedSpec): |
| 1015 | + volume_all_file = File(desc="File containing all volume structures") |
| 1016 | + volume_all_roi_file = File(desc="Output the roi of which voxels have data") |
| 1017 | + volume_all_label_file = File( |
| 1018 | + desc="output a volume label file indicating the location of structures" |
| 1019 | + ) |
| 1020 | + label_files = OutputMultiObject(File(), desc="Output label files") |
| 1021 | + label_roi_files = OutputMultiObject(File(), desc="Output label rois files") |
| 1022 | + metric_files = OutputMultiObject(File(), desc="Output metric files") |
| 1023 | + metric_roi_files = OutputMultiObject(File(), desc="Output metric rois files") |
| 1024 | + volume_files = OutputMultiObject(File(), desc="Output volume files") |
| 1025 | + volume_roi_files = OutputMultiObject(File(), desc="Output volume roi files") |
| 1026 | + |
| 1027 | + |
| 1028 | +class CiftiSeparate(WBCommand): |
| 1029 | + """ |
| 1030 | + Extract left or right hemisphere surface from CIFTI file (.dtseries) |
| 1031 | + other structure can also be extracted |
| 1032 | + The input cifti file must have a brain models mapping on the chosen |
| 1033 | + dimension, columns for .dtseries. |
| 1034 | +
|
| 1035 | + >>> separate = CiftiSeparate() |
| 1036 | + >>> separate.inputs.in_file = data_dir / "func.dtseries.nii" |
| 1037 | + >>> separate.inputs.direction = "COLUMN" |
| 1038 | + >>> separate.inputs.volume_all_file = "volume_all.nii.gz" |
| 1039 | + >>> separate.cmdline #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE |
| 1040 | + 'wb_command -cifti-separate .../func.dtseries.nii COLUMN \ |
| 1041 | + -volume-all volume_all.nii.gz' |
| 1042 | +
|
| 1043 | + Metrics, labels, and volumes can also be freely extracted |
| 1044 | + >>> separate.inputs.metric = [("CORTEX_LEFT", "cortexleft.func.gii")] |
| 1045 | + >>> separate.inputs.volume = [("HIPPOCAMPUS_LEFT", "hippoL.nii.gz"), \ |
| 1046 | + ("HIPPOCAMPUS_RIGHT", "hippoR.nii.gz", "hippoR.roi.nii.gz")] |
| 1047 | + >>> separate.cmdline #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE |
| 1048 | + 'wb_command -cifti-separate .../func.dtseries.nii COLUMN \ |
| 1049 | + -volume-all volume_all.nii.gz -metric CORTEX_LEFT cortexleft.func.gii \ |
| 1050 | + -volume HIPPOCAMPUS_LEFT hippoL.nii.gz \ |
| 1051 | + -volume HIPPOCAMPUS_RIGHT hippoR.nii.gz -roi hippoR.roi.nii.gz' |
| 1052 | +
|
| 1053 | + """ |
| 1054 | + input_spec = CiftiSeparateInputSpec |
| 1055 | + output_spec = CiftiSeparateOutputSpec |
| 1056 | + _cmd = "wb_command -cifti-separate" |
| 1057 | + _label_roi_files = [] |
| 1058 | + _metric_roi_files = [] |
| 1059 | + _volume_roi_files = [] |
| 1060 | + |
| 1061 | + def _format_arg(self, name, trait_spec, value): |
| 1062 | + if name in ("label", "metric", "volume"): |
| 1063 | + cmds = [] |
| 1064 | + for i, val in enumerate(value): |
| 1065 | + if len(val) == 3: |
| 1066 | + if val[-1] is True: |
| 1067 | + val = val[:-1] + ("-crop",) |
| 1068 | + else: |
| 1069 | + val = val[:-1] + ("-roi", val[-1]) |
| 1070 | + self._set_roi_file(name, val[-1]) |
| 1071 | + elif len(val) == 4: |
| 1072 | + val = val[:-2] + ("-roi", val[-2]) + ("crop") if val[-1] is True else () |
| 1073 | + self._set_roi_file(name, val[-2]) |
| 1074 | + cmds.append(" ".join((f"-{name}",) + val)) |
| 1075 | + return trait_spec.argstr % " ".join(cmds) |
| 1076 | + return super()._format_arg(name, trait_spec, value) |
| 1077 | + |
| 1078 | + def _list_outputs(self): |
| 1079 | + outputs = super()._list_outputs() |
| 1080 | + if self.inputs.volume_all_file: |
| 1081 | + outputs["volume_all_file"] = self.inputs.volume_all_file |
| 1082 | + if self.inputs.volume_all_roi_file: |
| 1083 | + outputs["volume_all_roi_file"] = self.inputs.volume_all_roi_file |
| 1084 | + if self.inputs.volume_all_label_file: |
| 1085 | + outputs["volume_all_label_file"] = self.inputs.volume_all_label_file |
| 1086 | + if self.inputs.label: |
| 1087 | + for label in self.inputs.label: |
| 1088 | + outputs["label_files"] = (outputs["label_files"] or []) + \ |
| 1089 | + self._gen_filename(label[2]) |
| 1090 | + if self._label_roi_files: |
| 1091 | + outputs["label_roi_files"] = self._label_roi_files |
| 1092 | + if self.inputs.metric: |
| 1093 | + for metric in self.inputs.metric: |
| 1094 | + outputs["metric_files"] = (outputs["metric_files"] or []) + \ |
| 1095 | + self._gen_filename(metric[2]) |
| 1096 | + if self._metric_roi_files: |
| 1097 | + outputs["metric_roi_files"] = self._metric_roi_files |
| 1098 | + if self.inputs.volume: |
| 1099 | + for volume in self.inputs.volume: |
| 1100 | + outputs["volume_files"] = (outputs["volume_files"] or []) + \ |
| 1101 | + self._gen_filename(volume[2]) |
| 1102 | + if self._volume_roi_files: |
| 1103 | + outputs["volume_roi_files"] = self._volume_roi_files |
| 1104 | + |
| 1105 | + def _set_roi_file(self, name, file): |
| 1106 | + rois = getattr(self, f"_{name}_roi_files") |
| 1107 | + rois.append(self._gen_filename(file)) |
| 1108 | + |
| 1109 | + |
943 | 1110 | class VolumeAffineResampleInputSpec(CommandLineInputSpec):
|
944 | 1111 | in_file = File(
|
945 | 1112 | exists=True,
|
|
0 commit comments