def execute(): #pylint: disable=unused-variable shells = [ int(round(float(x))) for x in image.mrinfo('dwi.mif', 'shell_bvalues').split() ] # Get lmax information (if provided) lmax = [ ] if app.ARGS.lmax: lmax = [ int(x.strip()) for x in app.ARGS.lmax.split(',') ] if not len(lmax) == len(shells): raise MRtrixError('Number of manually-defined lmax\'s (' + str(len(lmax)) + ') does not match number of b-value shells (' + str(len(shells)) + ')') for shell_l in lmax: if shell_l % 2: raise MRtrixError('Values for lmax must be even') if shell_l < 0: raise MRtrixError('Values for lmax must be non-negative') # Do we have directions, or do we need to calculate them? if not os.path.exists('dirs.mif'): run.command('dwi2tensor dwi.mif - -mask in_voxels.mif | tensor2metric - -vector dirs.mif') # Get response function bvalues_option = ' -shells ' + ','.join(map(str,shells)) lmax_option = '' if lmax: lmax_option = ' -lmax ' + ','.join(map(str,lmax)) run.command('amp2response dwi.mif in_voxels.mif dirs.mif response.txt' + bvalues_option + lmax_option) run.function(shutil.copyfile, 'response.txt', path.from_user(app.ARGS.output, False)) if app.ARGS.voxels: run.command('mrconvert in_voxels.mif ' + path.from_user(app.ARGS.voxels), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE)
def check_gif_input(image_path): from mrtrix3 import image, MRtrixError dim = image.Header(image_path).size() if len(dim) < 4: raise MRtrixError('Image \'' + image_path + '\' does not look like GIF segmentation (less than 4 spatial dimensions)') if min(dim[:4]) == 1: raise MRtrixError('Image \'' + image_path + '\' does not look like GIF segmentation (axis with size 1)')
def dot(input_a, input_b): #pylint: disable=unused-variable from mrtrix3 import MRtrixError if not input_a: if input_b: raise MRtrixError('Dimension mismatch (0 vs. ' + str(len(input_b)) + ')') return [] if is_2d_matrix(input_a): if not is_2d_matrix(input_b): raise MRtrixError( 'Both inputs must be either 1D vectors or 2D matrices') if len(input_a[0]) != len(input_b): raise MRtrixError('Invalid dimensions for matrix dot product(' + \ str(len(input_a)) + 'x' + str(len(input_a[0])) + ' vs. ' + \ str(len(input_b)) + 'x' + str(len(input_b[0])) + ')') return [[ sum(x * y for x, y in zip(a_row, b_col)) for b_col in zip(*input_b) ] for a_row in input_a] if is_2d_matrix(input_b): raise MRtrixError( 'Both inputs must be either 1D vectors or 2D matrices') if len(input_a) != len(input_b): raise MRtrixError('Dimension mismatch (' + str(len(input_a)) + ' vs. ' + str(len(input_b)) + ')') return sum([x * y for x, y in zip(input_a, input_b)])
def execute(): #pylint: disable=unused-variable if utils.is_windows(): raise MRtrixError('Script cannot run using FSL on Windows due to FSL dependency') if not os.environ.get('FSLDIR', ''): raise MRtrixError('Environment variable FSLDIR is not set; please run appropriate FSL configuration script') fast_cmd = fsl.exe_name('fast') app.warn('Use of fsl algorithm in dwibiascorrect script is discouraged due to its strong dependence ' + \ 'on brain masking (specifically its inability to correct voxels outside of this mask).' + \ 'Use of the ants algorithm is recommended for quantitative DWI analyses.') # Generate a mean b=0 image run.command('dwiextract in.mif - -bzero | mrmath - mean mean_bzero.mif -axis 3') # FAST doesn't accept a mask input; therefore need to explicitly mask the input image run.command('mrcalc mean_bzero.mif mask.mif -mult - | mrconvert - mean_bzero_masked.nii -strides -1,+2,+3') run.command(fast_cmd + ' -t 2 -o fast -n 3 -b mean_bzero_masked.nii') bias_path = fsl.find_image('fast_bias') # Rather than using a bias field estimate of 1.0 outside the brain mask, zero-fill the # output image outside of this mask run.command('mrcalc in.mif ' + bias_path + ' -div mask.mif -mult result.mif') run.command('mrconvert result.mif ' + path.from_user(app.ARGS.output), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE) if app.ARGS.bias: run.command('mrconvert ' + bias_path + ' ' + path.from_user(app.ARGS.bias), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE)
def execute(): #pylint: disable=unused-variable lut_input_path = 'LUT.txt' if not os.path.exists('LUT.txt'): freesurfer_home = os.environ.get('FREESURFER_HOME', '') if not freesurfer_home: raise MRtrixError( 'Environment variable FREESURFER_HOME is not set; please run appropriate FreeSurfer configuration script, set this variable manually, or provide script with path to file FreeSurferColorLUT.txt using -lut option' ) lut_input_path = os.path.join(freesurfer_home, 'FreeSurferColorLUT.txt') if not os.path.isfile(lut_input_path): raise MRtrixError( 'Could not find FreeSurfer lookup table file (expected location: ' + lut_input_path + '), and none provided using -lut') if app.ARGS.sgm_amyg_hipp: lut_output_file_name = 'FreeSurfer2ACT_sgm_amyg_hipp.txt' else: lut_output_file_name = 'FreeSurfer2ACT.txt' lut_output_path = os.path.join(path.shared_data_path(), path.script_subdir_name(), lut_output_file_name) if not os.path.isfile(lut_output_path): raise MRtrixError( 'Could not find lookup table file for converting FreeSurfer parcellation output to tissues (expected location: ' + lut_output_path + ')') # Initial conversion from FreeSurfer parcellation to five principal tissue types run.command('labelconvert input.mif ' + lut_input_path + ' ' + lut_output_path + ' indices.mif') # Crop to reduce file size if app.ARGS.nocrop: image = 'indices.mif' else: image = 'indices_cropped.mif' run.command( 'mrthreshold indices.mif - -abs 0.5 | mrgrid indices.mif crop ' + image + ' -mask -') # Convert into the 5TT format for ACT run.command('mrcalc ' + image + ' 1 -eq cgm.mif') run.command('mrcalc ' + image + ' 2 -eq sgm.mif') run.command('mrcalc ' + image + ' 3 -eq wm.mif') run.command('mrcalc ' + image + ' 4 -eq csf.mif') run.command('mrcalc ' + image + ' 5 -eq path.mif') run.command( 'mrcat cgm.mif sgm.mif wm.mif csf.mif path.mif - -axis 3 | mrconvert - result.mif -datatype float32' ) run.command('mrconvert result.mif ' + path.from_user(app.ARGS.output), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE)
def check_3d_nonunity(image_in): #pylint: disable=unused-variable from mrtrix3 import app #pylint: disable=import-outside-toplevel if not isinstance(image_in, Header): if not isinstance(image_in, STRING_TYPES): raise MRtrixError('Error trying to test \'' + str(image_in) + '\': Not an image header or file path') image_in = Header(image_in) if len(image_in.size()) < 3: raise MRtrixError('Image \'' + image_in.name() + '\' does not contain 3 spatial dimensions') if min(image_in.size()[:3]) == 1: raise MRtrixError('Image \'' + image_in.name() + '\' does not contain 3D spatial information (has axis with size 1)') app.debug('Image \'' + image_in.name() + '\' is >= 3D, and does not contain a unity spatial dimension')
def load_transform(filename, **kwargs): #pylint: disable=unused-variable data = load_matrix(filename, **kwargs) if len(data) == 4: if any(a!=b for a, b in zip(data[3], _TRANSFORM_LAST_ROW)): raise MRtrixError('File "' + filename + '" does not contain a valid transform (fourth line contains values other than "0,0,0,1")') elif len(data) == 3: data.append(_TRANSFORM_LAST_ROW) else: raise MRtrixError('File "' + filename + '" does not contain a valid transform (must contain 3 or 4 lines)') if len(data[0]) != 4: raise MRtrixError('File "' + filename + '" does not contain a valid transform (must contain 4 columns)') return data
def match(image_one, image_two, **kwargs): #pylint: disable=unused-variable, too-many-return-statements from mrtrix3 import app #pylint: disable=import-outside-toplevel up_to_dim = kwargs.pop('up_to_dim', 0) check_transform = kwargs.pop('check_transform', True) if kwargs: raise TypeError('Unsupported keyword arguments passed to image.match(): ' + str(kwargs)) if not isinstance(image_one, Header): if not isinstance(image_one, STRING_TYPES): raise MRtrixError('Error trying to test \'' + str(image_one) + '\': Not an image header or file path') image_one = Header(image_one) if not isinstance(image_two, Header): if not isinstance(image_two, STRING_TYPES): raise MRtrixError('Error trying to test \'' + str(image_two) + '\': Not an image header or file path') image_two = Header(image_two) debug_prefix = '\'' + image_one.name() + '\' \'' + image_two.name() + '\'' # Handle possibility of only checking up to a certain axis if up_to_dim: if up_to_dim > min(len(image_one.size()), len(image_two.size())): app.debug(debug_prefix + ' dimensionality less than specified maximum (' + str(up_to_dim) + ')') return False else: if len(image_one.size()) != len(image_two.size()): app.debug(debug_prefix + ' dimensionality mismatch (' + str(len(image_one.size())) + ' vs. ' + str(len(image_two.size())) + ')') return False up_to_dim = len(image_one.size()) # Image dimensions if not image_one.size()[:up_to_dim] == image_two.size()[:up_to_dim]: app.debug(debug_prefix + ' axis size mismatch (' + str(image_one.size()) + ' ' + str(image_two.size()) + ')') return False # Voxel size for one, two in zip(image_one.spacing()[:up_to_dim], image_two.spacing()[:up_to_dim]): if one and two and not math.isnan(one) and not math.isnan(two): if (abs(two-one) / (0.5*(one+two))) > 1e-04: app.debug(debug_prefix + ' voxel size mismatch (' + str(image_one.spacing()) + ' ' + str(image_two.spacing()) + ')') return False # Image transform if check_transform: for line_one, line_two in zip(image_one.transform(), image_two.transform()): for one, two in zip(line_one[:3], line_two[:3]): if abs(one-two) > 1e-4: app.debug(debug_prefix + ' transform (rotation) mismatch (' + str(image_one.transform()) + ' ' + str(image_two.transform()) + ')') return False if abs(line_one[3]-line_two[3]) > 1e-2: app.debug(debug_prefix + ' transform (translation) mismatch (' + str(image_one.transform()) + ' ' + str(image_two.transform()) + ')') return False # Everything matches! app.debug(debug_prefix + ' image match') return True
def suffix(): #pylint: disable=unused-variable from mrtrix3 import app #pylint: disable=import-outside-toplevel global _SUFFIX if _SUFFIX: return _SUFFIX fsl_output_type = os.environ.get('FSLOUTPUTTYPE', '') if fsl_output_type == 'NIFTI': app.debug('NIFTI -> .nii') _SUFFIX = '.nii' elif fsl_output_type == 'NIFTI_GZ': app.debug('NIFTI_GZ -> .nii.gz') _SUFFIX = '.nii.gz' elif fsl_output_type == 'NIFTI_PAIR': app.debug('NIFTI_PAIR -> .img') _SUFFIX = '.img' elif fsl_output_type == 'NIFTI_PAIR_GZ': raise MRtrixError( 'MRtrix3 does not support compressed NIFTI pairs; please change FSLOUTPUTTYPE environment variable' ) elif fsl_output_type: app.warn( 'Unrecognised value for environment variable FSLOUTPUTTYPE (\"' + fsl_output_type + '\"): Expecting compressed NIfTIs, but FSL commands may fail') _SUFFIX = '.nii.gz' else: app.warn( 'Environment variable FSLOUTPUTTYPE not set; FSL commands may fail, or script may fail to locate FSL command outputs' ) _SUFFIX = '.nii.gz' return _SUFFIX
def load_matrix(filename, **kwargs): #pylint: disable=unused-variable data = load_numeric(filename, **kwargs) columns = len(data[0]) for line in data[1:]: if len(line) != columns: raise MRtrixError('Inconsistent number of columns in matrix text file "' + filename + '"') return data
def execute(): #pylint: disable=unused-variable if not find_executable('N4BiasFieldCorrection'): raise MRtrixError('Could not find ANTS program N4BiasFieldCorrection; please check installation') for key in sorted(OPT_N4_BIAS_FIELD_CORRECTION): if hasattr(app.ARGS, 'ants.' + key): val = getattr(app.ARGS, 'ants.' + key) if val is not None: OPT_N4_BIAS_FIELD_CORRECTION[key] = (val, 'user defined') ants_options = ' '.join(['-%s %s' %(k, v[0]) for k, v in OPT_N4_BIAS_FIELD_CORRECTION.items()]) # Generate a mean b=0 image run.command('dwiextract in.mif - -bzero | mrmath - mean mean_bzero.mif -axis 3') # Use the brain mask as a weights image rather than a mask; means that voxels at the edge of the mask # will have a smoothly-varying bias field correction applied, rather than multiplying by 1.0 outside the mask run.command('mrconvert mean_bzero.mif mean_bzero.nii -strides +1,+2,+3') run.command('mrconvert mask.mif mask.nii -strides +1,+2,+3') init_bias_path = 'init_bias.nii' corrected_path = 'corrected.nii' run.command('N4BiasFieldCorrection -d 3 -i mean_bzero.nii -w mask.nii -o [' + corrected_path + ',' + init_bias_path + '] ' + ants_options) # N4 can introduce large differences between subjects via a global scaling of the bias field # Estimate this scaling based on the total integral of the pre- and post-correction images within the brain mask input_integral = float(run.command('mrcalc mean_bzero.mif mask.mif -mult - | mrmath - sum - -axis 0 | mrmath - sum - -axis 1 | mrmath - sum - -axis 2 | mrdump -').stdout) output_integral = float(run.command('mrcalc ' + corrected_path + ' mask.mif -mult - | mrmath - sum - -axis 0 | mrmath - sum - -axis 1 | mrmath - sum - -axis 2 | mrdump -').stdout) multiplier = output_integral / input_integral app.debug('Integrals: Input = ' + str(input_integral) + '; Output = ' + str(output_integral) + '; resulting multiplier = ' + str(multiplier)) run.command('mrcalc ' + init_bias_path + ' ' + str(multiplier) + ' -mult bias.mif') # Common final steps for all algorithms run.command('mrcalc in.mif bias.mif -div result.mif') run.command('mrconvert result.mif ' + path.from_user(app.ARGS.output), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE) if app.ARGS.bias: run.command('mrconvert bias.mif ' + path.from_user(app.ARGS.bias), mrconvert_keyval=path.from_user(app.ARGS.input, False), force=app.FORCE_OVERWRITE)
def execute(): #pylint: disable=unused-variable grad_option = '' if app.ARGS.grad: grad_option = ' -grad ' + path.from_user(app.ARGS.grad) elif app.ARGS.fslgrad: grad_option = ' -fslgrad ' + path.from_user(app.ARGS.fslgrad[0]) + ' ' + path.from_user(app.ARGS.fslgrad[1]) if app.ARGS.percentile: if app.ARGS.percentile < 0.0 or app.ARGS.percentile > 100.0: raise MRtrixError('-percentile value must be between 0 and 100') intensities = [float(value) for value in run.command('dwiextract ' + path.from_user(app.ARGS.input_dwi) + grad_option + ' -bzero - | ' + \ 'mrmath - mean - -axis 3 | ' + \ 'mrdump - -mask ' + path.from_user(app.ARGS.input_mask)).stdout.splitlines()] intensities = sorted(intensities) float_index = 0.01 * app.ARGS.percentile * len(intensities) lower_index = int(math.floor(float_index)) if app.ARGS.percentile == 100.0: reference_value = intensities[-1] else: interp_mu = float_index - float(lower_index) reference_value = (1.0-interp_mu)*intensities[lower_index] + interp_mu*intensities[lower_index+1] else: reference_value = float(run.command('dwiextract ' + path.from_user(app.ARGS.input_dwi) + grad_option + ' -bzero - | ' + \ 'mrmath - mean - -axis 3 | ' + \ 'mrstats - -mask ' + path.from_user(app.ARGS.input_mask) + ' -output median').stdout) multiplier = app.ARGS.intensity / reference_value run.command('mrcalc ' + path.from_user(app.ARGS.input_dwi) + ' ' + str(multiplier) + ' -mult - | ' + \ 'mrconvert - ' + path.from_user(app.ARGS.output_dwi) + grad_option, \ mrconvert_keyval=path.from_user(app.ARGS.input_dwi, False), \ force=app.FORCE_OVERWRITE)
def load_vector(filename, **kwargs): #pylint: disable=unused-variable data = load_matrix(filename, **kwargs) if len(data) == 1: return data[0] for line in data: if len(line) != 1: raise MRtrixError('File "' + filename + '" does not contain vector data (multiple columns detected)') return [ line[0] for line in data ]
def __init__(self, image_path): from mrtrix3 import app, path, run #pylint: disable=import-outside-toplevel filename = path.name_temporary('json') command = [ run.exe_name(run.version_match('mrinfo')), image_path, '-json_all', filename ] if app.VERBOSITY > 1: app.console('Loading header for image file \'' + image_path + '\'') app.debug(str(command)) result = subprocess.call(command, stdout=None, stderr=None) if result: raise MRtrixError( 'Could not access header information for image \'' + image_path + '\'') try: with open(filename, 'r') as json_file: data = json.load(json_file) except UnicodeDecodeError: with open(filename, 'r') as json_file: data = json.loads(json_file.read().decode('utf-8', errors='replace')) os.remove(filename) try: #self.__dict__.update(data) # Load the individual header elements manually, for a couple of reasons: # - So that pylint knows that they'll be there # - Write to private members, and give read-only access self._name = data['name'] self._size = data['size'] self._spacing = data['spacing'] self._strides = data['strides'] self._format = data['format'] self._datatype = data['datatype'] self._intensity_offset = data['intensity_offset'] self._intensity_scale = data['intensity_scale'] self._transform = data['transform'] if not 'keyval' in data or not data['keyval']: self._keyval = {} else: self._keyval = data['keyval'] except: raise MRtrixError( 'Error in reading header information from file \'' + image_path + '\'') app.debug(str(vars(self)))
def direction(string): #pylint: disable=unused-variable from mrtrix3 import app #pylint: disable=import-outside-toplevel pe_dir = '' try: pe_axis = abs(int(string)) if pe_axis > 2: raise MRtrixError( 'When specified as a number, phase encode axis must be either 0, 1 or 2 (positive or negative)' ) reverse = (string.contains('-')) # Allow -0 pe_dir = [0, 0, 0] if reverse: pe_dir[pe_axis] = -1 else: pe_dir[pe_axis] = 1 except: string = string.lower() if string == 'lr': pe_dir = [1, 0, 0] elif string == 'rl': pe_dir = [-1, 0, 0] elif string == 'pa': pe_dir = [0, 1, 0] elif string == 'ap': pe_dir = [0, -1, 0] elif string == 'is': pe_dir = [0, 0, 1] elif string == 'si': pe_dir = [0, 0, -1] elif string == 'i': pe_dir = [1, 0, 0] elif string == 'i-': pe_dir = [-1, 0, 0] elif string == 'j': pe_dir = [0, 1, 0] elif string == 'j-': pe_dir = [0, -1, 0] elif string == 'k': pe_dir = [0, 0, 1] elif string == 'k-': pe_dir = [0, 0, -1] else: raise MRtrixError( 'Unrecognized phase encode direction specifier: ' + string) app.debug(string + ' -> ' + str(pe_dir)) return pe_dir
def save(filename, scheme, **kwargs): #pylint: disable=unused-variable from mrtrix3 import matrix #pylint: disable=import-outside-toplevel add_to_command_history = bool(kwargs.pop('add_to_command_history', True)) header = kwargs.pop('header', {}) if kwargs: raise TypeError( 'Unsupported keyword arguments passed to phaseencoding.save(): ' + str(kwargs)) if not scheme: raise MRtrixError( 'phaseencoding.save() cannot be run on an empty scheme') if not matrix.is_2d_matrix(scheme): raise TypeError('Input to phaseencoding.save() must be a 2D matrix') if len(scheme[0]) != 4: raise MRtrixError('Input to phaseencoding.save() not a valid scheme ' '(contains ' + str(len(scheme[0])) + ' columns rather than 4)') if header: if isinstance(header, STRING_TYPES): header = {'comments': header} elif isinstance(header, list): header = {'comments': '\n'.join(str(entry) for entry in header)} elif isinstance(header, dict): header = dict((key, str(value)) for key, value in header.items()) else: raise TypeError( 'Unrecognised input to matrix.save_numeric() using "header=" option' ) else: header = {} if add_to_command_history and COMMAND_HISTORY_STRING: if 'command_history' in header: header['command_history'] += '\n' + COMMAND_HISTORY_STRING else: header['command_history'] = COMMAND_HISTORY_STRING with open(filename, 'w') as outfile: for key, value in sorted(header.items()): for line in value.splitlines(): outfile.write('# ' + key + ': ' + line + '\n') for line in scheme: outfile.write('{:.0f} {:.0f} {:.0f} {:.15g}\n'.format(*line))
def get_inputs(): #pylint: disable=unused-variable image.check_3d_nonunity(path.from_user(app.ARGS.input, False)) run.command('mrconvert ' + path.from_user(app.ARGS.input) + ' ' + path.to_scratch('input.mif')) if app.ARGS.mask: run.command('mrconvert ' + path.from_user(app.ARGS.mask) + ' ' + path.to_scratch('mask.mif') + ' -datatype bit -strides -1,+2,+3') if app.ARGS.t2: if not image.match(path.from_user(app.ARGS.input, False), path.from_user(app.ARGS.t2, False)): raise MRtrixError('Provided T2 image does not match input T1 image') run.command('mrconvert ' + path.from_user(app.ARGS.t2) + ' ' + path.to_scratch('T2.nii') + ' -strides -1,+2,+3')
def _shebang(item): import os from distutils.spawn import find_executable from mrtrix3 import app, MRtrixError, utils # If a complete path has been provided rather than just a file name, don't perform any additional file search if os.sep in item: path = item else: path = version_match(item) if path == item: path = find_executable(exe_name(item)) if not path: app.debug('File \"' + item + '\": Could not find file to query') return [] # Read the first 1024 bytes of the file with open(path, 'rb') as file_in: data = file_in.read(1024) # Try to find the shebang line for line in data.splitlines(): # Are there any non-text characters? If so, it's a binary file, so no need to looking for a shebang try: line = str(line.decode('utf-8')) except: app.debug('File \"' + item + '\": Not a text file') return [] line = line.strip() if len(line) > 2 and line[0:2] == '#!': # Need to strip first in case there's a gap between the shebang symbol and the interpreter path shebang = line[2:].strip().split(' ') if utils.is_windows(): # On Windows, /usr/bin/env can't be easily found, and any direct interpreter path will have a similar issue. # Instead, manually find the right interpreter to call using distutils if os.path.basename(shebang[0]) == 'env': new_shebang = [ os.path.abspath(find_executable(exe_name(shebang[1]))) ] new_shebang.extend(shebang[2:]) shebang = new_shebang else: new_shebang = [ os.path.abspath( find_executable( exe_name(os.path.basename(shebang[0])))) ] new_shebang.extend(shebang[1:]) shebang = new_shebang if not shebang or not shebang[0]: raise MRtrixError('malformed shebang in file \"' + item + '\": \"' + line + '\"') app.debug('File \"' + item + '\": string \"' + line + '\": ' + str(shebang)) return shebang app.debug('File \"' + item + '\": No shebang found') return []
def exe_name(name): #pylint: disable=unused-variable from mrtrix3 import app, MRtrixError from distutils.spawn import find_executable if find_executable(name): output = name elif find_executable('fsl5.0-' + name): output = 'fsl5.0-' + name else: raise MRtrixError('Could not find FSL program \"' + name + '\"; please verify FSL install') app.debug(output) return output
def check_first(prefix, structures): #pylint: disable=unused-variable import os from mrtrix3 import app, MRtrixError, path vtk_files = [ prefix + '-' + struct + '_first.vtk' for struct in structures ] existing_file_count = sum([ os.path.exists(filename) for filename in vtk_files ]) if existing_file_count != len(vtk_files): if 'SGE_ROOT' in os.environ and os.environ['SGE_ROOT']: app.console('FSL FIRST job may have been run via SGE; awaiting completion') app.console('(note however that FIRST may fail silently, and hence this script may hang indefinitely)') path.wait_for(vtk_files) else: raise MRtrixError('FSL FIRST has failed; ' + ('only ' if existing_file_count else '') + str(existing_file_count) + ' of ' + str(len(vtk_files)) + ' structures were segmented successfully (check ' + path.to_scratch('first.logs', False) + ')')
def find_image(name): #pylint: disable=unused-variable import os from mrtrix3 import app, MRtrixError prefix = os.path.join(os.path.dirname(name), os.path.basename(name).split('.')[0]) if os.path.isfile(prefix + suffix()): app.debug('Image at expected location: \"' + prefix + suffix() + '\"') return prefix + suffix() for suf in ['.nii', '.nii.gz', '.img']: if os.path.isfile(prefix + suf): app.debug('Expected image at \"' + prefix + suffix() + '\", but found at \"' + prefix + suf + '\"') return prefix + suf raise MRtrixError('Unable to find FSL output file for path \"' + name + '\"')
def exe_name(name): #pylint: disable=unused-variable from mrtrix3 import app #pylint: disable=import-outside-toplevel if find_executable(name): output = name elif find_executable('fsl5.0-' + name): output = 'fsl5.0-' + name app.warn('Using FSL binary \"' + output + '\" rather than \"' + name + '\"; suggest checking FSL installation') else: raise MRtrixError('Could not find FSL program \"' + name + '\"; please verify FSL install') app.debug(output) return output
def version_match(item): from mrtrix3 import app #pylint: disable=import-outside-toplevel if not item in EXE_LIST: app.debug('Command ' + item + ' not found in MRtrix3 bin/ directory') return item exe_path_manual = os.path.join(BIN_PATH, exe_name(item)) if os.path.isfile(exe_path_manual): app.debug('Version-matched executable for ' + item + ': ' + exe_path_manual) return exe_path_manual exe_path_sys = find_executable(exe_name(item)) if exe_path_sys and os.path.isfile(exe_path_sys): app.debug('Using non-version-matched executable for ' + item + ': ' + exe_path_sys) return exe_path_sys raise MRtrixError('Unable to find executable for MRtrix3 command ' + item)
def statistics(image_path, **kwargs): #pylint: disable=unused-variable from mrtrix3 import app, run #pylint: disable=import-outside-toplevel mask = kwargs.pop('mask', None) allvolumes = kwargs.pop('allvolumes', False) ignorezero = kwargs.pop('ignorezero', False) if kwargs: raise TypeError( 'Unsupported keyword arguments passed to image.statistics(): ' + str(kwargs)) command = [run.exe_name(run.version_match('mrstats')), image_path] for stat in IMAGE_STATISTICS: command.extend(['-output', stat]) if mask: command.extend(['-mask', mask]) if allvolumes: command.append('-allvolumes') if ignorezero: command.append('-ignorezero') if app.VERBOSITY > 1: app.console('Command: \'' + ' '.join(command) + '\' (piping data to local storage)') try: from subprocess import DEVNULL #pylint: disable=import-outside-toplevel except ImportError: DEVNULL = open(os.devnull, 'wb') proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=DEVNULL) stdout = proc.communicate()[0] if proc.returncode: raise MRtrixError( 'Error trying to calculate statistics from image \'' + image_path + '\'') stdout_lines = [ line.strip() for line in stdout.decode('cp437').splitlines() ] result = [] for line in stdout_lines: line = line.replace('N/A', 'nan').split() assert len(line) == len(IMAGE_STATISTICS) result.append( ImageStatistics(float(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4]), float(line[5]), int(line[6]))) if len(result) == 1: result = result[0] if app.VERBOSITY > 1: app.console('Result: ' + str(result)) return result
def check_output_path(item): #pylint: disable=unused-variable global ARGS, FORCE_OVERWRITE, WORKING_DIR if not item: return abspath = os.path.abspath(os.path.join(WORKING_DIR, item)) if os.path.exists(abspath): item_type = '' if os.path.isfile(abspath): item_type = ' file' elif os.path.isdir(abspath): item_type = ' directory' if FORCE_OVERWRITE: warn('Output' + item_type + ' \'' + item + '\' already exists; will be overwritten at script completion') else: raise MRtrixError('Output' + item_type + ' \'' + item + '\' already exists (use -force to override)')
def axis2dir(string): #pylint: disable=unused-variable from mrtrix3 import app #pylint: disable=import-outside-toplevel if string == 'i': direction = [1,0,0] elif string == 'i-': direction = [-1,0,0] elif string == 'j': direction = [0,1,0] elif string == 'j-': direction = [0,-1,0] elif string == 'k': direction = [0,0,1] elif string == 'k-': direction = [0,0,-1] else: raise MRtrixError('Unrecognized NIfTI axis & direction specifier: ' + string) app.debug(string + ' -> ' + str(direction)) return direction
def get_scheme(arg): #pylint: disable=unused-variable from mrtrix3 import app, image, MRtrixError if not isinstance(arg, image.Header): if not isinstance(arg, str): raise MRtrixError( 'Error trying to derive phase-encoding scheme from \'' + str(arg) + '\': Not an image header or file path') arg = image.Header(arg) if 'pe_scheme' in arg.keyval(): app.debug(str(arg.keyval()['pe_scheme'])) return arg.keyval()['pe_scheme'] if 'PhaseEncodingDirection' not in arg.keyval(): return None line = direction(arg.keyval()['PhaseEncodingDirection']) if 'TotalReadoutTime' in arg.keyval(): line = [float(value) for value in line] line.append(float(arg.keyval()['TotalReadoutTime'])) num_volumes = 1 if len(arg.size()) < 4 else arg.size()[3] app.debug(str(line) + ' x ' + str(num_volumes) + ' rows') return [line] * num_volumes
def version_match(item): import os from distutils.spawn import find_executable from mrtrix3 import app, BIN_PATH, EXE_LIST, MRtrixError if not item in EXE_LIST: app.debug('Command ' + item + ' not found in MRtrix3 bin/ directory') return item exe_path_manual = os.path.join(BIN_PATH, exe_name(item)) if os.path.isfile(exe_path_manual): app.debug('Version-matched executable for ' + item + ': ' + exe_path_manual) return exe_path_manual exe_path_sys = find_executable(exe_name(item)) if exe_path_sys and os.path.isfile(exe_path_sys): app.debug('Using non-version-matched executable for ' + item + ': ' + exe_path_sys) return exe_path_sys raise MRtrixError('Unable to find executable for MRtrix3 command ' + item)
def statistic(image_path, stat, options=''): #pylint: disable=unused-variable import shlex, subprocess from mrtrix3 import app, MRtrixError, run command = [ run.exe_name(run.version_match('mrstats')), image_path, '-output', stat ] if options: command.extend(shlex.split(options)) if app.VERBOSITY > 1: app.console('Command: \'' + ' '.join(command) + '\' (piping data to local storage)') proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None) result = [ line.strip() for line in proc.communicate()[0].decode('cp437').splitlines() ] if stat == 'count': result = [ int(i) for i in result ] else: result = [ float(f) for f in result ] if len(result) == 1: result = result[0] if app.VERBOSITY > 1: app.console('Result: ' + str(result)) if proc.returncode: raise MRtrixError('Error trying to calculate statistic \'' + stat + '\' from image \'' + image_path + '\'') return result
def execute(): #pylint: disable=unused-variable import shutil from mrtrix3 import app, image, MRtrixError, path, run bvalues = [ int(round(float(x))) for x in image.mrinfo('dwi.mif', 'shell_bvalues').split() ] if len(bvalues) < 2: raise MRtrixError('Need at least 2 unique b-values (including b=0).') lmax_option = '' if app.ARGS.lmax: lmax_option = ' -lmax ' + app.ARGS.lmax if not app.ARGS.mask: run.command('maskfilter mask.mif erode mask_eroded.mif -npass ' + str(app.ARGS.erode)) mask_path = 'mask_eroded.mif' else: mask_path = 'mask.mif' run.command('dwi2tensor dwi.mif -mask ' + mask_path + ' tensor.mif') run.command( 'tensor2metric tensor.mif -fa fa.mif -vector vector.mif -mask ' + mask_path) if app.ARGS.threshold: run.command('mrthreshold fa.mif voxels.mif -abs ' + str(app.ARGS.threshold)) else: run.command('mrthreshold fa.mif voxels.mif -top ' + str(app.ARGS.number)) run.command( 'dwiextract dwi.mif - -singleshell -no_bzero | amp2response - voxels.mif vector.mif response.txt' + lmax_option) run.function(shutil.copyfile, 'response.txt', path.from_user(app.ARGS.output, False)) if app.ARGS.voxels: run.command('mrconvert voxels.mif ' + path.from_user(app.ARGS.voxels), mrconvert_keyval=path.from_user(app.ARGS.input), force=app.FORCE_OVERWRITE)