Esempio n. 1
0
 def is_hidden(directory, filename):
   if app.isWindows():
     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. 2
0
 def is_hidden(directory, filename):
     if app.isWindows():
         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. 3
0
def _shebang(item):
    import os
    from mrtrix3 import app
    from distutils.spawn import find_executable
    # 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 = versionMatch(item)
        if path == item:
            path = find_executable(exeName(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 f:
        data = f.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 app.isWindows():
                # 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(exeName(shebang[1])))
                    ]
                    new_shebang.extend(shebang[2:])
                    shebang = new_shebang
                else:
                    new_shebang = [
                        os.path.abspath(
                            find_executable(
                                exeName(os.path.basename(shebang[0]))))
                    ]
                    new_shebang.extend(shebang[1:])
                    shebang = new_shebang
                if not shebang or not shebang[0]:
                    app.error('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. 4
0
def _shebang(item):
  import os
  from mrtrix3 import app
  from distutils.spawn import find_executable
  # 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 = versionMatch(item)
    if path == item:
      path = find_executable(exeName(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 f:
    data = f.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 app.isWindows():
        # 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(exeName(shebang[1]))) ]
          new_shebang.extend(shebang[2:])
          shebang = new_shebang
        else:
          new_shebang = [ os.path.abspath(find_executable(exeName(os.path.basename(shebang[0])))) ]
          new_shebang.extend(shebang[1:])
          shebang = new_shebang
        if not shebang or not shebang[0]:
          app.error('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 inUse(path):
   import subprocess
   from distutils.spawn import find_executable
   if not os.path.isfile(path):
     return None
   if app.isWindows():
     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 -> inUse() = False, so waitFor() can return
   return not subprocess.call(['fuser', '-s', path], shell=False, stdin=None, stdout=None, stderr=None)
Esempio n. 6
0
def exeName(item):
    from distutils.spawn import find_executable
    from mrtrix3 import app
    global _mrtrix_bin_path
    if not app.isWindows():
        path = item
    elif item.endswith('.exe'):
        path = item
    elif os.path.isfile(os.path.join(_mrtrix_bin_path, item)):
        path = item
    elif os.path.isfile(os.path.join(_mrtrix_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
def exeName(item):
  from distutils.spawn import find_executable
  from mrtrix3 import app
  global _mrtrix_bin_path
  if not app.isWindows():
    path = item
  elif item.endswith('.exe'):
    path = item
  elif os.path.isfile(os.path.join(_mrtrix_bin_path, item)):
    path = item
  elif os.path.isfile(os.path.join(_mrtrix_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. 8
0
 def inUse(path):
     import subprocess
     from distutils.spawn import find_executable
     if app.isWindows():
         if not os.access(path, os.W_OK):
             return None
         try:
             with open(path, 'rb+') as 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 -> inUse() = False, so waitFor() can return
     return not subprocess.call(['fuser', '-s', path],
                                shell=False,
                                stdin=None,
                                stdout=None,
                                stderr=None)
Esempio n. 9
0
def execute():
    import os
    from distutils.spawn import find_executable
    from mrtrix3 import app, file, fsl, image, run

    if app.isWindows():
        app.error(
            '\'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:
        app.error(
            'Environment variable FSLDIR is not set; please run appropriate FSL configuration script'
        )

    ssroi_cmd = 'standard_space_roi'
    if not find_executable(ssroi_cmd):
        ssroi_cmd = 'fsl5.0-standard_space_roi'
        if not find_executable(ssroi_cmd):
            app.error(
                'Could not find FSL program standard_space_roi; please verify FSL install'
            )

    bet_cmd = 'bet'
    if not find_executable(bet_cmd):
        bet_cmd = 'fsl5.0-bet'
        if not find_executable(bet_cmd):
            app.error(
                'Could not find FSL program bet; please verify FSL install')

    fast_cmd = 'fast'
    if not find_executable(fast_cmd):
        fast_cmd = 'fsl5.0-fast'
        if not find_executable(fast_cmd):
            app.error(
                'Could not find FSL program fast; please verify FSL install')

    first_cmd = 'run_first_all'
    if not find_executable(first_cmd):
        first_cmd = "fsl5.0-run_first_all"
        if not find_executable(first_cmd):
            app.error(
                'Could not find FSL program run_first_all; please verify FSL install'
            )

    first_atlas_path = os.path.join(fsl_path, 'data', 'first',
                                    'models_336_bin')

    if not os.path.isdir(first_atlas_path):
        app.error(
            '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'])

    run.command('mrconvert input.mif T1.nii -stride -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')
            run.command('mrcalc T1.nii mask_regrid.mif ' + 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
        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, False)
        else:
            run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix + ' -b',
                        False)

        # For whatever reason, the output file from standard_space_roi may not be
        #   completed before BET is run
        file.waitFor('T1_preBET' + fsl_suffix)

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

        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)
    fast_output_prefix = fast_t1_input.split('.')[0]

    # FIRST
    first_input_is_brain_extracted = ''
    if app.args.premasked:
        first_input_is_brain_extracted = ' -b'
    run.command(first_cmd + ' -s ' + ','.join(sgm_structures) +
                ' -i T1.nii -o first' + first_input_is_brain_extracted)

    # Test to see whether or not FIRST has succeeded
    # However if the expected image is absent, it may be due to FIRST being run
    #   on SGE; in this case it is necessary to wait and see if the file appears.
    #   But even in this case, FIRST may still fail, and the file will never appear...
    combined_image_path = 'first_all_none_firstseg' + fsl_suffix
    if not os.path.isfile(combined_image_path):
        if 'SGE_ROOT' in os.environ:
            app.console(
                'FSL FIRST job has been submitted to SGE; awaiting completion')
            app.console(
                '(note however that FIRST may fail, and hence this script may hang indefinitely)'
            )
            file.waitFor(combined_image_path)
        else:
            app.error(
                'FSL FIRST has failed; not all structures were segmented successfully (check '
                + path.toTemp('first.logs', False) + ')')

    # Convert FIRST meshes to partial volume images
    pve_image_list = []
    for struct in sgm_structures:
        pve_image_path = 'mesh2pve_' + 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 T1.nii')
        run.command('mesh2pve ' + vtk_temp_path + ' ' + fast_t1_input + ' ' +
                    pve_image_path)
        pve_image_list.append(pve_image_path)
    pve_cat = ' '.join(pve_image_list)
    run.command('mrmath ' + pve_cat +
                ' sum - | mrcalc - 1.0 -min all_sgms.mif')

    # Looks like FAST in 5.0 ignores FSLOUTPUTTYPE when writing the PVE images
    # Will have to wait and see whether this changes, and update the script accordingly
    if fast_cmd == 'fast':
        fast_suffix = fsl_suffix
    else:
        fast_suffix = '.nii.gz'

    # Combine the tissue images into the 5TT format within the script itself
    # Step 1: Run LCC on the WM image
    run.command(
        'mrthreshold ' + fast_output_prefix + '_pve_2' + fast_suffix +
        ' - -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 5ttgen command
    run.command('mrcalc ' + fast_output_prefix + '_pve_0' + fast_suffix +
                ' 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_output_prefix +
                '_pve_1' + fast_suffix + ' ' + fast_output_prefix + '_pve_2' +
                fast_suffix + ' -add -div multiplier.mif')
    run.command(
        'mrcalc multiplier.mif -finite multiplier.mif 0.0 -if multiplier_noNAN.mif'
    )
    run.command(
        'mrcalc ' + fast_output_prefix + '_pve_1' + fast_suffix +
        ' multiplier_noNAN.mif -mult remove_unconnected_wm_mask.mif -mult cgm.mif'
    )
    run.command(
        'mrcalc ' + fast_output_prefix + '_pve_2' + fast_suffix +
        ' 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 -stride +2,+3,+4,+1'
    )

    # Use mrcrop to reduce file size (improves caching of image data during tracking)
    if app.args.nocrop:
        run.command('mrconvert combined_precrop.mif result.mif')
    else:
        run.command(
            'mrmath combined_precrop.mif sum - -axis 3 | mrthreshold - - -abs 0.5 | mrcrop combined_precrop.mif result.mif -mask -'
        )
Esempio n. 10
0
options.add_argument('-num_tracks',
                     type=int,
                     default='20000000',
                     help='define the number of streamlines to be computed '
                     'when performing tractography on the FOD template. '
                     '(group3 analysis level only)')
options.add_argument('-num_tracks_sift',
                     type=int,
                     default='2000000',
                     help='define the number of streamlines to '
                     'remain after performing SIFT on the tractogram'
                     '(group3 analysis level only)')

app.parse()

if app.isWindows():
    app.error('Script cannot be run on Windows due to FSL dependency')

subjects_to_analyze = []
# only for a subset of subjects
if app.args.participant_label:
    subjects_to_analyze = app.args.participant_label
# for all subjects
else:
    subject_dirs = glob.glob(os.path.join(app.args.in_dir, 'sub-*'))
    subjects_to_analyze = [
        subject_dir.split("-")[-1] for subject_dir in subject_dirs
    ]

# create output subjects directory
all_subjects_dir = os.path.join(app.args.output_dir, 'subjects')
Esempio n. 11
0
def execute(): #pylint: disable=unused-variable
  import math, os
  from mrtrix3 import app, fsl, image, run

  if app.isWindows():
    app.error('\'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:
    app.error('Environment variable FSLDIR is not set; please run appropriate FSL configuration script')

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

  first_atlas_path = os.path.join(fsl_path, 'data', 'first', 'models_336_bin')
  if not os.path.isdir(first_atlas_path):
    app.error('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
    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, False)
    else:
      run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix + ' -b', False)
    pre_bet_image = fsl.findImage('T1_preBET')

    # BET
    run.command(bet_cmd + ' ' + pre_bet_image + ' T1_BET' + fsl_suffix + ' -f 0.15 -R')
    fast_t1_input = fsl.findImage('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('mrresize T1.nii T1_1mm.nii -voxel 1.0 -interp sinc')
    first_input = 'T1_1mm.nii'
  first_input_brain_extracted_option = ''
  if app.args.premasked:
    first_input_brain_extracted_option = ' -b'
  first_debug_option = ''
  if not app.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_input_brain_extracted_option + first_debug_option + first_verbosity_option)
  fsl.checkFirst('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 ' + ' '.join(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.findImage(fast_output_prefix + '_pve_0')
  fast_gm_output = fsl.findImage(fast_output_prefix + '_pve_1')
  fast_wm_output = fsl.findImage(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')

  # Use mrcrop to reduce file size (improves caching of image data during tracking)
  if app.args.nocrop:
    run.command('mrconvert combined_precrop.mif result.mif')
  else:
    run.command('mrmath combined_precrop.mif sum - -axis 3 | mrthreshold - - -abs 0.5 | mrcrop combined_precrop.mif result.mif -mask -')
Esempio n. 12
0
def execute():
    import os
    from distutils.spawn import find_executable
    from mrtrix3 import app, file, fsl, image, path, run

    if app.isWindows():
        app.error(
            '\'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:
        app.error(
            'Environment variable FSLDIR is not set; please run appropriate FSL configuration script'
        )

    ssroi_cmd = 'standard_space_roi'
    if not find_executable(ssroi_cmd):
        ssroi_cmd = 'fsl5.0-standard_space_roi'
        if not find_executable(ssroi_cmd):
            app.error(
                'Could not find FSL program standard_space_roi; please verify FSL install'
            )

    bet_cmd = 'bet'
    if not find_executable(bet_cmd):
        bet_cmd = 'fsl5.0-bet'
        if not find_executable(bet_cmd):
            app.error(
                'Could not find FSL program bet; please verify FSL install')

    fast_cmd = 'fast'
    if not find_executable(fast_cmd):
        fast_cmd = 'fsl5.0-fast'
        if not find_executable(fast_cmd):
            app.error(
                'Could not find FSL program fast; please verify FSL install')

    first_cmd = 'run_first_all'
    if not find_executable(first_cmd):
        first_cmd = "fsl5.0-run_first_all"
        if not find_executable(first_cmd):
            app.error(
                'Could not find FSL program run_first_all; please verify FSL install'
            )

    first_atlas_path = os.path.join(fsl_path, 'data', 'first',
                                    'models_336_bin')

    if not os.path.isdir(first_atlas_path):
        app.error(
            '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'])

    run.command('mrconvert input.mif T1.nii -stride -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')
            run.command('mrcalc T1.nii mask_regrid.mif ' + 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
        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, False)
        else:
            run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix + ' -b',
                        False)
        pre_bet_image = fsl.findImage('T1_preBET')

        # BET
        run.command(bet_cmd + ' ' + pre_bet_image + ' T1_BET' + fsl_suffix +
                    ' -f 0.15 -R')
        fast_t1_input = fsl.findImage('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_is_brain_extracted = ''
    if app.args.premasked:
        first_input_is_brain_extracted = ' -b'
    run.command(first_cmd + ' -m none -s ' + ','.join(sgm_structures) +
                ' -i T1.nii -o first' + first_input_is_brain_extracted)
    fsl.checkFirst('first', sgm_structures)

    # Convert FIRST meshes to partial volume images
    pve_image_list = []
    for struct in sgm_structures:
        pve_image_path = 'mesh2pve_' + 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 T1.nii')
        run.command('mesh2pve ' + vtk_temp_path + ' ' + fast_t1_input + ' ' +
                    pve_image_path)
        pve_image_list.append(pve_image_path)
    pve_cat = ' '.join(pve_image_list)
    run.command('mrmath ' + pve_cat +
                ' 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.findImage(fast_output_prefix + '_pve_0')
    fast_gm_output = fsl.findImage(fast_output_prefix + '_pve_1')
    fast_wm_output = fsl.findImage(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 -stride +2,+3,+4,+1'
    )

    # Use mrcrop to reduce file size (improves caching of image data during tracking)
    if app.args.nocrop:
        run.command('mrconvert combined_precrop.mif result.mif')
    else:
        run.command(
            'mrmath combined_precrop.mif sum - -axis 3 | mrthreshold - - -abs 0.5 | mrcrop combined_precrop.mif result.mif -mask -'
        )
Esempio n. 13
0
def execute():  #pylint: disable=unused-variable
    import math, os
    from mrtrix3 import app, fsl, image, run

    if app.isWindows():
        app.error(
            '\'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:
        app.error(
            'Environment variable FSLDIR is not set; please run appropriate FSL configuration script'
        )

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

    first_atlas_path = os.path.join(fsl_path, 'data', 'first',
                                    'models_336_bin')
    if not os.path.isdir(first_atlas_path):
        app.error(
            '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
        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, False)
        else:
            run.command(ssroi_cmd + ' T1.nii T1_preBET' + fsl_suffix + ' -b',
                        False)
        pre_bet_image = fsl.findImage('T1_preBET')

        # BET
        run.command(bet_cmd + ' ' + pre_bet_image + ' T1_BET' + fsl_suffix +
                    ' -f 0.15 -R')
        fast_t1_input = fsl.findImage('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('mrresize T1.nii T1_1mm.nii -voxel 1.0 -interp sinc')
        first_input = 'T1_1mm.nii'
    first_input_brain_extracted_option = ''
    if app.args.premasked:
        first_input_brain_extracted_option = ' -b'
    first_debug_option = ''
    if not app.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_input_brain_extracted_option + first_debug_option +
                first_verbosity_option)
    fsl.checkFirst('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 ' + ' '.join(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.findImage(fast_output_prefix + '_pve_0')
    fast_gm_output = fsl.findImage(fast_output_prefix + '_pve_1')
    fast_wm_output = fsl.findImage(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'
    )

    # Use mrcrop to reduce file size (improves caching of image data during tracking)
    if app.args.nocrop:
        run.command('mrconvert combined_precrop.mif result.mif')
    else:
        run.command(
            'mrmath combined_precrop.mif sum - -axis 3 | mrthreshold - - -abs 0.5 | mrcrop combined_precrop.mif result.mif -mask -'
        )