1- """Provides interfaces to various commands provided by FreeSurfer
1+ """Provides interfaces to various commands provided by dcmstack
22
33 Change directory to provide relative paths for doctests
44 >>> import os
99"""
1010
1111from __future__ import absolute_import
12- import os , string
13- from os import path
12+ import os
13+ import string
14+ import errno
15+ from os import path as op
1416from glob import glob
1517from nipype .interfaces .base import (TraitedSpec ,
1618 DynamicTraitedSpec ,
3335except ImportError :
3436 have_dcmstack = False
3537
38+
3639def sanitize_path_comp (path_comp ):
3740 result = []
3841 for char in path_comp :
@@ -42,16 +45,18 @@ def sanitize_path_comp(path_comp):
4245 result .append (char )
4346 return '' .join (result )
4447
48+
4549class NiftiGeneratorBaseInputSpec (TraitedSpec ):
4650 out_format = traits .Str (desc = "String which can be formatted with "
4751 "meta data to create the output filename(s)" )
48- out_ext = traits .Str ('.nii.gz' ,
49- usedefault = True ,
52+ out_ext = traits .Str ('.nii.gz' , usedefault = True ,
5053 desc = "Determines output file type" )
54+ out_path = Directory (desc = 'output path, current working directory if not set' )
55+
5156
5257class NiftiGeneratorBase (BaseInterface ):
5358 '''Base class for interfaces that produce Nifti files, potentially with
54- embeded meta data.'''
59+ embedded meta data.'''
5560 def _get_out_path (self , meta , idx = None ):
5661 '''Return the output path for the gernerated Nifti.'''
5762 if self .inputs .out_format :
@@ -73,7 +78,22 @@ def _get_out_path(self, meta, idx=None):
7378 out_fmt = '-' .join (out_fmt )
7479 out_fn = (out_fmt % meta ) + self .inputs .out_ext
7580 out_fn = sanitize_path_comp (out_fn )
76- return path .join (os .getcwd (), out_fn )
81+
82+ out_path = os .getcwd ()
83+ if isdefined (self .inputs .out_path ):
84+ out_path = op .abspath (self .inputs .out_path )
85+
86+ # now, mkdir -p $out_path
87+ try :
88+ os .makedirs (out_path )
89+ except OSError as exc : # Python >2.5
90+ if exc .errno == errno .EEXIST and op .isdir (out_path ):
91+ pass
92+ else :
93+ raise
94+
95+ return op .join (out_path , out_fn )
96+
7797
7898class DcmStackInputSpec (NiftiGeneratorBaseInputSpec ):
7999 dicom_files = traits .Either (InputMultiPath (File (exists = True )),
@@ -92,6 +112,7 @@ class DcmStackInputSpec(NiftiGeneratorBaseInputSpec):
92112class DcmStackOutputSpec (TraitedSpec ):
93113 out_file = File (exists = True )
94114
115+
95116class DcmStack (NiftiGeneratorBase ):
96117 '''Create one Nifti file from a set of DICOM files. Can optionally embed
97118 meta data.
@@ -111,8 +132,8 @@ class DcmStack(NiftiGeneratorBase):
111132
112133 def _get_filelist (self , trait_input ):
113134 if isinstance (trait_input , six .string_types ):
114- if path .isdir (trait_input ):
115- return glob (path .join (trait_input , '*.dcm' ))
135+ if op .isdir (trait_input ):
136+ return glob (op .join (trait_input , '*.dcm' ))
116137 else :
117138 return glob (trait_input )
118139
@@ -147,9 +168,11 @@ def _list_outputs(self):
147168 outputs ["out_file" ] = self .out_path
148169 return outputs
149170
171+
150172class GroupAndStackOutputSpec (TraitedSpec ):
151173 out_list = traits .List (desc = "List of output nifti files" )
152174
175+
153176class GroupAndStack (DcmStack ):
154177 '''Create (potentially) multiple Nifti files for a set of DICOM files.
155178 '''
@@ -177,6 +200,7 @@ def _list_outputs(self):
177200 outputs ["out_list" ] = self .out_list
178201 return outputs
179202
203+
180204class LookupMetaInputSpec (TraitedSpec ):
181205 in_file = File (mandatory = True ,
182206 exists = True ,
@@ -189,8 +213,9 @@ class LookupMetaInputSpec(TraitedSpec):
189213 "lookup and the values specify the output names" )
190214 )
191215
216+
192217class LookupMeta (BaseInterface ):
193- '''Lookup meta data values from a Nifti with embeded meta data.
218+ '''Lookup meta data values from a Nifti with embedded meta data.
194219
195220 Example
196221 -------
@@ -225,13 +250,13 @@ def _outputs(self):
225250 outputs .add_trait (out_name , traits .Any )
226251 undefined_traits [out_name ] = Undefined
227252 outputs .trait_set (trait_change_notify = False , ** undefined_traits )
228- #Not sure why this is needed
253+ # Not sure why this is needed
229254 for out_name in self ._meta_keys .values ():
230255 _ = getattr (outputs , out_name )
231256 return outputs
232257
233258 def _run_interface (self , runtime ):
234- #If the 'meta_keys' input is a list, covert it to a dict
259+ # If the 'meta_keys' input is a list, covert it to a dict
235260 self ._make_name_map ()
236261 nw = NiftiWrapper .from_filename (self .inputs .in_file )
237262 self .result = {}
@@ -245,6 +270,7 @@ def _list_outputs(self):
245270 outputs .update (self .result )
246271 return outputs
247272
273+
248274class CopyMetaInputSpec (TraitedSpec ):
249275 src_file = File (mandatory = True , exists = True )
250276 dest_file = File (mandatory = True , exists = True )
@@ -254,9 +280,11 @@ class CopyMetaInputSpec(TraitedSpec):
254280 exclude_classes = traits .List (desc = "List of meta data "
255281 "classifications to exclude" )
256282
283+
257284class CopyMetaOutputSpec (TraitedSpec ):
258285 dest_file = File (exists = True )
259286
287+
260288class CopyMeta (BaseInterface ):
261289 '''Copy meta data from one Nifti file to another. Useful for preserving
262290 meta data after some processing steps.'''
@@ -288,8 +316,8 @@ def _run_interface(self, runtime):
288316 dest .meta_ext .slice_dim = src .meta_ext .slice_dim
289317 dest .meta_ext .shape = src .meta_ext .shape
290318
291- self .out_path = path .join (os .getcwd (),
292- path .basename (self .inputs .dest_file ))
319+ self .out_path = op .join (os .getcwd (),
320+ op .basename (self .inputs .dest_file ))
293321 dest .to_filename (self .out_path )
294322
295323 return runtime
@@ -299,6 +327,7 @@ def _list_outputs(self):
299327 outputs ['dest_file' ] = self .out_path
300328 return outputs
301329
330+
302331class MergeNiftiInputSpec (NiftiGeneratorBaseInputSpec ):
303332 in_files = traits .List (mandatory = True ,
304333 desc = "List of Nifti files to merge" )
@@ -310,16 +339,19 @@ class MergeNiftiInputSpec(NiftiGeneratorBaseInputSpec):
310339 "specified, the last singular or "
311340 "non-existant dimension is used." )
312341
342+
313343class MergeNiftiOutputSpec (TraitedSpec ):
314344 out_file = File (exists = True , desc = "Merged Nifti file" )
315345
346+
316347def make_key_func (meta_keys , index = None ):
317348 def key_func (src_nii ):
318349 result = [src_nii .get_meta (key , index ) for key in meta_keys ]
319350 return result
320351
321352 return key_func
322353
354+
323355class MergeNifti (NiftiGeneratorBase ):
324356 '''Merge multiple Nifti files into one. Merges together meta data
325357 extensions as well.'''
@@ -353,18 +385,23 @@ def _list_outputs(self):
353385 outputs ['out_file' ] = self .out_path
354386 return outputs
355387
388+
356389class SplitNiftiInputSpec (NiftiGeneratorBaseInputSpec ):
357390 in_file = File (exists = True , mandatory = True , desc = "Nifti file to split" )
358391 split_dim = traits .Int (desc = "Dimension to split along. If not "
359392 "specified, the last dimension is used." )
360393
394+
361395class SplitNiftiOutputSpec (TraitedSpec ):
362396 out_list = traits .List (File (exists = True ),
363397 desc = "Split Nifti files" )
364398
399+
365400class SplitNifti (NiftiGeneratorBase ):
366- '''Split one Nifti file into many along the specified dimension. Each
367- result has an updated meta data extension as well.'''
401+ '''
402+ Split one Nifti file into many along the specified dimension. Each
403+ result has an updated meta data extension as well.
404+ '''
368405 input_spec = SplitNiftiInputSpec
369406 output_spec = SplitNiftiOutputSpec
370407
0 commit comments