Esempio n. 1
0
def _shebang(item):
    from mrtrix3 import app, utils  #pylint: disable=import-outside-toplevel
    # 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(' ')
            # 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
            # Also if script is written in Python, try to execute it using the same interpreter as that currently running
            if os.path.basename(shebang[0]) == 'env':
                if len(shebang) < 2:
                    app.warn('Invalid shebang in script file \"' + item +
                             '\" (missing interpreter after \"env\")')
                    return []
                if shebang[1] == 'python':
                    if not sys.executable:
                        app.warn(
                            'Unable to self-identify Python interpreter; file \"'
                            + item +
                            '\" not guaranteed to execute on same version')
                        return []
                    shebang = [sys.executable] + shebang[2:]
                    app.debug('File \"' + item +
                              '\": Using current Python interpreter')
                elif utils.is_windows():
                    shebang = [
                        os.path.abspath(find_executable(exe_name(shebang[1])))
                    ] + shebang[2:]
            elif utils.is_windows():
                shebang = [
                    os.path.abspath(
                        find_executable(exe_name(os.path.basename(
                            shebang[0]))))
                ] + shebang[1:]
            app.debug('File \"' + item + '\": string \"' + line + '\": ' +
                      str(shebang))
            return shebang
    app.debug('File \"' + item + '\": No shebang found')
    return []
Esempio n. 2
0
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)
Esempio n. 3
0
 def is_hidden(directory, filename):
   if utils.is_windows():
     try:
       attrs = ctypes.windll.kernel32.GetFileAttributesW(u"%s" % str(os.path.join(directory, filename)))
       assert attrs != -1
       return bool(attrs & 2)
     except (AttributeError, AssertionError):
       return filename.startswith('.')
   return filename.startswith('.')
Esempio n. 4
0
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 []
Esempio n. 5
0
 def in_use(path):
   if not os.path.isfile(path):
     return None
   if utils.is_windows():
     if not os.access(path, os.W_OK):
       return None
     try:
       with open(path, 'rb+') as dummy_f:
         pass
       return False
     except:
       return True
   if not find_executable('fuser'):
     return None
   # fuser returns zero if there IS at least one process accessing the file
   # A fatal error will result in a non-zero code -> in_use() = False, so wait_for() can return
   return not subprocess.call(['fuser', '-s', path], shell=False, stdin=None, stdout=None, stderr=None)
Esempio n. 6
0
def exe_name(item):
    from mrtrix3 import app, utils  #pylint: disable=import-outside-toplevel
    if not utils.is_windows():
        path = item
    elif item.endswith('.exe'):
        path = item
    elif os.path.isfile(os.path.join(BIN_PATH, item)):
        path = item
    elif os.path.isfile(os.path.join(BIN_PATH, item + '.exe')):
        path = item + '.exe'
    elif find_executable(item) is not None:
        path = item
    elif find_executable(item + '.exe') is not None:
        path = item + '.exe'
    # If it can't be found, return the item as-is; find_executable() fails to identify Python scripts
    else:
        path = item
    app.debug(item + ' -> ' + path)
    return path
Esempio n. 7
0
             'SIGBUS' : 'Bus error: Accessing invalid address (out of storage space?)',
             'SIGFPE' : 'Floating-point arithmetic exception',
             'SIGHUP' : 'Disconnection of terminal',
             'SIGILL' : 'Illegal instruction (corrupt binary command file?)',
             'SIGINT' : 'Program manually interrupted by terminal',
             'SIGPIPE': 'Nothing on receiving end of pipe',
             'SIGPWR' : 'Power failure restart',
             'SIGQUIT': 'Received terminal quit signal',
             'SIGSEGV': 'Segmentation fault: Invalid memory reference',
             'SIGSYS' : 'Bad system call',
             'SIGXCPU': 'CPU time limit exceeded',
             'SIGXFSZ': 'File size limit exceeded' }
           # Can't be handled; see https://bugs.python.org/issue9524
           # 'CTRL_C_EVENT': 'Terminated by user Ctrl-C input',
           # 'CTRL_BREAK_EVENT': 'Terminated by user Ctrl-Break input'
if utils.is_windows():
  _SIGNALS['SIGBREAK'] = 'Received Windows \'break\' signal'
else:
  _SIGNALS['SIGTERM'] = 'Received termination signal'



# Generally preferable to use:
#   "import mrtrix3"
#   "mrtrix3.execute()"
# , rather than executing this function directly
def _execute(module): #pylint: disable=unused-variable
  from mrtrix3 import run #pylint: disable=import-outside-toplevel
  global ARGS, CMDLINE, CONTINUE_OPTION, DO_CLEANUP, EXEC_NAME, FORCE_OVERWRITE, NUM_THREADS, SCRATCH_DIR, VERBOSITY, WORKING_DIR

  # Set up signal handlers
Esempio n. 8
0
def execute():  #pylint: disable=unused-variable
    import math, os
    from distutils.spawn import find_executable
    from mrtrix3 import app, fsl, image, MRtrixError, path, run, utils

    if utils.is_windows():
        raise MRtrixError(
            '\'fsl\' algorithm of 5ttgen script cannot be run on Windows: FSL not available on Windows'
        )

    fsl_path = os.environ.get('FSLDIR', '')
    if not fsl_path:
        raise MRtrixError(
            'Environment variable FSLDIR is not set; please run appropriate FSL configuration script'
        )

    bet_cmd = fsl.exe_name('bet')
    fast_cmd = fsl.exe_name('fast')
    first_cmd = fsl.exe_name('run_first_all')
    ssroi_cmd = fsl.exe_name('standard_space_roi')

    first_atlas_path = os.path.join(fsl_path, 'data', 'first',
                                    'models_336_bin')
    if not os.path.isdir(first_atlas_path):
        raise MRtrixError(
            'Atlases required for FSL\'s FIRST program not installed; please install fsl-first-data using your relevant package manager'
        )

    fsl_suffix = fsl.suffix()

    sgm_structures = [
        'L_Accu', 'R_Accu', 'L_Caud', 'R_Caud', 'L_Pall', 'R_Pall', 'L_Puta',
        'R_Puta', 'L_Thal', 'R_Thal'
    ]
    if app.ARGS.sgm_amyg_hipp:
        sgm_structures.extend(['L_Amyg', 'R_Amyg', 'L_Hipp', 'R_Hipp'])

    t1_spacing = image.Header('input.mif').spacing()
    upsample_for_first = False
    # If voxel size is 1.25mm or larger, make a guess that the user has erroneously re-gridded their data
    if math.pow(t1_spacing[0] * t1_spacing[1] * t1_spacing[2],
                1.0 / 3.0) > 1.225:
        app.warn(
            'Voxel size larger than expected for T1-weighted images (' +
            str(t1_spacing) + '); '
            'note that ACT does not require re-gridding of T1 image to DWI space, and indeed '
            'retaining the original higher resolution of the T1 image is preferable'
        )
        upsample_for_first = True

    run.command('mrconvert input.mif T1.nii -strides -1,+2,+3')

    fast_t1_input = 'T1.nii'
    fast_t2_input = ''

    # Decide whether or not we're going to do any brain masking
    if os.path.exists('mask.mif'):

        fast_t1_input = 'T1_masked' + fsl_suffix

        # Check to see if the mask matches the T1 image
        if image.match('T1.nii', 'mask.mif'):
            run.command('mrcalc T1.nii mask.mif -mult ' + fast_t1_input)
            mask_path = 'mask.mif'
        else:
            app.warn('Mask image does not match input image - re-gridding')
            run.command(
                'mrtransform mask.mif mask_regrid.mif -template T1.nii -datatype bit'
            )
            run.command('mrcalc T1.nii mask_regrid.mif -mult ' + fast_t1_input)
            mask_path = 'mask_regrid.mif'

        if os.path.exists('T2.nii'):
            fast_t2_input = 'T2_masked' + fsl_suffix
            run.command('mrcalc T2.nii ' + mask_path + ' -mult ' +
                        fast_t2_input)

    elif app.ARGS.premasked:

        fast_t1_input = 'T1.nii'
        if os.path.exists('T2.nii'):
            fast_t2_input = 'T2.nii'

    else:

        # Use FSL command standard_space_roi to do an initial masking of the image before BET
        # Also reduce the FoV of the image
        # Using MNI 1mm dilated brain mask rather than the -b option in standard_space_roi (which uses the 2mm mask); the latter looks 'buggy' to me... Unfortunately even with the 1mm 'dilated' mask, it can still cut into some brain areas, hence the explicit dilation
        mni_mask_path = os.path.join(fsl_path, 'data', 'standard',
                                     'MNI152_T1_1mm_brain_mask_dil.nii.gz')
        mni_mask_dilation = 0
        if os.path.exists(mni_mask_path):
            mni_mask_dilation = 4
        else:
            mni_mask_path = os.path.join(
                fsl_path, 'data', 'standard',
                'MNI152_T1_2mm_brain_mask_dil.nii.gz')
            if os.path.exists(mni_mask_path):
                mni_mask_dilation = 2
        try:
            if mni_mask_dilation:
                run.command('maskfilter ' + mni_mask_path +
                            ' dilate mni_mask.nii -npass ' +
                            str(mni_mask_dilation))
                if app.ARGS.nocrop:
                    ssroi_roi_option = ' -roiNONE'
                else:
                    ssroi_roi_option = ' -roiFOV'
                run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix +
                            ' -maskMASK mni_mask.nii' + ssroi_roi_option)
            else:
                run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix +
                            ' -b')
        except run.MRtrixCmdError:
            pass
        try:
            pre_bet_image = fsl.find_image('T1_preBET')
        except MRtrixError:
            app.warn('FSL script \'standard_space_roi\' did not complete successfully' + \
                     ('' if find_executable('dc') else ' (possibly due to program \'dc\' not being installed') + '; ' + \
                     'attempting to continue by providing un-cropped image to BET')
            pre_bet_image = 'T1.nii'

        # BET
        run.command(bet_cmd + ' ' + pre_bet_image + ' T1_BET' + fsl_suffix +
                    ' -f 0.15 -R')
        fast_t1_input = fsl.find_image('T1_BET' + fsl_suffix)

        if os.path.exists('T2.nii'):
            if app.ARGS.nocrop:
                fast_t2_input = 'T2.nii'
            else:
                # Just a reduction of FoV, no sub-voxel interpolation going on
                run.command('mrtransform T2.nii T2_cropped.nii -template ' +
                            fast_t1_input + ' -interp nearest')
                fast_t2_input = 'T2_cropped.nii'

    # Finish branching based on brain masking

    # FAST
    if fast_t2_input:
        run.command(fast_cmd + ' -S 2 ' + fast_t2_input + ' ' + fast_t1_input)
    else:
        run.command(fast_cmd + ' ' + fast_t1_input)

    # FIRST
    first_input = 'T1.nii'
    if upsample_for_first:
        app.warn(
            'Generating 1mm isotropic T1 image for FIRST in hope of preventing failure, since input image is of lower resolution'
        )
        run.command('mrgrid T1.nii regrid T1_1mm.nii -voxel 1.0 -interp sinc')
        first_input = 'T1_1mm.nii'
    first_brain_extracted_option = ''
    if app.ARGS.premasked:
        first_brain_extracted_option = ' -b'
    first_debug_option = ''
    if not app.DO_CLEANUP:
        first_debug_option = ' -d'
    first_verbosity_option = ''
    if app.VERBOSITY == 3:
        first_verbosity_option = ' -v'
    run.command(first_cmd + ' -m none -s ' + ','.join(sgm_structures) +
                ' -i ' + first_input + ' -o first' +
                first_brain_extracted_option + first_debug_option +
                first_verbosity_option)
    fsl.check_first('first', sgm_structures)

    # Convert FIRST meshes to partial volume images
    pve_image_list = []
    progress = app.ProgressBar(
        'Generating partial volume images for SGM structures',
        len(sgm_structures))
    for struct in sgm_structures:
        pve_image_path = 'mesh2voxel_' + struct + '.mif'
        vtk_in_path = 'first-' + struct + '_first.vtk'
        vtk_temp_path = struct + '.vtk'
        run.command('meshconvert ' + vtk_in_path + ' ' + vtk_temp_path +
                    ' -transform first2real ' + first_input)
        run.command('mesh2voxel ' + vtk_temp_path + ' ' + fast_t1_input + ' ' +
                    pve_image_path)
        pve_image_list.append(pve_image_path)
        progress.increment()
    progress.done()
    run.command(['mrmath', pve_image_list, 'sum', '-', '|', \
                 'mrcalc', '-', '1.0', '-min', 'all_sgms.mif'])

    # Combine the tissue images into the 5TT format within the script itself
    fast_output_prefix = fast_t1_input.split('.')[0]
    fast_csf_output = fsl.find_image(fast_output_prefix + '_pve_0')
    fast_gm_output = fsl.find_image(fast_output_prefix + '_pve_1')
    fast_wm_output = fsl.find_image(fast_output_prefix + '_pve_2')
    # Step 1: Run LCC on the WM image
    run.command(
        'mrthreshold ' + fast_wm_output +
        ' - -abs 0.001 | maskfilter - connect - -connectivity | mrcalc 1 - 1 -gt -sub remove_unconnected_wm_mask.mif -datatype bit'
    )
    # Step 2: Generate the images in the same fashion as the old 5ttgen binary used to:
    #   - Preserve CSF as-is
    #   - Preserve SGM, unless it results in a sum of volume fractions greater than 1, in which case clamp
    #   - Multiply the FAST volume fractions of GM and CSF, so that the sum of CSF, SGM, CGM and WM is 1.0
    run.command('mrcalc ' + fast_csf_output +
                ' remove_unconnected_wm_mask.mif -mult csf.mif')
    run.command('mrcalc 1.0 csf.mif -sub all_sgms.mif -min sgm.mif')
    run.command('mrcalc 1.0 csf.mif sgm.mif -add -sub ' + fast_gm_output +
                ' ' + fast_wm_output + ' -add -div multiplier.mif')
    run.command(
        'mrcalc multiplier.mif -finite multiplier.mif 0.0 -if multiplier_noNAN.mif'
    )
    run.command(
        'mrcalc ' + fast_gm_output +
        ' multiplier_noNAN.mif -mult remove_unconnected_wm_mask.mif -mult cgm.mif'
    )
    run.command(
        'mrcalc ' + fast_wm_output +
        ' multiplier_noNAN.mif -mult remove_unconnected_wm_mask.mif -mult wm.mif'
    )
    run.command('mrcalc 0 wm.mif -min path.mif')
    run.command(
        'mrcat cgm.mif sgm.mif wm.mif csf.mif path.mif - -axis 3 | mrconvert - combined_precrop.mif -strides +2,+3,+4,+1'
    )

    # Crop to reduce file size (improves caching of image data during tracking)
    if app.ARGS.nocrop:
        run.function(os.rename, 'combined_precrop.mif', 'result.mif')
    else:
        run.command(
            'mrmath combined_precrop.mif sum - -axis 3 | mrthreshold - - -abs 0.5 | mrgrid combined_precrop.mif crop result.mif -mask -'
        )

    run.command('mrconvert result.mif ' + path.from_user(app.ARGS.output),
                mrconvert_keyval=path.from_user(app.ARGS.input),
                force=app.FORCE_OVERWRITE)