def _formatRegistration(self): retval = [] for ii in range(len(self.inputs.transforms)): retval.append('--transform %s' % (self._formatTransform(ii))) for metric in self._formatMetric(ii): retval.append('--metric %s' % metric) retval.append('--convergence %s' % self._formatConvergence(ii)) if isdefined(self.inputs.sigma_units): retval.append( '--smoothing-sigmas %s%s' % (self._antsJoinList(self.inputs.smoothing_sigmas[ii]), self.inputs.sigma_units[ii])) else: retval.append( '--smoothing-sigmas %s' % self._antsJoinList(self.inputs.smoothing_sigmas[ii])) retval.append('--shrink-factors %s' % self._antsJoinList(self.inputs.shrink_factors[ii])) if isdefined(self.inputs.use_estimate_learning_rate_once): retval.append('--use-estimate-learning-rate-once %d' % self.inputs.use_estimate_learning_rate_once[ii]) if isdefined(self.inputs.use_histogram_matching): # use_histogram_matching is either a common flag for all transforms # or a list of transform-specific flags if isinstance(self.inputs.use_histogram_matching, bool): histval = self.inputs.use_histogram_matching else: histval = self.inputs.use_histogram_matching[ii] retval.append('--use-histogram-matching %d' % histval) return " ".join(retval)
def _format_arg(self, opt, spec, val): if opt == 'moving_image_mask': return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask) elif opt == 'transforms': return self._formatRegistration() elif opt == 'initial_moving_transform': if self.inputs.invert_initial_moving_transform: return '--initial-moving-transform [ %s, 1 ]' % self.inputs.initial_moving_transform else: return '--initial-moving-transform [ %s, 0 ]' % self.inputs.initial_moving_transform elif opt == 'interpolation': # TODO: handle multilabel, gaussian, and bspline options return '--interpolation %s' % self.inputs.interpolation elif opt == 'output_transform_prefix': if isdefined(self.inputs.output_inverse_warped_image) and self.inputs.output_inverse_warped_image: return '--output [ %s, %s, %s ]' % (self.inputs.output_transform_prefix, self.inputs.output_warped_image, self.inputs.output_inverse_warped_image) elif isdefined(self.inputs.output_warped_image) and self.inputs.output_warped_image: return '--output [ %s, %s ]' % (self.inputs.output_transform_prefix, self.inputs.output_warped_image) else: return '--output %s' % self.inputs.output_transform_prefix elif opt == 'winsorize_upper_quantile' or opt == 'winsorize_lower_quantile': if not self._quantilesDone: return self._formatWinsorizeImageIntensities() return '' # Must return something for argstr! elif opt == 'collapse_linear_transforms_to_fixed_image_header': return self._formatCollapseLinearTransformsToFixedImageHeader() return super(Registration, self)._format_arg(opt, spec, val)
def _clean_container(self, object, undefinedval=None, skipundefined=False): """Convert a traited obejct into a pure python representation. """ if isinstance(object, TraitDictObject) or isinstance(object, dict): out = {} for key, val in object.items(): if isdefined(val): out[key] = self._clean_container(val, undefinedval) else: if not skipundefined: out[key] = undefinedval elif isinstance(object, TraitListObject) or isinstance(object, list) or isinstance(object, tuple): out = [] for val in object: if isdefined(val): out.append(self._clean_container(val, undefinedval)) else: if not skipundefined: out.append(undefinedval) else: out.append(None) if isinstance(object, tuple): out = tuple(out) else: if isdefined(object): out = object else: if not skipundefined: out = undefinedval return out
def _format_arg(self, opt, spec, val): if opt == 'moving_image_mask': return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask) elif opt == 'transforms': self.numberOfTransforms = len(self.inputs.transforms) return self._formatRegistration() elif opt == 'initial_moving_transform': if self.inputs.invert_initial_moving_transform: return '--initial-moving-transform [ %s, 1 ]' % self.inputs.initial_moving_transform else: return '--initial-moving-transform [ %s, 0 ]' % self.inputs.initial_moving_transform elif opt == 'interpolation': # TODO: handle multilabel, gaussian, and bspline options return '--interpolation %s' % self.inputs.interpolation elif opt == 'output_transform_prefix': if isdefined(self.inputs.output_inverse_warped_image ) and self.inputs.output_inverse_warped_image: return '--output [ %s, %s, %s ]' % ( self.inputs.output_transform_prefix, self.inputs.output_warped_image, self.inputs.output_inverse_warped_image) elif isdefined(self.inputs.output_warped_image ) and self.inputs.output_warped_image: return '--output [ %s, %s ]' % ( self.inputs.output_transform_prefix, self.inputs.output_warped_image) else: return '--output %s' % self.inputs.output_transform_prefix return super(Registration, self)._format_arg(opt, spec, val)
def _formatRegistration(self): retval = [] for ii in range(len(self.inputs.transforms)): retval.append('--transform %s' % (self._formatTransform(ii))) for metric in self._formatMetric(ii): retval.append('--metric %s' % metric) retval.append('--convergence %s' % self._formatConvergence(ii)) if isdefined(self.inputs.sigma_units): retval.append('--smoothing-sigmas %s%s' % (self._antsJoinList(self.inputs.smoothing_sigmas[ ii]), self.inputs.sigma_units[ii])) else: retval.append('--smoothing-sigmas %s' % self._antsJoinList(self.inputs.smoothing_sigmas[ii])) retval.append('--shrink-factors %s' % self._antsJoinList(self.inputs.shrink_factors[ii])) if isdefined(self.inputs.use_estimate_learning_rate_once): retval.append('--use-estimate-learning-rate-once %d' % self.inputs.use_estimate_learning_rate_once[ii]) if isdefined(self.inputs.use_histogram_matching): # use_histogram_matching is either a common flag for all transforms # or a list of transform-specific flags if isinstance(self.inputs.use_histogram_matching, bool): histval = self.inputs.use_histogram_matching else: histval = self.inputs.use_histogram_matching[ii] retval.append('--use-histogram-matching %d' % histval) return " ".join(retval)
def _get_sorteddict(self, object, dictwithhash=False, hash_method=None, hash_files=True): if isinstance(object, dict): out = {} for key, val in sorted(object.items()): if isdefined(val): out[key] = self._get_sorteddict(val, dictwithhash, hash_method=hash_method, hash_files=hash_files) elif isinstance(object, (list, tuple)): out = [] for val in object: if isdefined(val): out.append(self._get_sorteddict(val, dictwithhash, hash_method=hash_method, hash_files=hash_files)) if isinstance(object, tuple): out = tuple(out) else: if isdefined(object): if hash_files and isinstance(object, str) and os.path.isfile(object): if hash_method == None: hash_method = config.get("execution", "hash_method") if hash_method.lower() == "timestamp": hash = hash_timestamp(object) elif hash_method.lower() == "content": hash = hash_infile(object) else: raise Exception("Unknown hash method: %s" % hash_method) if dictwithhash: out = (object, hash) else: out = hash elif isinstance(object, float): out = "%.10f" % object else: out = object return out
def _format_arg(self, opt, spec, val): if opt == 'moving_image_mask': return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask) elif opt == 'transforms': return self._formatRegistration() elif opt == 'initial_moving_transform': if self.inputs.invert_initial_moving_transform: return '--initial-moving-transform [ %s, 1 ]' % self.inputs.initial_moving_transform else: return '--initial-moving-transform [ %s, 0 ]' % self.inputs.initial_moving_transform elif opt == 'interpolation': # TODO: handle multilabel, gaussian, and bspline options return '--interpolation %s' % self.inputs.interpolation elif opt == 'output_transform_prefix': if isdefined(self.inputs.output_inverse_warped_image ) and self.inputs.output_inverse_warped_image: return '--output [ %s, %s, %s ]' % ( self.inputs.output_transform_prefix, self.inputs.output_warped_image, self.inputs.output_inverse_warped_image) elif isdefined(self.inputs.output_warped_image ) and self.inputs.output_warped_image: return '--output [ %s, %s ]' % ( self.inputs.output_transform_prefix, self.inputs.output_warped_image) else: return '--output %s' % self.inputs.output_transform_prefix elif opt == 'winsorize_upper_quantile' or opt == 'winsorize_lower_quantile': if not self._quantilesDone: return self._formatWinsorizeImageIntensities() return '' # Must return something for argstr! elif opt == 'collapse_linear_transforms_to_fixed_image_header': return self._formatCollapseLinearTransformsToFixedImageHeader() return super(Registration, self)._format_arg(opt, spec, val)
def _list_outputs(self): outputs = self._outputs().get() outputs["forward_transforms"] = [] outputs["forward_invert_flags"] = [] outputs["reverse_transforms"] = [] outputs["reverse_invert_flags"] = [] if not self.inputs.collapse_output_transforms: transformCount = 0 if isdefined(self.inputs.initial_moving_transform): outputs["forward_transforms"].append(self.inputs.initial_moving_transform) outputs["forward_invert_flags"].append(self.inputs.invert_initial_moving_transform) outputs["reverse_transforms"].insert(0, self.inputs.initial_moving_transform) outputs["reverse_invert_flags"].insert(0, not self.inputs.invert_initial_moving_transform) # Prepend transformCount += 1 elif isdefined(self.inputs.initial_moving_transform_com): # forwardFileName, _ = self._outputFileNames(self.inputs.output_transform_prefix, # transformCount, # 'Initial') # outputs['forward_transforms'].append(forwardFileName) transformCount += 1 for count in range(len(self.inputs.transforms)): forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count] ) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True ) outputs["forward_transforms"].append(os.path.abspath(forwardFileName)) outputs["forward_invert_flags"].append(forwardInverseMode) outputs["reverse_transforms"].insert(0, os.path.abspath(reverseFileName)) outputs["reverse_invert_flags"].insert(0, reverseInverseMode) transformCount += 1 else: transformCount = 0 for transform in ["GenericAffine", "SyN"]: # Only files returned by collapse_output_transforms forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform ) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform, True ) outputs["forward_transforms"].append(os.path.abspath(forwardFileName)) outputs["forward_invert_flags"].append(forwardInverseMode) outputs["reverse_transforms"].append(os.path.abspath(reverseFileName)) outputs["reverse_invert_flags"].append(reverseInverseMode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + "Composite.h5" outputs["composite_transform"] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + "InverseComposite.h5" outputs["inverse_composite_transform"] = [os.path.abspath(fileName)] out_filename = self._get_outputfilenames(inverse=False) inv_out_filename = self._get_outputfilenames(inverse=True) if out_filename: outputs["warped_image"] = os.path.abspath(out_filename) if inv_out_filename: outputs["inverse_warped_image"] = os.path.abspath(inv_out_filename) return outputs
def _format_arg(self, name, spec, value): if name == 'use_histogram_matching': if isdefined(self.inputs.use_histogram_matching): return spec.argstr % {False: '0', True: '1'}[value] elif name == 'precision_type': if isdefined(self.inputs.precision_type): return spec.argstr % {'float': 'f', 'double': 'd'}[value] return super(RegistrationSynQuick, self)._format_arg(name, spec, value)
def _parse_stdout(self, stdout): import re import os files = [] reoriented_files = [] reoriented_and_cropped_files = [] bvecs = [] bvals = [] skip = False last_added_file = None for line in stdout.split("\n"): if not skip: file = None if line.startswith("Saving "): file = line[len("Saving "):] elif line.startswith("GZip..."): #for gzipped outpus files are not absolute if isdefined(self.inputs.output_dir): output_dir = self.inputs.output_dir else: output_dir = self._gen_filename('output_dir') file = os.path.abspath(os.path.join(output_dir, line[len("GZip..."):])) elif line.startswith("Number of diffusion directions "): if last_added_file: base, filename, ext = split_filename(last_added_file) bvecs.append(os.path.join(base,filename + ".bvec")) bvals.append(os.path.join(base,filename + ".bval")) elif re.search('.*->(.*)', line): val = re.search('.*->(.*)', line) val = val.groups()[0] if isdefined(self.inputs.output_dir): output_dir = self.inputs.output_dir else: output_dir = self._gen_filename('output_dir') val = os.path.join(output_dir, val) file = val if file: if last_added_file and os.path.exists(file) and not last_added_file in file: files.append(file) last_added_file = file continue if line.startswith("Reorienting as "): reoriented_files.append(line[len("Reorienting as "):]) skip = True continue elif line.startswith("Cropping NIfTI/Analyze image "): base, filename = os.path.split(line[len("Cropping NIfTI/Analyze image "):]) filename = "c" + filename reoriented_and_cropped_files.append(os.path.join(base, filename)) skip = True continue skip = False return files, reoriented_files, reoriented_and_cropped_files, bvecs, bvals
def _check_xor(self, spec, name, value): """ check if mutually exclusive inputs are satisfied """ if spec.xor: values = [isdefined(getattr(self.inputs, field)) for field in spec.xor] if not any(values) and not isdefined(value): msg = "%s requires a value for one of the inputs '%s'. " \ "For a list of required inputs, see %s.help()" % \ (self.__class__.__name__, ', '.join(spec.xor), self.__class__.__name__) raise ValueError(msg)
def _check_requires(self, spec, name, value): """ check if required inputs are satisfied """ if spec.requires: values = [not isdefined(getattr(self.inputs, field)) for field in spec.requires] if any(values) and isdefined(value): msg = "%s requires a value for input '%s' because one of %s is set. " \ "For a list of required inputs, see %s.help()" % \ (self.__class__.__name__, name, ', '.join(spec.requires), self.__class__.__name__) raise ValueError(msg)
def _formatMetric(self, index): """ Format the antsRegistration -m metric argument(s). Parameters ---------- index: the stage index """ # The common fixed image. fixed = self.inputs.fixed_image[0] # The common moving image. moving = self.inputs.moving_image[0] # The metric name input for the current stage. name_input = self.inputs.metric[index] # The stage-specific input dictionary. stage_inputs = dict( metric=name_input, weight=self.inputs.metric_weight[index], radius_or_bins=self.inputs.radius_or_number_of_bins[index], optional=self.inputs.radius_or_number_of_bins[index]) # The optional sampling strategy and percentage. if (isdefined(self.inputs.sampling_strategy) and self.inputs.sampling_strategy): sampling_strategy = self.inputs.sampling_strategy[index] if sampling_strategy: stage_inputs['sampling_strategy'] = sampling_strategy sampling_percentage = self.inputs.sampling_percentage if (isdefined(self.inputs.sampling_percentage) and self.inputs.sampling_percentage): sampling_percentage = self.inputs.sampling_percentage[index] if sampling_percentage: stage_inputs['sampling_percentage'] = sampling_percentage # Make a list of metric specifications, one per -m command line # argument for the current stage. # If there are multiple inputs for this stage, then convert the # dictionary of list inputs into a list of metric specifications. # Otherwise, make a singleton list of the metric specification # from the non-list inputs. if isinstance(name_input, list): items = stage_inputs.items() indexes = range(0, len(name_input)) # dict-comprehension only works with python 2.7 and up # specs = [{k: v[i] for k, v in items} for i in indexes] specs = [dict([(k, v[i]) for k, v in items]) for i in indexes] else: specs = [stage_inputs] # Format the --metric command line metric arguments, one per # specification. return [ self._formatMetricArgument(fixed, moving, **spec) for spec in specs ]
def _formatRegistration(self): retval = [] for ii in range(len(self.inputs.transforms)): retval.append('--transform %s' % (self._formatTransform(ii))) retval.append('--metric %s' % self._formatMetric(ii)) retval.append('--convergence %s' % self._formatConvergence(ii)) retval.append('--smoothing-sigmas %s' % self._antsJoinList(self.inputs.smoothing_sigmas[ii])) retval.append('--shrink-factors %s' % self._antsJoinList(self.inputs.shrink_factors[ii])) if isdefined(self.inputs.use_estimate_learning_rate_once): retval.append('--use-estimate-learning-rate-once %d' % self.inputs.use_estimate_learning_rate_once[ii]) if isdefined(self.inputs.use_histogram_matching): retval.append('--use-histogram-matching %d' % self.inputs.use_histogram_matching[ii]) return " ".join(retval)
def _formatMetric(self, index): """ Format the antsRegistration -m metric argument(s). Parameters ---------- index: the stage index """ # The common fixed image. fixed = self.inputs.fixed_image[0] # The common moving image. moving = self.inputs.moving_image[0] # The metric name input for the current stage. name_input = self.inputs.metric[index] # The stage-specific input dictionary. stage_inputs = dict( metric=name_input, weight=self.inputs.metric_weight[index], radius_or_bins=self.inputs.radius_or_number_of_bins[index], optional=self.inputs.radius_or_number_of_bins[index] ) # The optional sampling strategy and percentage. if (isdefined(self.inputs.sampling_strategy) and self.inputs.sampling_strategy): sampling_strategy = self.inputs.sampling_strategy[index] if sampling_strategy: stage_inputs['sampling_strategy'] = sampling_strategy sampling_percentage = self.inputs.sampling_percentage if (isdefined(self.inputs.sampling_percentage) and self.inputs.sampling_percentage): sampling_percentage = self.inputs.sampling_percentage[index] if sampling_percentage: stage_inputs['sampling_percentage'] = sampling_percentage # Make a list of metric specifications, one per -m command line # argument for the current stage. # If there are multiple inputs for this stage, then convert the # dictionary of list inputs into a list of metric specifications. # Otherwise, make a singleton list of the metric specification # from the non-list inputs. if isinstance(name_input, list): items = stage_inputs.items() indexes = range(0, len(name_input)) # dict-comprehension only works with python 2.7 and up #specs = [{k: v[i] for k, v in items} for i in indexes] specs = [dict([(k, v[i]) for k, v in items]) for i in indexes] else: specs = [stage_inputs] # Format the --metric command line metric arguments, one per # specification. return [self._formatMetricArgument(fixed, moving, **spec) for spec in specs]
def _list_outputs(self): outputs = self.output_spec().get() if isdefined(self.inputs.trained_wts_filestem): outputs['trained_wts_file'] = os.path.abspath(self.inputs.trained_wts_filestem + '.RData') else: outputs['trained_wts_file'] = os.path.abspath('trained_wts_file.RData') return outputs
def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) if isdefined(self.inputs.out_sf): outputs['out_sf'] = op.abspath(self.inputs.out_sf) return outputs
def _xor_warn(self, obj, name, old, new): """ Generates warnings for xor traits """ if isdefined(new): trait_spec = self.traits()[name] # for each xor, set to default_value for trait_name in trait_spec.xor: if trait_name == name: # skip ourself continue if isdefined(getattr(self, trait_name)): self.trait_set(trait_change_notify=False, **{'%s' % name: Undefined}) msg = 'Input "%s" is mutually exclusive with input "%s", ' \ 'which is already set' \ % (name, trait_name) raise IOError(msg)
def _check_mandatory_inputs(self): """ Raises an exception if a mandatory input is Undefined """ for name, spec in self.inputs.traits(mandatory=True).items(): value = getattr(self.inputs, name) self._check_xor(spec, name, value) if not isdefined(value) and spec.xor is None: msg = "%s requires a value for input '%s'. " \ "For a list of required inputs, see %s.help()" % \ (self.__class__.__name__, name, self.__class__.__name__) raise ValueError(msg) if isdefined(value): self._check_requires(spec, name, value) for name, spec in self.inputs.traits(mandatory=None, transient=None).items(): self._check_requires(spec, name, getattr(self.inputs, name))
def get_hashval(self, hash_method=None): """Return a dictionary of our items with hashes for each file. Searches through dictionary items and if an item is a file, it calculates the md5 hash of the file contents and stores the file name and hash value as the new key value. However, the overall bunch hash is calculated only on the hash value of a file. The path and name of the file are not used in the overall hash calculation. Returns ------- dict_withhash : dict Copy of our dictionary with the new file hashes included with each file. hashvalue : str The md5 hash value of the traited spec """ dict_withhash = {} dict_nofilename = {} for name, val in sorted(self.get().items()): if isdefined(val): trait = self.trait(name) hash_files = not has_metadata(trait.trait_type, "hash_files", False) dict_nofilename[name] = self._get_sorteddict(val, hash_method=hash_method, hash_files=hash_files) dict_withhash[name] = self._get_sorteddict(val, True, hash_method=hash_method, hash_files=hash_files) return (dict_withhash, md5(str(dict_nofilename)).hexdigest())
def run(self, **inputs): """Execute this interface. This interface will not raise an exception if runtime.returncode is non-zero. Parameters ---------- inputs : allows the interface settings to be updated Returns ------- results : an InterfaceResult object containing a copy of the instance that was executed, provenance information and, if successful, results """ self.inputs.set(**inputs) self._check_mandatory_inputs() interface = self.__class__ # initialize provenance tracking env = deepcopy(os.environ.data) runtime = Bunch(cwd=os.getcwd(), returncode=None, duration=None, environ=env, hostname=gethostname()) t = time() try: runtime = self._run_interface(runtime) runtime.duration = time() - t results = InterfaceResult(interface, runtime, inputs=self.inputs.get_traitsfree()) results.outputs = self.aggregate_outputs(results.runtime) except Exception, e: if len(e.args) == 0: e.args = ("") message = "\nInterface %s failed to run." % self.__class__.__name__ if config.has_option('logging', 'interface_level') and config.get('logging', 'interface_level').lower() == 'debug': inputs_str = "Inputs:" + str(self.inputs) + "\n" else: inputs_str = '' if len(e.args) == 1 and isinstance(e.args[0], str): e.args = (e.args[0] + " ".join([message, inputs_str]),) else: e.args += (message, ) if inputs_str != '': e.args += (inputs_str, ) #exception raising inhibition for special cases if hasattr(self.inputs, 'ignore_exception') and \ isdefined(self.inputs.ignore_exception) and \ self.inputs.ignore_exception: import traceback runtime.traceback = traceback.format_exc() runtime.traceback_args = e.args return InterfaceResult(interface, runtime) else: raise
def _list_outputs(self): outputs = self.output_spec().get() if isdefined(self.inputs.output_directory): outputs['output_directory'] = Directory(exists=False, value=self.inputs.output_directory) else: outputs['output_directory'] = Directory(exists=False, value='accuracy_test') return outputs
def _list_outputs(self): outputs = self._outputs().get() outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] if not self.inputs.collapse_output_transforms: if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append( self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append( self.inputs.invert_initial_moving_transform) outputs['reverse_transforms'].insert( 0, self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert( 0, not self.inputs.invert_initial_moving_transform) # Prepend transformCount = 1 for count in range(self._numberOfOutputTransforms): forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count]) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].insert( 0, reverseInverseMode) transformCount += 1 else: transformCount = 0 for transform in [ 'GenericAffine', 'SyN' ]: # Only files returned by collapse_output_transforms forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform, True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].append( os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].append(reverseInverseMode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + \ 'InverseComposite.h5' outputs['inverse_composite_transform'] = [ os.path.abspath(fileName) ] return outputs
def fname_presuffix(fname, prefix='', suffix='', newpath=None, use_ext=True): """Manipulates path and name of input filename Parameters ---------- fname : string A filename (may or may not include path) prefix : string Characters to prepend to the filename suffix : string Characters to append to the filename newpath : string Path to replace the path of the input fname use_ext : boolean If True (default), appends the extension of the original file to the output name. Returns ------- Absolute path of the modified filename >>> from nipype.utils.filemanip import fname_presuffix >>> fname = 'foo.nii.gz' >>> fname_presuffix(fname,'pre','post','/tmp') '/tmp/prefoopost.nii.gz' """ pth, fname, ext = split_filename(fname) if not use_ext: ext = '' if newpath and isdefined(newpath): pth = os.path.abspath(newpath) return os.path.join(pth, prefix+fname+suffix+ext)
def fname_presuffix(fname, prefix='', suffix='', newpath=None, use_ext=True): """Manipulates path and name of input filename Parameters ---------- fname : string A filename (may or may not include path) prefix : string Characters to prepend to the filename suffix : string Characters to append to the filename newpath : string Path to replace the path of the input fname use_ext : boolean If True (default), appends the extension of the original file to the output name. Returns ------- Absolute path of the modified filename >>> from nipype.utils.filemanip import fname_presuffix >>> fname = 'foo.nii.gz' >>> fname_presuffix(fname,'pre','post','/tmp') '/tmp/prefoopost.nii.gz' """ pth, fname, ext = split_filename(fname) if not use_ext: ext = '' if newpath and isdefined(newpath): pth = os.path.abspath(newpath) return os.path.join(pth, prefix + fname + suffix + ext)
def _list_outputs(self): outputs = self._outputs().get() transformCount = 0 outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append(self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append(self.inputs.invert_initial_moving_transform) outputs['reverse_transforms'].insert(0,self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert(0,not self.inputs.invert_initial_moving_transform) ## Prepend transformCount += 1 for count in range(self.numberOfTransforms): forward_fileName, forward_inverse_mode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count],False) reverse_fileName, reverse_inverse_mode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count],True) outputs['forward_transforms'].append(os.path.abspath(forward_fileName)) outputs['forward_invert_flags'].append(forward_inverse_mode) outputs['reverse_transforms'].insert(0,os.path.abspath(reverse_fileName)) outputs['reverse_invert_flags'].insert(0,reverse_inverse_mode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + 'InverseComposite.h5' outputs['inverse_composite_transform'] = [os.path.abspath(fileName)] return outputs
def _list_outputs(self): outputs = self.output_spec().get() outputs['tract_image'] = self.inputs.out_filename if not isdefined(outputs['tract_image']): outputs['tract_image'] = op.abspath(self._gen_outfilename()) else: outputs['tract_image'] = os.path.abspath(outputs['tract_image']) return outputs
def _list_outputs(self): outputs = self.output_spec().get() for k in outputs.keys(): if isdefined(getattr(self.inputs, k)): outputs[k] = op.abspath(getattr(self.inputs, k)) return outputs
def _get_outputfilenames(self, inverse=False): output_filename = None if not inverse: if isdefined(self.inputs.output_warped_image) and self.inputs.output_warped_image: output_filename = self.inputs.output_warped_image if isinstance(output_filename, bool): output_filename = "%s_Warped.nii.gz" % self.inputs.output_transform_prefix else: output_filename = output_filename return output_filename inv_output_filename = None if isdefined(self.inputs.output_inverse_warped_image) and self.inputs.output_inverse_warped_image: inv_output_filename = self.inputs.output_inverse_warped_image if isinstance(inv_output_filename, bool): inv_output_filename = "%s_InverseWarped.nii.gz" % self.inputs.output_transform_prefix else: inv_output_filename = inv_output_filename return inv_output_filename
def _optionalMetricParameters(self, index): if (len(self.inputs.sampling_strategy) > index) and (self.inputs.sampling_strategy[index] is not None): if self.inputs.sampling_strategy[index] == "Dense": return '' # The default when nothing is specified if isdefined(self.inputs.sampling_percentage) and (self.inputs.sampling_percentage is not None): return ',%s,%g' % (self.inputs.sampling_strategy[index], self.inputs.sampling_percentage[index]) else: return ',%s' % self.inputs.sampling_strategy[index] return ''
def _parse_inputs(self, skip=None): if skip is None: skip = [] try: if (isdefined(self.inputs.grad_file) or isdefined(self.inputs.grad_fsl)): skip += ['in_bvec', 'in_bval'] is_bvec = isdefined(self.inputs.in_bvec) is_bval = isdefined(self.inputs.in_bval) if is_bvec or is_bval: if not is_bvec or not is_bval: raise RuntimeError('If using bvecs and bvals inputs, both' 'should be defined') skip += ['in_bval'] except AttributeError: pass return super(MRTrix3Base, self)._parse_inputs(skip=skip)
def _run_interface(self, runtime): src_paths = self._get_filelist(self.inputs.dicom_files) include_regexes = dcmstack.default_key_incl_res if isdefined(self.inputs.include_regexes): include_regexes += self.inputs.include_regexes exclude_regexes = dcmstack.default_key_excl_res if isdefined(self.inputs.exclude_regexes): exclude_regexes += self.inputs.exclude_regexes meta_filter = dcmstack.make_key_regex_filter(exclude_regexes, include_regexes) stack = dcmstack.DicomStack(meta_filter=meta_filter) for src_path in src_paths: src_dcm = dicom.read_file(src_path, force=True) stack.add_dcm(src_dcm) nii = stack.to_nifti(embed_meta=True) nw = NiftiWrapper(nii) self.out_path = self._get_out_path(nw.meta_ext.get_class_dict(("global", "const"))) if not self.inputs.embed_meta: nw.remove_extension() nb.save(nii, self.out_path) return runtime
def _run_interface(self, runtime): if isdefined(self.inputs.pattern_file): from pylab import imread pattern = imread(self.inputs.pattern_file)[:, :, 0:1] pattern *= self.inputs.SNR else: pattern = self._gen_pattern() noisy_sequence = self._gen_noisy_sequence(pattern) nim_tmap = nifti.Nifti1Image(noisy_sequence, np.diag([1, 1, 1, 1])) nifti.save(nim_tmap, "simulated_sequence.nii") return runtime
def _get_outputfilenames(self, inverse=False): output_filename = None if not inverse: if isdefined(self.inputs.output_warped_image) and \ self.inputs.output_warped_image: output_filename = self.inputs.output_warped_image if isinstance(output_filename, bool): output_filename = '%s_Warped.nii.gz' % self.inputs.output_transform_prefix else: output_filename = output_filename return output_filename inv_output_filename = None if isdefined(self.inputs.output_inverse_warped_image) and \ self.inputs.output_inverse_warped_image: inv_output_filename = self.inputs.output_inverse_warped_image if isinstance(inv_output_filename, bool): inv_output_filename = '%s_InverseWarped.nii.gz' % self.inputs.output_transform_prefix else: inv_output_filename = inv_output_filename return inv_output_filename
def _requires_warn(self, obj, name, old, new): """Part of the xor behavior """ if new: trait_spec = self.traits()[name] msg = None for trait_name in trait_spec.requires: if not isdefined(getattr(self, trait_name)): if not msg: msg = "Input %s requires inputs: %s" % (name, ", ".join(trait_spec.requires)) if msg: warn(msg)
def _optionalMetricParameters(self, index): if (len(self.inputs.sampling_strategy) > index) and (self.inputs.sampling_strategy[index] is not None): if self.inputs.sampling_strategy[index] == "Dense": return '' # The default when nothing is specified if isdefined(self.inputs.sampling_percentage) and ( self.inputs.sampling_percentage is not None): return ',%s,%g' % (self.inputs.sampling_strategy[index], self.inputs.sampling_percentage[index]) else: return ',%s' % self.inputs.sampling_strategy[index] return ''
def _format_arg(self, opt, spec, val): if opt == 'moving_image_mask': return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask) elif opt == 'transforms': self.numberOfTransforms = len(self.inputs.transforms) return self._formatRegistration() elif opt == 'initial_moving_transform': if self.inputs.invert_initial_moving_transform: return '--initial-moving-transform [ %s, 1 ]' % self.inputs.initial_moving_transform else: return '--initial-moving-transform [ %s, 0 ]' % self.inputs.initial_moving_transform elif opt == 'interpolation': # TODO: handle multilabel, gaussian, and bspline options return '--interpolation %s' % self.inputs.interpolation elif opt == 'output_transform_prefix': if isdefined(self.inputs.output_inverse_warped_image) and self.inputs.output_inverse_warped_image: return '--output [ %s, %s, %s ]' % (self.inputs.output_transform_prefix, self.inputs.output_warped_image, self.inputs.output_inverse_warped_image ) elif isdefined(self.inputs.output_warped_image) and self.inputs.output_warped_image: return '--output [ %s, %s ]' % (self.inputs.output_transform_prefix, self.inputs.output_warped_image ) else: return '--output %s' % self.inputs.output_transform_prefix return super(Registration, self)._format_arg(opt, spec, val)
def _run_interface(self, runtime): src_paths = self._get_filelist(self.inputs.dicom_files) include_regexes = dcmstack.default_key_incl_res if isdefined(self.inputs.include_regexes): include_regexes += self.inputs.include_regexes exclude_regexes = dcmstack.default_key_excl_res if isdefined(self.inputs.exclude_regexes): exclude_regexes += self.inputs.exclude_regexes meta_filter = dcmstack.make_key_regex_filter(exclude_regexes, include_regexes) stack = dcmstack.DicomStack(meta_filter=meta_filter) for src_path in src_paths: src_dcm = dicom.read_file(src_path, force=True) stack.add_dcm(src_dcm) nii = stack.to_nifti(embed_meta=True) nw = NiftiWrapper(nii) self.out_path = \ self._get_out_path(nw.meta_ext.get_class_dict(('global', 'const'))) if not self.inputs.embed_meta: nw.remove_extension() nb.save(nii, self.out_path) return runtime
def _list_outputs(self): outputs = self._outputs().get() outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] if not self.inputs.collapse_output_transforms: transformCount = 0 if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append( self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append( self.inputs.invert_initial_moving_transform) outputs['reverse_transforms'].insert( 0, self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert(0, not self.inputs.invert_initial_moving_transform) # Prepend transformCount += 1 for count in range(len(self.inputs.transforms)): forwardFileName, forwardInverseMode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count]) reverseFileName, reverseInverseMode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverseFileName)) outputs[ 'reverse_invert_flags'].insert(0, reverseInverseMode) transformCount += 1 else: transformCount = 0 for transform in ['GenericAffine', 'SyN']: # Only files returned by collapse_output_transforms forwardFileName, forwardInverseMode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, transform) reverseFileName, reverseInverseMode = self._outputFileNames(self.inputs.output_transform_prefix, transformCount, transform, True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].append( os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].append(reverseInverseMode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + \ 'InverseComposite.h5' outputs['inverse_composite_transform'] = [ os.path.abspath(fileName)] return outputs
def _format_arg(self, opt, spec, val): if opt == 'fixed_image_mask': if isdefined(self.inputs.moving_image_mask): return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask) else: return '--masks %s' % self.inputs.fixed_image_mask elif opt == 'transforms': return self._formatRegistration() elif opt == 'initial_moving_transform': try: doInvertTransform = int( self.inputs.invert_initial_moving_transform) except: doInvertTransform = 0 # Just do the default behavior return '--initial-moving-transform [ %s, %d ]' % ( self.inputs.initial_moving_transform, doInvertTransform) elif opt == 'initial_moving_transform_com': try: doCenterOfMassInit = int( self.inputs.initial_moving_transform_com) except: doCenterOfMassInit = 0 # Just do the default behavior return '--initial-moving-transform [ %s, %s, %d ]' % ( self.inputs.fixed_image[0], self.inputs.moving_image[0], doCenterOfMassInit) elif opt == 'interpolation': # TODO: handle multilabel, gaussian, and bspline options return '--interpolation %s' % self.inputs.interpolation elif opt == 'output_transform_prefix': out_filename = self._get_outputfilenames(inverse=False) inv_out_filename = self._get_outputfilenames(inverse=True) if out_filename and inv_out_filename: return '--output [ %s, %s, %s ]' % ( self.inputs.output_transform_prefix, out_filename, inv_out_filename) elif out_filename: return '--output [ %s, %s ]' % ( self.inputs.output_transform_prefix, out_filename) else: return '--output %s' % self.inputs.output_transform_prefix elif opt == 'winsorize_upper_quantile' or opt == 'winsorize_lower_quantile': if not self._quantilesDone: return self._formatWinsorizeImageIntensities() return '' # Must return something for argstr! # This feature was removed from recent versions of antsRegistration due to corrupt outputs. # elif opt == 'collapse_linear_transforms_to_fixed_image_header': # return self._formatCollapseLinearTransformsToFixedImageHeader() return super(Registration, self)._format_arg(opt, spec, val)
def _parse_inputs(self, skip=None): if skip is None: skip = [] if not isdefined(self.inputs.in_config): from distutils.spawn import find_executable path = find_executable(self._cmd) if path is None: path = os.getenv(MRTRIX3_HOME, '/opt/mrtrix3') else: path = op.dirname(op.dirname(path)) self.inputs.in_config = op.join( path, 'src/dwi/tractography/connectomics/' 'example_configs/fs_default.txt') return super(LabelConfig, self)._parse_inputs(skip=skip)
def get_form(config,mwf): from nipype.interfaces.traits_extension import isdefined if not isdefined(mwf.html_view): schema = colander.Schema() all_traits = config.trait_names() all_traits.remove('trait_added') all_traits.remove('trait_modified') for tr in all_traits: _type = type(config.trait(tr).trait_type) col_type = getNode(_type,tr,config) schema.add(col_type) form = Form(schema,buttons = ('submit',),action='') return form.render(appstruct=config.get()) else: form = Form(mwf.html_view(),buttons = ('submit',),action='') return form.render()
def _list_outputs(self): outputs = self._outputs().get() transformCount = 0 outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append( self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append( self.inputs.invert_initial_moving_transform) outputs['reverse_transforms'].insert( 0, self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert( 0, not self.inputs.invert_initial_moving_transform) ## Prepend transformCount += 1 for count in range(self.numberOfTransforms): forward_fileName, forward_inverse_mode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], False) reverse_fileName, reverse_inverse_mode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True) outputs['forward_transforms'].append( os.path.abspath(forward_fileName)) outputs['forward_invert_flags'].append(forward_inverse_mode) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverse_fileName)) outputs['reverse_invert_flags'].insert(0, reverse_inverse_mode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + 'InverseComposite.h5' outputs['inverse_composite_transform'] = [ os.path.abspath(fileName) ] return outputs
def _run_interface(self, runtime): phase_filename_list=self.inputs.phase json_filename_list=self.inputs.json truncate_echo=self.inputs.truncate_echo if not truncate_echo: truncate_echo=None mask_filename=self.inputs.mask freq_filename=self._list_outputs()['freq_filename'] if isdefined(self.inputs.weight): weight_filename=self.inputs.weight weight=nib.load(weight_filename).get_data() else: weight=None ne=len(phase_filename_list) ph_img_obj=nib.load(phase_filename_list[0]) shape=ph_img_obj.get_shape() voxel_size=ph_img_obj.header['pixdim'][1:4] ph_img=np.empty(shape+(ne,)) if weight is None: weight=np.ones(shape+(ne,)) count=0 phase_filename_list.sort() json_filename_list.sort() te=np.empty(ne) for imgloc,jsonloc in zip(phase_filename_list,json_filename_list): #assert os.path.splitext(jsonloc)[0] in os.path.splitext(imgloc)[0] ph_img[...,count]=nib.load(imgloc).get_data() with open(jsonloc) as f: te[count]=float(json.load(f)['EchoTime']) count+=1 eps = np.sqrt(sys.float_info.min) ph_img = ph_img + eps mask=nib.load(mask_filename).get_data() freq=pyQSM.frequencyEstimate.estimateFrequencyFromWrappedPhase(ph_img,voxel_size,te,mask,weight,truncateEcho=truncate_echo) niftifile=nib.Nifti1Pair(freq,ph_img_obj.affine) nib.save(niftifile,freq_filename) return runtime
def _get_out_path(self, meta, idx=None): '''Return the output path for the gernerated Nifti.''' if self.inputs.out_format: out_fmt = self.inputs.out_format else: #If no out_format is specified, use a sane default that will work #with the provided meta data. out_fmt = [] if not idx is None: out_fmt.append('%03d' % idx) if 'SeriesNumber' in meta: out_fmt.append('%(SeriesNumber)03d') if 'ProtocolName' in meta: out_fmt.append('%(ProtocolName)s') elif 'SeriesDescription' in meta: out_fmt.append('%(SeriesDescription)s') else: out_fmt.append('sequence') out_fmt = '-'.join(out_fmt) out_fn = (out_fmt % meta) + self.inputs.out_ext out_fn = sanitize_path_comp(out_fn) out_path = os.getcwd() if isdefined(self.inputs.out_path): out_path = op.abspath(self.inputs.out_path) # now, mkdir -p $out_path try: os.makedirs(out_path) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST and op.isdir(out_path): pass else: raise return op.join(out_path, out_fn)
class NiiWrangler(BaseInterface): input_spec = NiiWranglerInputSpec output_spec = NiiWranglerOutputSpec def __init__(self, *args, **kwargs): super(NiiWrangler, self).__init__(*args, **kwargs) self.t1_files = [] self.rsfmri_files = [] self.dwi_files = [] self.dwi_ap_files = [] self.dwi_pa_files = [] self.flair_files = [] self.fieldmap_mag = [] self.fieldmap_ph = [] self.bval = [] self.bvec = [] self.ep_TR = None self.fieldmap_mag_delta_te = "NONE" self.t1_sample_spacing = 0. self.ep_dwi_echo_spacings = None self.ep_rsfmri_echo_spacings = None self.ep_unwarp_dirs = None def _run_interface(self, runtime): import re import operator print "starting NII wrangler" nii_files = self.inputs.nii_files smap = self.inputs.series_map dinfo = self.inputs.dicom_info #block_averaging = self.inputs.block_struct_averaging s_num_reg = re.compile( ".*s(\d+)a(?!.*/)" ) # sux to use filename. make more robust if needed. nii_by_series = {} fails = [] extras = [] for fn in nii_files: try: # we only want the first nii for each series # TODO: find out what those others (A/B) are all about. fix this as needed. sn = int(s_num_reg.match(fn).groups()[0]) if sn in nii_by_series: extras.append(fn) continue nii_by_series[sn] = fn except Exception, e: fails.append(fn) if fails: raise ValueError( "Could not derive series number from file names: %s." % str(fails)) if extras: print >> sys.stderr, "\nWARNING: Ignoring extra niftis: %s\n" % str( extras) # add nifti names to the dicts m_count = 0 for sn, fn in nii_by_series.iteritems(): m = filter(lambda x: x.get("series_num", -1) == sn, dinfo) if not m: continue m_count += 1 m[0]["nifti_file"] = fn if not m_count == len(dinfo): raise ValueError( "incorrect number of nifti->series matches (%d/%d)" % (m_count, len(dinfo))) # time for some data wrangling nf = "nifti_file" sd = "series_desc" it = "image_type" t1fs = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("t1", []), dinfo) if nf in d ] #if block_averaging: # t1fs = [t1fs[0]] # t2fs = [t2fs[0]] self.t1_files = [d[nf] for d in t1fs] #get rsfmri, if no "resting state return default file" bs = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("rsfmri", []), dinfo) if nf in d ] self.rsfmri_files = [d[nf] for d in bs] #get dwi dwi = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("dwi", []), dinfo) if nf in d ] if len(dwi) == 0: print "no DTI acquired" self.dwi_files = ['nothing to proceed'] self.dwi_pa_files = ['nothing to proceed'] self.dwi_ap_files = ['nothing to proceed'] else: self.dwi_files = [d[nf] for d in dwi] dwi_pa = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("fieldmap_pa", []), dinfo) if nf in d ] self.dwi_pa_files = [d[nf] for d in dwi_pa] dwi_ap = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("fieldmap_ap", []), dinfo) if nf in d ] self.dwi_ap_files = [d[nf] for d in dwi_ap] flair = [ d for d in filter( lambda x: sd in x and x[sd] in smap.get("flair", []), dinfo) if nf in d ] if len(flair) == 0: print "no FLAIR acquired" self.flair_files = ['nothing to proceed'] else: self.flair_files = [d[nf] for d in flair] # we have to do some extra looking at the headers for the mag and phase fieldmaps too mag_fs = filter(lambda x: sd in x and x[sd] in smap.get( "fieldmap_magnitude", []) and it in x and isinstance(x[it], list) and len(x[it]) > 2 and x[it][2].strip().lower() == "m", dinfo) # we want the 3rd field of image type to be 'm' phase_fs = filter( lambda x: sd in x and x[sd] in smap.get("fieldmap_phase", [ ]) and it in x and isinstance(x[it], list) and len(x[ it]) > 2 and x[it][2].strip().lower() == "p", dinfo) # we want the 3rd field of image type to be 'p' self.fieldmap_mag = [d[nf] for d in mag_fs if nf in d] self.fieldmap_ph = [d[nf] for d in phase_fs if nf in d] # calculate echo spacing for rsfmri: #if more than one resting state scan was acquired: ep_rsfmri_echo_fail = False ep_TR_fail = False if len(bs) > 1: print "two or more resting-state scans" if isdefined(self.inputs.ep_rsfmri_echo_spacings): self.ep_rsfmri_echo_spacings = [ self.inputs.ep_rsfmri_echo_spacings for n in self.rsfmri_files ] elif bs and any([ "bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in bs ]): if not all([ "bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in bs ]): ep_rsfmri_echo_fail = True else: self.ep_rsfmri_echo_spacings = [ 1 / (d["bw_per_pix_phase_encode"] * d["acq_matrix_n"]) for d in bs ] else: self.ep_rsfmri_echo_spacings = [ "NONE" for n in self.rsfmri_files ] if isdefined(self.inputs.ep_TR): self.ep_TR = [self.inputs.ep_TR for n in self.rsfmri_files] elif bs and any(["TR" in d for d in bs]): if not all(["TR" in d for d in bs]): ep_TR_fail = True else: self.ep_TR = [d["TR"] for d in bs] else: self.ep_TR = ["NONE" for n in self.rsfmri_files] else: print "one resting-state scan" if isdefined(self.inputs.ep_rsfmri_echo_spacings): self.ep_rsfmri_echo_spacings = self.inputs.ep_rsfmri_echo_spacings elif bs and "bw_per_pix_phase_encode" in bs[ 0] and "acq_matrix_n" in bs[0]: if not "bw_per_pix_phase_encode" in bs[ 0] and "acq_matrix_n" in bs[0]: ep_rsfmri_echo_fail = True else: self.ep_rsfmri_echo_spacings = 1 / ( bs[0]["bw_per_pix_phase_encode"] * bs[0]["acq_matrix_n"]) else: self.ep_rsfmri_echo_spacings = "NONE" if isdefined(self.inputs.ep_TR): self.ep_TR = self.inputs.ep_TR elif bs and "TR" in bs[0]: if not "TR" in bs[0]: ep_TR_fail = True else: self.ep_TR = bs[0]["TR"] else: self.ep_TR = "NONE" ep_dwi_echo_fail = False if len(dwi) > 1: print "more than one dwi scan" if isdefined(self.inputs.ep_dwi_echo_spacings): self.ep_dwi_echo_spacings = [ self.inputs.ep_dwi_echo_spacings for n in self.dwi_files ] elif bs and any([ "bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in dwi ]): if not all([ "bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in dwi ]): ep_dwi_echo_fail = True else: self.ep_dwi_echo_spacings = [ 1 / (d["bw_per_pix_phase_encode"] * d["acq_matrix_n"]) for d in dwi ] else: self.ep_dwi_echo_spacings = ["NONE" for n in self.dwi_files] else: print "one dwi scan" if isdefined(self.inputs.ep_dwi_echo_spacings): self.ep_dwi_echo_spacings = self.inputs.ep_dwi_echo_spacings elif bs and "bw_per_pix_phase_encode" in bs[ 0] and "acq_matrix_n" in bs[0]: if not "bw_per_pix_phase_encode" in bs[ 0] and "acq_matrix_n" in bs[0]: ep_dwi_echo_fail = True else: self.ep_dwi_echo_spacings = 1 / ( bs[0]["bw_per_pix_phase_encode"] * bs[0]["acq_matrix_n"]) else: self.ep_dwi_echo_spacings = "NONE" # output delta te for magnitude fieldmap if available if mag_fs and self.fieldmap_mag and self.fieldmap_ph: self.fieldmap_mag_delta_te = mag_fs[0].get("delta_te", "NONE") else: self.fieldmap_mag_delta_te = "NONE" # # a BOLD image by any other name... # self.bold_names = ["bold_%d" % n for n in xrange(len(self.bolds))] # # we'll derive the ep unwarp dir in the future... for now, just set it in config if isdefined(self.inputs.ep_unwarp_dir): self.ep_unwarp_dirs = [ self.inputs.ep_unwarp_dir for n in self.rsfmri_files ] # if you have any polarity swapped series, apply that now pswaps = smap.get("polarity_swapped", []) if pswaps: for b_idx, uw_dir in enumerate(self.ep_unwarp_dirs): if bs[b_idx].get("series_desc", None) in pswaps: raw_dir = uw_dir.replace("-", "") self.ep_unwarp_dirs[ b_idx] = "-" + raw_dir if not "-" in uw_dir else raw_dir else: # fail. we can do better! raise ValueError( "We can't derive ep_unwarp_dir yet. Please set it in the nii wrangler config section." ) ### and let's do some sanity checking # warn if you're going to ignore field or magnitude phase maps if not (len(self.fieldmap_mag) and len(self.fieldmap_ph)): print >> sys.stderr, "\nWARNING: found %d magnitude fieldmaps and %d phase fieldmaps.\n" % ( len(self.fieldmap_mag), len(self.fieldmap_ph)) ### derive the derived values # t1_sample_spacing if t1fs and "RealDwellTime" in t1fs[0].keys(): self.t1_sample_spacing = t1fs[0]["RealDwellTime"] * math.pow( 10, -9) else: self.t1_sample_spacing = "NONE" # don't continue if there was screwiness around calculating ep echo spacing if ep_rsfmri_echo_fail: raise ValueError( "Unabel to calculate fmri ep echo spacing. Try specifying manually in nii wrangler config section." ) if ep_dwi_echo_fail: raise ValueError( "Unabel to calculate dwi ep echo spacing. Try specifying manually in nii wrangler config section." ) if ep_TR_fail: raise ValueError( "Unabel to derive TR. Try specifying manually in nii wrangler config section." ) return runtime
class NiiWrangler(BaseInterface): input_spec = NiiWranglerInputSpec output_spec = NiiWranglerOutputSpec def __init__(self, *args, **kwargs): super(NiiWrangler, self).__init__(*args, **kwargs) self.t1_files = [] self.t2_files = [] self.bolds = [] self.bold_names = [] self.sbrefs = [] self.fieldmap_pos = [] self.fieldmap_neg = [] self.fieldmap_mag = [] self.fieldmap_ph = [] self.fieldmap_mag_delta_te = "NONE" self.t1_sample_spacing = 0. self.t2_sample_spacing = 0. self.ep_e_spaces = None self.ep_unwarp_dirs = None def _run_interface(self, runtime): import re import operator nii_files = self.inputs.nii_files smap = self.inputs.series_map dinfo = self.inputs.dicom_info block_averaging = self.inputs.block_struct_averaging s_num_reg = re.compile(".*s(\d+)a(?!.*/)") # sux to use filename. make more robust if needed. nii_by_series = {} fails = [] extras = [] for fn in nii_files: try: # we only want the first nii for each series # TODO: find out what those others (A/B) are all about. fix this as needed. sn = int(s_num_reg.match(fn).groups()[0]) if sn in nii_by_series: extras.append(fn) continue nii_by_series[sn] = fn except Exception, e: fails.append(fn) if fails: raise ValueError("Could not derive series number from file names: %s." % str(fails)) if extras: print >> sys.stderr, "\nWARNING: Ignoring extra niftis: %s\n" % str(extras) # add nifti names to the dicts m_count = 0 for sn, fn in nii_by_series.iteritems(): m = filter(lambda x: x.get("series_num",-1) == sn, dinfo) if not m: continue m_count += 1 m[0]["nifti_file"] = fn if not m_count == len(dinfo): raise ValueError("incorrect number of nifti->series matches (%d/%d)" % (m_count, len(dinfo))) # time for some data wrangling nf = "nifti_file" sd = "series_desc" it = "image_type" t1fs = [d for d in filter(lambda x: sd in x and x[sd] in smap.get("t1",[]), dinfo) if nf in d] t2fs = [d for d in filter(lambda x: sd in x and x[sd] in smap.get("t2",[]), dinfo) if nf in d] if block_averaging: t1fs = [t1fs[0]] t2fs = [t2fs[0]] self.t1_files = [d[nf] for d in t1fs] self.t2_files = [d[nf] for d in t2fs] bs = [d for d in filter(lambda x: sd in x and x[sd] in smap.get("bold",[]), dinfo) if nf in d] self.bolds = [d[nf] for d in bs] self.sbrefs = [d[nf] for d in filter(lambda x: sd in x and x[sd] in smap.get("bold_sbref",[]), dinfo) if nf in d] # for now, we only support one se fieldmap pair. In the future, we'll implement # a more flexible policy here. This is actually really crappy... but the user can always # flip the unwarpdir through config :/ s_policy = self.inputs.ep_fieldmap_selection pos_types = reduce(operator.add, [smap.get(k, []) for k in POS_FIELDMAPS]) neg_types = reduce(operator.add, [smap.get(k, []) for k in NEG_FIELDMAPS]) pos = [d for d in filter(lambda x: sd in x and x[sd] in pos_types, dinfo) if nf in d] neg = [d for d in filter(lambda x: sd in x and x[sd] in neg_types, dinfo) if nf in d] both = zip(pos,neg) if s_policy == "most_recent": pfs = [] nfs = [] for bold in bs: sn = bold["series_num"] # we want the last of the images with a lower sn, or the firs tof the images with a higher sn earlier = filter(lambda x: x[0]["series_num"] < sn and x[1]["series_num"] < sn, both) later = filter(lambda x: x[0]["series_num"] < sn and x[1]["series_num"] < sn, both) if earlier: pfs.append(earlier[-1][0][nf]) nfs.append(earlier[-1][1][nf]) elif later: pfs.append(later[0][0][nf]) nfs.append(later[0][1][nf]) else: print "This... should never happen." self.fieldmaps_pos = pfs self.fieldmaps_neg = nfs else: # default to "first" self.fieldmaps_pos = [pos[0][nf] for n in self.bolds] if pos else [] self.fieldmaps_neg = [neg[0][nf] for n in self.bolds] if pos else [] # we have to do some extra looking at the headers for the mag and phase fieldmaps too mag_fs = filter(lambda x: sd in x and x[sd] in smap.get("fieldmap_magnitude",[]) and it in x and isinstance(x[it], list) and len(x[it]) > 2 and x[it][2].strip().lower() == "m", dinfo) # we want the 3rd field of image type to be 'm' phase_fs = filter(lambda x: sd in x and x[sd] in smap.get("fieldmap_phase",[]) and it in x and isinstance(x[it], list) and len(x[it]) > 2 and x[it][2].strip().lower() == "p", dinfo) # we want the 3rd field of image type to be 'p' self.fieldmap_mag = [d[nf] for d in mag_fs if nf in d] self.fieldmap_ph = [d[nf] for d in phase_fs if nf in d] # calculate echo spacing for each of the bold images ep_calc_fail = False if isdefined(self.inputs.ep_echo_spacing): self.ep_e_spaces = [self.inputs.ep_echo_spacing for n in self.bolds] elif bs and any(["bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in bs]): if not all(["bw_per_pix_phase_encode" in d and "acq_matrix_n" in d for d in bs]): ep_calc_fail = True else: self.ep_e_spaces = [1/(d["bw_per_pix_phase_encode"] * d["acq_matrix_n"]) for d in bs] else: self.ep_e_spaces = ["NONE" for n in self.bolds] # output delta te for magnitude fieldmap if available if mag_fs and self.fieldmap_mag and self.fieldmap_ph: self.fieldmap_mag_delta_te = mag_fs[0].get("delta_te","NONE") else: self.fieldmap_mag_delta_te = "NONE" # a BOLD image by any other name... self.bold_names = ["bold_%d" % n for n in xrange(len(self.bolds))] # we'll derive the ep unwarp dir in the future... for now, just set it in config if isdefined(self.inputs.ep_unwarp_dir): self.ep_unwarp_dirs = [self.inputs.ep_unwarp_dir for n in self.bolds] # if you have any polarity swapped series, apply that now pswaps = smap.get("polarity_swapped", []) if pswaps: for b_idx, uw_dir in enumerate(self.ep_unwarp_dirs): if bs[b_idx].get("series_desc",None) in pswaps: raw_dir = uw_dir.replace("-","") self.ep_unwarp_dirs[b_idx] = "-"+raw_dir if not "-" in uw_dir else raw_dir else: # fail. we can do better! raise ValueError("We can't derive ep_unwarp_dir yet. Please set it in the nii wrangler config section.") ### and let's do some sanity checking # warn if you're going to ignore field or magnitude phase maps if not (len(self.fieldmap_mag) and len(self.fieldmap_ph)): print >> sys.stderr, "\nWARNING: found %d magnitude fieldmaps and %d phase fieldmaps.\n" % (len(self.fieldmap_mag), len(self.fieldmap_ph)) # if we have any sbrefs, we should have one for each bold if self.sbrefs and len(self.sbrefs) != len(self.bolds): raise ValueError("Had %d bolds, but %d SBRefs. If there are any SBRefs, there must be one for each BOLD image" % (len(self.bolds), len(self.sbrefs))) # and if we DON'T have any, then we need a list full of NONE if not self.sbrefs: self.sbrefs = ["NONE" for n in self.bolds] # we should have the same number of positive and negative fieldmaps if len(self.fieldmaps_pos) != len(self.fieldmaps_neg): raise ValueError("Mismatched number of pos and neg fieldmaps (%d/%d)" % (len(self.fieldmaps_pos), len(self.fieldmaps_neg))) # we also need the same number of pos/neg se fieldmaps as bold images if len(self.fieldmaps_pos) != len(self.bolds): raise ValueError("Mismatched number of pos/neg fieldmaps and bolds (%d/%d)" % (len(self.fieldmaps_pos), len(self.bolds))) ### derive the derived values # t1_sample_spacing if t1fs and "RealDwellTime" in t1fs[0].keys(): self.t1_sample_spacing = t1fs[0]["RealDwellTime"] * math.pow(10,-9) else: self.t1_sample_spacing = "NONE" # t2_sample_spacing if t2fs and "RealDwellTime" in t2fs[0].keys(): self.t2_sample_spacing = t2fs[0]["RealDwellTime"] * math.pow(10,-9) else: self.t2_sample_spacing = "NONE" # don't continue if there was screwiness around calculating ep echo spacing if ep_calc_fail: raise ValueError("Unabel to calculate ep echo spacing. Try specifying manually in nii wrangler config section.") return runtime
def _list_outputs(self): outputs = self._outputs().get() outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] # invert_initial_moving_transform should be always defined, even if # there's no initial transform invert_initial_moving_transform = False if isdefined(self.inputs.invert_initial_moving_transform): invert_initial_moving_transform = self.inputs.invert_initial_moving_transform if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = os.path.abspath(fileName) fileName = self.inputs.output_transform_prefix + \ 'InverseComposite.h5' outputs['inverse_composite_transform'] = os.path.abspath(fileName) else: # If composite transforms are written, then individuals are not written (as of 2014-10-26 if not self.inputs.collapse_output_transforms: transformCount = 0 if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append( self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append( invert_initial_moving_transform) outputs['reverse_transforms'].insert( 0, self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert( 0, not invert_initial_moving_transform) # Prepend transformCount += 1 elif isdefined(self.inputs.initial_moving_transform_com): forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, 'Initial') reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, 'Initial', True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(False) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].insert(0, True) transformCount += 1 for count in range(len(self.inputs.transforms)): forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count]) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].insert( 0, reverseInverseMode) transformCount += 1 else: transformCount = 0 isLinear = [ any(self._linear_transform_names == t) for t in self.inputs.transforms ] collapse_list = [] if isdefined(self.inputs.initial_moving_transform) or \ isdefined(self.inputs.initial_moving_transform_com): isLinear.insert(0, True) # Only files returned by collapse_output_transforms if any(isLinear): collapse_list.append('GenericAffine') if not all(isLinear): collapse_list.append('SyN') for transform in collapse_list: forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform, inverse=False) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform, inverse=True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].append( os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].append(reverseInverseMode) transformCount += 1 out_filename = self._get_outputfilenames(inverse=False) inv_out_filename = self._get_outputfilenames(inverse=True) if out_filename: outputs['warped_image'] = os.path.abspath(out_filename) if inv_out_filename: outputs['inverse_warped_image'] = os.path.abspath(inv_out_filename) if len(self.inputs.save_state): outputs['save_state'] = os.path.abspath(self.inputs.save_state) return outputs
def _list_outputs(self): outputs = self._outputs().get() outputs['forward_transforms'] = [] outputs['forward_invert_flags'] = [] outputs['reverse_transforms'] = [] outputs['reverse_invert_flags'] = [] if not self.inputs.collapse_output_transforms: transformCount = 0 if isdefined(self.inputs.initial_moving_transform): outputs['forward_transforms'].append( self.inputs.initial_moving_transform) outputs['forward_invert_flags'].append( self.inputs.invert_initial_moving_transform) outputs['reverse_transforms'].insert( 0, self.inputs.initial_moving_transform) outputs['reverse_invert_flags'].insert( 0, not self.inputs.invert_initial_moving_transform) # Prepend transformCount += 1 elif isdefined(self.inputs.initial_moving_transform_com): #forwardFileName, _ = self._outputFileNames(self.inputs.output_transform_prefix, # transformCount, # 'Initial') #outputs['forward_transforms'].append(forwardFileName) transformCount += 1 for count in range(len(self.inputs.transforms)): forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count]) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, self.inputs.transforms[count], True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].insert( 0, os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].insert(0, reverseInverseMode) transformCount += 1 else: transformCount = 0 for transform in [ 'GenericAffine', 'SyN' ]: # Only files returned by collapse_output_transforms forwardFileName, forwardInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform) reverseFileName, reverseInverseMode = self._outputFileNames( self.inputs.output_transform_prefix, transformCount, transform, True) outputs['forward_transforms'].append( os.path.abspath(forwardFileName)) outputs['forward_invert_flags'].append(forwardInverseMode) outputs['reverse_transforms'].append( os.path.abspath(reverseFileName)) outputs['reverse_invert_flags'].append(reverseInverseMode) transformCount += 1 if self.inputs.write_composite_transform: fileName = self.inputs.output_transform_prefix + 'Composite.h5' outputs['composite_transform'] = [os.path.abspath(fileName)] fileName = self.inputs.output_transform_prefix + \ 'InverseComposite.h5' outputs['inverse_composite_transform'] = [ os.path.abspath(fileName) ] out_filename = self._get_outputfilenames(inverse=False) inv_out_filename = self._get_outputfilenames(inverse=True) if out_filename: outputs['warped_image'] = os.path.abspath(out_filename) if inv_out_filename: outputs['inverse_warped_image'] = os.path.abspath(inv_out_filename) return outputs