@@ -1159,35 +1159,27 @@ def _gen_filename(self, name):
1159
1159
class FUGUEInputSpec (FSLCommandInputSpec ):
1160
1160
in_file = File (exists = True , argstr = '--in=%s' ,
1161
1161
desc = 'filename of input volume' )
1162
- unwarped_file = File (
1163
- argstr = '--unwarp=%s' , genfile = True ,
1164
- desc = 'apply unwarping and save as filename' , hash_files = False )
1165
- forward_warping = traits .Bool (
1166
- False , usedefault = True ,
1167
- desc = 'apply forward warping instead of unwarping' )
1168
- warped_file = File (argstr = '--warp=%s' ,
1169
- desc = 'apply forward warping and save as filename' ,
1170
- hash_files = False )
1171
- phasemap_file = File (exists = True , argstr = '--phasemap=%s' ,
1172
- desc = 'filename for input phase image' )
1162
+ shift_in_file = File (exists = True , argstr = '--loadshift=%s' ,
1163
+ desc = 'filename for reading pixel shift volume' )
1164
+ phasemap_in_file = File (exists = True , argstr = '--phasemap=%s' ,
1165
+ desc = 'filename for input phase image' )
1166
+ fmap_in_file = File (exists = True , argstr = '--loadfmap=%s' ,
1167
+ desc = 'filename for loading fieldmap (rad/s)' )
1168
+ unwarped_file = File (argstr = '--unwarp=%s' , desc = 'apply unwarping and save as filename' ,
1169
+ xor = ['warped_file' ], requires = ['in_file' ])
1170
+ warped_file = File (argstr = '--warp=%s' , desc = 'apply forward warping and save as filename' ,
1171
+ xor = ['unwarped_file' ], requires = ['in_file' ])
1172
+
1173
+ forward_warping = traits .Bool (False , usedefault = True ,
1174
+ desc = 'apply forward warping instead of unwarping' )
1175
+
1173
1176
dwell_to_asym_ratio = traits .Float (argstr = '--dwelltoasym=%.10f' ,
1174
1177
desc = 'set the dwell to asym time ratio' )
1175
1178
dwell_time = traits .Float (argstr = '--dwell=%.10f' ,
1176
- desc = 'set the EPI dwell time per phase-encode line - same as echo spacing - (sec)' )
1179
+ desc = ('set the EPI dwell time per phase-encode line - same as echo '
1180
+ 'spacing - (sec)' ))
1177
1181
asym_se_time = traits .Float (argstr = '--asym=%.10f' ,
1178
1182
desc = 'set the fieldmap asymmetric spin echo time (sec)' )
1179
- fmap_out_file = File (argstr = '--savefmap=%s' ,
1180
- desc = 'filename for saving fieldmap (rad/s)' , hash_files = False )
1181
- fmap_in_file = File (exists = True , argstr = '--loadfmap=%s' ,
1182
- desc = 'filename for loading fieldmap (rad/s)' )
1183
-
1184
- save_shift = traits .Bool (desc = 'output pixel shift volume' )
1185
-
1186
- shift_out_file = traits .File (argstr = '--saveshift=%s' ,
1187
- desc = 'filename for saving pixel shift volume' , hash_files = False )
1188
-
1189
- shift_in_file = File (exists = True , argstr = '--loadshift=%s' ,
1190
- desc = 'filename for reading pixel shift volume' )
1191
1183
median_2dfilter = traits .Bool (argstr = '--median' ,
1192
1184
desc = 'apply 2D median filtering' )
1193
1185
despike_2dfilter = traits .Bool (argstr = '--despike' ,
@@ -1217,16 +1209,24 @@ class FUGUEInputSpec(FSLCommandInputSpec):
1217
1209
desc = 'apply intensity correction to unwarping (pixel shift method only)' )
1218
1210
icorr_only = traits .Bool (argstr = '--icorronly' , requires = ['unwarped_file' ],
1219
1211
desc = 'apply intensity correction only' )
1220
- mask_file = File (exists = True , argstr = '--mask=%s' ,
1221
- desc = 'filename for loading valid mask' )
1222
- save_unmasked_fmap = traits .Bool (argstr = '--unmaskfmap' ,
1223
- requires = ['fmap_out_file' ],
1224
- desc = 'saves the unmasked fieldmap when using --savefmap' )
1225
- save_unmasked_shift = traits .Bool (argstr = '--unmaskshift' ,
1226
- requires = ['shift_out_file' ],
1212
+ mask_file = File (exists = True , argstr = '--mask=%s' , desc = 'filename for loading valid mask' )
1213
+ nokspace = traits .Bool (False , argstr = '--nokspace' , desc = 'do not use k-space forward warping' )
1214
+
1215
+ # Special outputs: shift (voxel shift map, vsm)
1216
+ save_shift = traits .Bool (False , xor = ['save_unmasked_shift' ],
1217
+ desc = 'write pixel shift volume' )
1218
+ shift_out_file = File (argstr = '--saveshift=%s' , desc = 'filename for saving pixel shift volume' )
1219
+ save_unmasked_shift = traits .Bool (argstr = '--unmaskshift' , xor = ['save_shift' ],
1227
1220
desc = 'saves the unmasked shiftmap when using --saveshift' )
1228
- nokspace = traits .Bool (
1229
- argstr = '--nokspace' , desc = 'do not use k-space forward warping' )
1221
+
1222
+ # Special outputs: fieldmap (fmap)
1223
+ save_fmap = traits .Bool (False , xor = ['save_unmasked_fmap' ],
1224
+ desc = 'write field map volume' )
1225
+ fmap_out_file = File (argstr = '--savefmap=%s' , desc = 'filename for saving fieldmap (rad/s)' )
1226
+ save_unmasked_fmap = traits .Bool (False , argstr = '--unmaskfmap' , xor = ['save_fmap' ],
1227
+ desc = 'saves the unmasked fieldmap when using --savefmap' )
1228
+
1229
+
1230
1230
1231
1231
1232
1232
class FUGUEOutputSpec (TraitedSpec ):
@@ -1237,75 +1237,148 @@ class FUGUEOutputSpec(TraitedSpec):
1237
1237
1238
1238
1239
1239
class FUGUE (FSLCommand ):
1240
- """Use FSL FUGUE to unwarp epi's with fieldmaps
1240
+ """
1241
+ `FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_ is, most generally, a set of tools for
1242
+ EPI distortion correction.
1243
+
1244
+ Distortions may be corrected for
1245
+ 1. improving registration with non-distorted images (e.g. structurals), or
1246
+ 2. dealing with motion-dependent changes.
1247
+
1248
+ FUGUE is designed to deal only with the first case - improving registration.
1249
+
1241
1250
1242
1251
Examples
1243
1252
--------
1244
1253
1245
- Please insert examples for use of this command
1246
1254
1247
- """
1255
+ Unwarping an input image (shift map is known) ::
1248
1256
1249
- _cmd = 'fugue'
1250
- input_spec = FUGUEInputSpec
1251
- output_spec = FUGUEOutputSpec
1257
+ >>> from nipype.interfaces.fsl.preprocess import FUGUE
1258
+ >>> fugue = FUGUE()
1259
+ >>> fugue.inputs.in_file = 'epi.nii'
1260
+ >>> fugue.inputs.mask_file = 'epi_mask.nii'
1261
+ >>> fugue.inputs.shift_in_file = 'vsm.nii' # Previously computed with fugue as well
1262
+ >>> fugue.inputs.unwarp_direction = 'y'
1263
+ >>> fugue.cmdline #doctest: +ELLIPSIS
1264
+ 'fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --unwarp=epi_unwarped.nii.gz'
1265
+ >>> fugue.run() #doctest: +SKIP
1252
1266
1253
- def __init__ (self , ** kwargs ):
1254
- super (FUGUE , self ).__init__ (** kwargs )
1255
- warn (
1256
- 'This interface has not been fully tested. Please report any failures.' )
1257
1267
1258
- def _list_outputs (self ):
1259
- outputs = self ._outputs ().get ()
1260
- if self .inputs .forward_warping :
1261
- out_field = 'warped_file'
1262
- else :
1263
- out_field = 'unwarped_file'
1268
+ Warping an input image (shift map is known) ::
1264
1269
1265
- out_file = getattr (self .inputs , out_field )
1266
- if not isdefined (out_file ):
1267
- if isdefined (self .inputs .in_file ):
1268
- out_file = self ._gen_fname (self .inputs .in_file ,
1269
- suffix = '_' + out_field [:- 5 ])
1270
- if isdefined (out_file ):
1271
- outputs [out_field ] = os .path .abspath (out_file )
1272
- if isdefined (self .inputs .fmap_out_file ):
1273
- outputs ['fmap_out_file' ] = os .path .abspath (
1274
- self .inputs .fmap_out_file )
1275
- if isdefined (self .inputs .shift_out_file ):
1276
- outputs ['shift_out_file' ] = os .path .abspath (
1277
- self .inputs .shift_out_file )
1270
+ >>> from nipype.interfaces.fsl.preprocess import FUGUE
1271
+ >>> fugue = FUGUE()
1272
+ >>> fugue.inputs.in_file = 'epi.nii'
1273
+ >>> fugue.inputs.forward_warping = True
1274
+ >>> fugue.inputs.mask_file = 'epi_mask.nii'
1275
+ >>> fugue.inputs.shift_in_file = 'vsm.nii' # Previously computed with fugue as well
1276
+ >>> fugue.inputs.unwarp_direction = 'y'
1277
+ >>> fugue.cmdline #doctest: +ELLIPSIS
1278
+ 'fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --warp=epi_warped.nii.gz'
1279
+ >>> fugue.run() #doctest: +SKIP
1278
1280
1279
- return outputs
1280
1281
1281
- def _gen_filename (self , name ):
1282
- if name == 'unwarped_file' and not self .inputs .forward_warping :
1283
- return self ._list_outputs ()['unwarped_file' ]
1284
- if name == 'warped_file' and self .inputs .forward_warping :
1285
- return self ._list_outputs ()['warped_file' ]
1286
- return None
1282
+ Computing the vsm (unwrapped phase map is known) ::
1283
+
1284
+ >>> from nipype.interfaces.fsl.preprocess import FUGUE
1285
+ >>> fugue = FUGUE()
1286
+ >>> fugue.inputs.phasemap_in_file = 'epi_phasediff.nii'
1287
+ >>> fugue.inputs.mask_file = 'epi_mask.nii'
1288
+ >>> fugue.inputs.dwell_to_asym_ratio = (0.77e-3 * 3) / 2.46e-3
1289
+ >>> fugue.inputs.unwarp_direction = 'y'
1290
+ >>> fugue.inputs.save_shift = True
1291
+ >>> fugue.cmdline #doctest: +ELLIPSIS
1292
+ 'fugue --dwelltoasym=0.9390243902 --mask=epi_mask.nii --phasemap=epi_phasediff.nii --saveshift=epi_phasediff_vsm.nii.gz --unwarpdir=y'
1293
+ >>> fugue.run() #doctest: +SKIP
1294
+
1295
+
1296
+ """
1297
+
1298
+ _cmd = 'fugue'
1299
+ input_spec = FUGUEInputSpec
1300
+ output_spec = FUGUEOutputSpec
1287
1301
1288
1302
def _parse_inputs (self , skip = None ):
1289
1303
if skip is None :
1290
1304
skip = []
1291
1305
1292
- if not isdefined (self .inputs .save_shift ) or not self . inputs . save_shift :
1293
- skip += [ 'shift_out_file' ]
1294
- else :
1295
- if not isdefined ( self . inputs . shift_out_file ):
1296
- self . inputs . shift_out_file = self . _gen_fname (
1297
- self . inputs . in_file , suffix = '_vsm ' )
1306
+ input_phase = isdefined (self .inputs .phasemap_in_file )
1307
+ input_vsm = isdefined ( self . inputs . shift_in_file )
1308
+ input_fmap = isdefined ( self . inputs . fmap_in_file )
1309
+
1310
+ if not input_phase and not input_vsm and not input_fmap :
1311
+ raise RuntimeError ( 'Either phasemap_in_file, shift_in_file or fmap_in_file must be set. ' )
1298
1312
1299
1313
if not isdefined (self .inputs .in_file ):
1300
1314
skip += ['unwarped_file' , 'warped_file' ]
1301
- elif self .inputs .forward_warping :
1302
- if not isdefined (self .inputs .warped_file ):
1303
- self .inputs .warped_file = self ._gen_fname (
1304
- self .inputs .in_file , suffix = '_warped' )
1305
- elif not self .inputs .forward_warping :
1306
- if not isdefined (self .inputs .unwarped_file ):
1307
- self .inputs .unwarped_file = self ._gen_fname (
1308
- self .inputs .in_file , suffix = '_unwarped' )
1315
+ else :
1316
+ if self .inputs .forward_warping :
1317
+ skip += ['unwarped_file' ]
1318
+ trait_spec = self .inputs .trait ('warped_file' )
1319
+ trait_spec .name_template = "%s_warped"
1320
+ trait_spec .name_source = 'in_file'
1321
+ trait_spec .output_name = 'warped_file'
1322
+ else :
1323
+ skip += ['warped_file' ]
1324
+ trait_spec = self .inputs .trait ('unwarped_file' )
1325
+ trait_spec .name_template = "%s_unwarped"
1326
+ trait_spec .name_source = 'in_file'
1327
+ trait_spec .output_name = 'unwarped_file'
1328
+
1329
+ # Handle shift output
1330
+ if not isdefined (self .inputs .shift_out_file ):
1331
+ vsm_save_masked = (isdefined (self .inputs .save_shift ) and self .inputs .save_shift )
1332
+ vsm_save_unmasked = (isdefined (self .inputs .save_unmasked_shift ) and
1333
+ self .inputs .save_unmasked_shift )
1334
+
1335
+ if (vsm_save_masked or vsm_save_unmasked ):
1336
+ trait_spec = self .inputs .trait ('shift_out_file' )
1337
+ trait_spec .output_name = 'shift_out_file'
1338
+
1339
+ if input_fmap :
1340
+ trait_spec .name_source = 'fmap_in_file'
1341
+ elif input_phase :
1342
+ trait_spec .name_source = 'phasemap_in_file'
1343
+ elif input_vsm :
1344
+ trait_spec .name_source = 'shift_in_file'
1345
+ else :
1346
+ raise RuntimeError (('Either phasemap_in_file, shift_in_file or '
1347
+ 'fmap_in_file must be set.' ))
1348
+
1349
+ if vsm_save_unmasked :
1350
+ trait_spec .name_template = '%s_vsm_unmasked'
1351
+ else :
1352
+ trait_spec .name_template = '%s_vsm'
1353
+ else :
1354
+ skip += ['save_shift' , 'save_unmasked_shift' , 'shift_out_file' ]
1355
+
1356
+ # Handle fieldmap output
1357
+ if not isdefined (self .inputs .fmap_out_file ):
1358
+ fmap_save_masked = (isdefined (self .inputs .save_fmap ) and self .inputs .save_fmap )
1359
+ fmap_save_unmasked = (isdefined (self .inputs .save_unmasked_fmap ) and
1360
+ self .inputs .save_unmasked_fmap )
1361
+
1362
+ if (fmap_save_masked or fmap_save_unmasked ):
1363
+ trait_spec = self .inputs .trait ('fmap_out_file' )
1364
+ trait_spec .output_name = 'fmap_out_file'
1365
+
1366
+ if input_vsm :
1367
+ trait_spec .name_source = 'shift_in_file'
1368
+ elif input_phase :
1369
+ trait_spec .name_source = 'phasemap_in_file'
1370
+ elif input_fmap :
1371
+ trait_spec .name_source = 'fmap_in_file'
1372
+ else :
1373
+ raise RuntimeError (('Either phasemap_in_file, shift_in_file or '
1374
+ 'fmap_in_file must be set.' ))
1375
+
1376
+ if fmap_save_unmasked :
1377
+ trait_spec .name_template = '%s_fieldmap_unmasked'
1378
+ else :
1379
+ trait_spec .name_template = '%s_fieldmap'
1380
+ else :
1381
+ skip += ['save_fmap' , 'save_unmasked_fmap' , 'fmap_out_file' ]
1309
1382
1310
1383
return super (FUGUE , self )._parse_inputs (skip = skip )
1311
1384
0 commit comments