|
| 1 | +import os |
| 2 | +import sys |
| 3 | +import traits |
| 4 | +from nipype.interfaces.base import InputMultiPath, TraitedSpec, isdefined |
| 5 | +from nipype.interfaces.spm import SPMCommand |
| 6 | +from nipype.interfaces.spm.base import SPMCommandInputSpec, ImageFileSPM, scans_for_fnames, scans_for_fname |
| 7 | +from nipype.utils.filemanip import split_filename, fname_presuffix |
| 8 | +from traits.trait_types import Int, File |
| 9 | +from traits.trait_types import List |
| 10 | + |
| 11 | + |
| 12 | +class CAT12SegmentInputSpec(SPMCommandInputSpec): |
| 13 | + in_files = InputMultiPath(ImageFileSPM(exists=True), field="data", desc="file to segment", mandatory=True, |
| 14 | + copyfile=False) |
| 15 | + |
| 16 | + tpm = InputMultiPath(ImageFileSPM(exists=True), field="tpm", desc="Tissue Probability Maps", mandatory=False, |
| 17 | + copyfile=False) |
| 18 | + |
| 19 | + n_jobs = traits.trait_types.Int(1, usedefault=True, mandatory=True, field="nproc", desc="Number of threads") |
| 20 | + use_prior = traits.trait_types.Str(field="useprior", usedefault=True) |
| 21 | + |
| 22 | + affine_regularization = traits.trait_types.Str(default_value="mni", |
| 23 | + field="opts.affreg", usedefault=True) |
| 24 | + |
| 25 | + power_spm_inhomogeneity_correction = traits.trait_types.Float(default_value=0.5, field='opts.biasacc', |
| 26 | + usedefault=True) |
| 27 | + # Extended options for CAT12 preprocessing |
| 28 | + affine_preprocessing = traits.trait_types.Int(1070, field="extopts.APP", usedefault=True) |
| 29 | + initial_segmentation = traits.trait_types.Int(0, field="extopts.spm_kamap", usedefault=True) |
| 30 | + local_adaptive_seg = traits.trait_types.Float(0.5, field="extopts.LASstr", usedefault=True) |
| 31 | + skull_strip = traits.trait_types.Float(2, field="extopts.gcutstr", usedefault=True) |
| 32 | + wm_hyper_intensity_correction = traits.trait_types.Int(1, field="extopts.WMHC", usedefault=True) |
| 33 | + spatial_registration = traits.trait_types.Int(1, field="extopts.WMHC", usedefault=True) |
| 34 | + voxel_size = traits.trait_types.Float(1.5, field="extopts.vox", usedefault=True) |
| 35 | + internal_resampling_process = traits.trait_types.Tuple(traits.trait_types.Float(1), traits.trait_types.Float(0.1), |
| 36 | + minlen=2, maxlen=2, |
| 37 | + field="extopts.restypes.optimal", usedefault=True) |
| 38 | + ignore_errors = traits.trait_types.Int(1, field="extopts.ignoreErrors", usedefault=True) |
| 39 | + |
| 40 | + # Writing options |
| 41 | + surface_and_thickness_estimation = traits.trait_types.Int(1, field="surface", usedefault=True) |
| 42 | + surface_measures = traits.trait_types.Int(1, field="output.surf_measures", usedefault=True) |
| 43 | + |
| 44 | + # Templates |
| 45 | + neuromorphometrics = traits.trait_types.Bool(True, field="output.ROImenu.atlases.neuromorphometrics", |
| 46 | + usedefault=True) |
| 47 | + lpba40 = traits.trait_types.Bool(False, field="output.ROImenu.atlases.lpba40", usedefault=True) |
| 48 | + cobra = traits.trait_types.Bool(True, field="output.ROImenu.atlases.hammers", usedefault=True) |
| 49 | + hammers = traits.trait_types.Bool(False, field="output.ROImenu.atlases.cobra", usedefault=True) |
| 50 | + own_atlas = InputMultiPath(ImageFileSPM(exists=True), field="output.ROImenu.atlases.ownatlas", |
| 51 | + desc="Own Atlas", mandatory=False, copyfile=False) |
| 52 | + |
| 53 | + # Grey matter |
| 54 | + gm_output_native = traits.trait_types.Bool(False, field="output.GM.native", usedefault=True) |
| 55 | + gm_output_modulated = traits.trait_types.Bool(True, field="output.GM.mod", usedefault=True) |
| 56 | + gm_output_dartel = traits.trait_types.Bool(False, field="output.GM.dartel", usedefault=True) |
| 57 | + |
| 58 | + # White matter |
| 59 | + wm_output_native = traits.trait_types.Bool(False, field="output.WM.native", usedefault=True) |
| 60 | + wm_output_modulated = traits.trait_types.Bool(True, field="output.WM.mod", usedefault=True) |
| 61 | + wm_output_dartel = traits.trait_types.Bool(False, field="output.WM.dartel", usedefault=True) |
| 62 | + |
| 63 | + # CSF matter |
| 64 | + csf_output_native = traits.trait_types.Bool(False, field="output.CSF.native", usedefault=True) |
| 65 | + csf_output_modulated = traits.trait_types.Bool(True, field="output.CSF.mod", usedefault=True) |
| 66 | + csf_output_dartel = traits.trait_types.Bool(False, field="output.CSF.dartel", usedefault=True) |
| 67 | + |
| 68 | + # Labels |
| 69 | + label_native = traits.trait_types.Bool(False, field="output.label.native", usedefault=True) |
| 70 | + label_warped = traits.trait_types.Bool(True, field="output.label.warped", usedefault=True) |
| 71 | + label_dartel = traits.trait_types.Bool(False, field="output.label.dartel", usedefault=True) |
| 72 | + output_labelnative = traits.trait_types.Bool(False, field="output.labelnative", usedefault=True) |
| 73 | + |
| 74 | + # Bias |
| 75 | + save_bias_corrected = traits.trait_types.Bool(True, field="output.bias.warped", usedefault=True) |
| 76 | + |
| 77 | + # las |
| 78 | + las_native = traits.trait_types.Bool(False, field="output.las.native", usedefault=True) |
| 79 | + las_warped = traits.trait_types.Bool(True, field="output.las.warped", usedefault=True) |
| 80 | + las_dartel = traits.trait_types.Bool(False, field="output.las.dartel", usedefault=True) |
| 81 | + |
| 82 | + # Jacobian Warped |
| 83 | + jacobianwarped = traits.trait_types.Bool(True, field="output.jacobianwarped", usedefault=True) |
| 84 | + |
| 85 | + # Deformation Fields |
| 86 | + warps = traits.trait_types.Tuple(traits.trait_types.Int(1), traits.trait_types.Int(0), minlen=2, maxlen=2, |
| 87 | + field="output.warps", usedefault=True) |
| 88 | + |
| 89 | + |
| 90 | +class CAT12SegmentOutputSpec(TraitedSpec): |
| 91 | + ########################################## |
| 92 | + # Label XML files |
| 93 | + ########################################## |
| 94 | + label_files = List(File(exists=True)) |
| 95 | + |
| 96 | + label_rois = File(exists=True, desc="ROIs Volumes") |
| 97 | + label_roi = File(exists=True, desc="ROI volumes") |
| 98 | + |
| 99 | + ########################################## |
| 100 | + # MRI .nii files |
| 101 | + ########################################## |
| 102 | + |
| 103 | + mri_images = List(File(exists=True)) |
| 104 | + |
| 105 | + # Grey Matter |
| 106 | + gm_modulated_image = File(exists=True) |
| 107 | + gm_dartel_image = File(exists=True) |
| 108 | + gm_native_image = File(exists=True) |
| 109 | + |
| 110 | + # White Matter |
| 111 | + wm_modulated_image = File(exists=True) |
| 112 | + wm_dartel_image = File(exists=True) |
| 113 | + wm_native_image = File(exists=True) |
| 114 | + |
| 115 | + # CSF |
| 116 | + csf_modulated_image = File(exists=True) |
| 117 | + csf_dartel_image = File(exists=True) |
| 118 | + csf_native_image = File(exists=True) |
| 119 | + |
| 120 | + bias_corrected_image = File(exists=True) |
| 121 | + ########################################## |
| 122 | + # Surface files |
| 123 | + ########################################## |
| 124 | + |
| 125 | + surface_files = List(File(exists=True)) |
| 126 | + |
| 127 | + # Right hemisphere |
| 128 | + rh_central_surface = File(exists=True) |
| 129 | + rh_sphere_surface = File(exists=True) |
| 130 | + |
| 131 | + # Left hemisphere |
| 132 | + lh_central_surface = File(exists=True) |
| 133 | + lh_sphere_surface = File(exists=True) |
| 134 | + |
| 135 | + # Report files |
| 136 | + report_files = List(File(exists=True)) |
| 137 | + report = File(exists=True) |
| 138 | + |
| 139 | + |
| 140 | +class CAT12Segment(SPMCommand): |
| 141 | + input_spec = CAT12SegmentInputSpec |
| 142 | + output_spec = CAT12SegmentOutputSpec |
| 143 | + |
| 144 | + def __init__(self, **inputs): |
| 145 | + _local_version = SPMCommand().version |
| 146 | + if _local_version and "12." in _local_version: |
| 147 | + self._jobtype = "tools" |
| 148 | + self._jobname = "cat.estwrite" |
| 149 | + |
| 150 | + SPMCommand.__init__(self, **inputs) |
| 151 | + |
| 152 | + def _format_arg(self, opt, spec, val): |
| 153 | + """Convert input to appropriate format for spm |
| 154 | + """ |
| 155 | + if opt in ["in_files"]: |
| 156 | + if isinstance(val, list): |
| 157 | + return scans_for_fnames(val) |
| 158 | + else: |
| 159 | + return scans_for_fname(val) |
| 160 | + return super(CAT12Segment, self)._format_arg(opt, spec, val) |
| 161 | + |
| 162 | + def _list_outputs(self): |
| 163 | + outputs = self._outputs().get() |
| 164 | + f = self.inputs.in_files[0] |
| 165 | + pth, base, ext = split_filename(f) |
| 166 | + |
| 167 | + outputs["mri_images"] = [os.path.join(os.path.join(pth, "mri"), f) for f in |
| 168 | + os.listdir(os.path.join(pth, "mri")) |
| 169 | + if os.path.isfile(os.path.join(os.path.join(pth, "mri"), f))] |
| 170 | + |
| 171 | + for tidx, tissue in enumerate(["gm", "wm", "csf"]): |
| 172 | + |
| 173 | + for idx, (image, prefix) in enumerate([("modulated", "mw"), ("dartel", "r"), ("native", "")]): |
| 174 | + outtype = f'{tissue}_output_{image}' |
| 175 | + if isdefined(getattr(self.inputs, outtype)) and getattr(self.inputs, outtype): |
| 176 | + outfield = f'{tissue}_{image}_image' |
| 177 | + prefix = os.path.join("mri", f'{prefix}p{tidx + 1}') |
| 178 | + if image != "dartel": |
| 179 | + outputs[outfield] = fname_presuffix(f, prefix=prefix) |
| 180 | + else: |
| 181 | + outputs[outfield] = fname_presuffix(f, prefix=prefix, suffix="_rigid") |
| 182 | + |
| 183 | + if isdefined(self.inputs.save_bias_corrected) and self.inputs.save_bias_corrected: |
| 184 | + outputs["bias_corrected_image"] = fname_presuffix(f, prefix=os.path.join("mri", 'mi')) |
| 185 | + |
| 186 | + outputs["surface_files"] = [os.path.join(os.path.join(pth, "surf"), f) for f in |
| 187 | + os.listdir(os.path.join(pth, "surf")) |
| 188 | + if os.path.isfile(os.path.join(os.path.join(pth, "surf"), f))] |
| 189 | + |
| 190 | + for tidx, hemisphere in enumerate(["rh", "lh"]): |
| 191 | + for idx, suffix in enumerate(["central", "sphere"]): |
| 192 | + outfield = f'{hemisphere}_{suffix}_surface' |
| 193 | + outputs[outfield] = fname_presuffix(f, prefix=os.path.join("surf", f'{hemisphere}.{suffix}.'), |
| 194 | + suffix=".gii", use_ext=False) |
| 195 | + |
| 196 | + outputs["report_files"] = [os.path.join(os.path.join(pth, "report"), f) for f in |
| 197 | + os.listdir(os.path.join(pth, "report")) |
| 198 | + if os.path.isfile(os.path.join(os.path.join(pth, "report"), f))] |
| 199 | + outputs[f'report'] = fname_presuffix(f, prefix=os.path.join("report", f'cat_'), suffix=".xml", use_ext=False) |
| 200 | + |
| 201 | + outputs["label_files"] = [os.path.join(os.path.join(pth, "label"), f) for f in |
| 202 | + os.listdir(os.path.join(pth, "label")) |
| 203 | + if os.path.isfile(os.path.join(os.path.join(pth, "label"), f))] |
| 204 | + |
| 205 | + outputs['label_rois'] = fname_presuffix(f, prefix=os.path.join("label", f'catROIs_'), suffix=".xml", |
| 206 | + use_ext=False) |
| 207 | + outputs['label_roi'] = fname_presuffix(f, prefix=os.path.join("label", f'catROI_'), suffix=".xml", |
| 208 | + use_ext=False) |
| 209 | + |
| 210 | + return outputs |
| 211 | + |
| 212 | + |
| 213 | +if __name__ == '__main__': |
| 214 | + path_mr = sys.argv[1] |
| 215 | + cat = CAT12Segment(in_files=path_mr) |
| 216 | + cat.run() |
0 commit comments