コード例 #1
0
def complete():
    import os, shutil, sys
    from lib.printMessage import printMessage
    global tempDir, workingDir
    printMessage('Changing back to original directory (' + workingDir + ')')
    os.chdir(workingDir)
    if cleanup and tempDir:
        printMessage('Deleting temporary directory ' + tempDir)
        shutil.rmtree(tempDir)
    elif tempDir:
        # This needs to be printed even if the -quiet option is used
        if os.path.isfile(os.path.join(tempDir, 'error.txt')):
            with open(os.path.join(tempDir, 'error.txt'), 'rb') as errortext:
                sys.stdout.write(
                    os.path.basename(sys.argv[0]) + ': ' + colourWarn +
                    'Script failed while executing the command: ' +
                    errortext.readline().rstrip() + colourClear + '\n')
            sys.stdout.write(
                os.path.basename(sys.argv[0]) + ': ' + colourWarn +
                'For debugging, inspect contents of temporary directory: ' +
                tempDir + colourClear + '\n')
        else:
            sys.stdout.write(
                os.path.basename(sys.argv[0]) + ': ' + colourPrint +
                'Contents of temporary directory kept, location: ' + tempDir +
                colourClear + '\n')
        sys.stdout.flush()
コード例 #2
0
ファイル: delFile.py プロジェクト: pmolfese/mrtrix3
def delFile(path):
    import lib.app, os
    from lib.printMessage import printMessage
    if not lib.app.cleanup:
        return
    printMessage('Deleting file: ' + path)
    os.remove(path)
コード例 #3
0
ファイル: app.py プロジェクト: emanuele/mrtrix3
def makeTempDir():
  import os, random, string, sys
  from lib.errorMessage          import errorMessage
  from lib.printMessage          import printMessage
  from lib.readMRtrixConfSetting import readMRtrixConfSetting
  global args, tempDir
  if args.cont:
    printMessage('Skipping temporary directory creation due to use of -continue option')
    return
  if tempDir:
    errorMessage('Script error: Cannot use multiple temporary directories')
  if args.tempdir:
    dir_path = os.path.abspath(args.tempdir)
  else:
    dir_path = readMRtrixConfSetting('TmpFileDir')
    if not dir_path:
      if os.name == 'posix':
        dir_path = '/tmp'
      else:
        dir_path = '.'
  prefix = readMRtrixConfSetting('TmpFilePrefix')
  if not prefix:
    prefix = os.path.basename(sys.argv[0]) + '-tmp-'
  tempDir = dir_path
  while os.path.isdir(tempDir):
    random_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
    tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
  os.makedirs(tempDir)
  printMessage('Generated temporary directory: ' + tempDir)
  with open(os.path.join(tempDir, 'cwd.txt'), 'w') as outfile:
    outfile.write(workingDir + '\n')
  with open(os.path.join(tempDir, 'command.txt'), 'w') as outfile:
    outfile.write(' '.join(sys.argv) + '\n')
コード例 #4
0
ファイル: app.py プロジェクト: skeif/mrtrix3
def moveFileToDest(local_path, destination):
  import os, shutil
  from lib.printMessage import printMessage
  if destination[0] != '/':
    destination = os.path.abspath(os.path.join(workingDir, destination))
  printMessage('Moving output file from temporary directory to user specified location')
  shutil.move(local_path, destination)
コード例 #5
0
def delFile(path):
  import lib.app, os
  from lib.printMessage import printMessage
  if not lib.app.cleanup:
    return
  printMessage('Deleting file: ' + path)
  os.remove(path)
コード例 #6
0
ファイル: app.py プロジェクト: qlryan/mrtrix3
def gotoTempDir():
    import os
    from lib.printMessage import printMessage

    if verbosity:
        printMessage("Changing to temporary directory (" + tempDir + ")")
    os.chdir(tempDir)
コード例 #7
0
ファイル: app.py プロジェクト: qlryan/mrtrix3
def initialise():
    import argparse, os, random, string, sys
    from lib.printMessage import printMessage
    from lib.readMRtrixConfSetting import readMRtrixConfSetting

    global args, cleanup, lastFile, mrtrixNThreads, mrtrixQuiet, tempDir, verbosity, workingDir
    global colourClear, colourConsole, colourError, colourPrint, colourWarn
    workingDir = os.getcwd()
    args = parser.parse_args()
    if args.nocleanup:
        cleanup = False
    if args.nthreads:
        mrtrixNThreads = "-nthreads " + args.nthreads
    if args.quiet:
        verbosity = 0
        mrtrixQuiet = "-quiet"
    if args.verbose:
        verbosity = 2
        mrtrixQuiet = ""
    if args.cont:
        tempDir = os.path.abspath(args.cont[0])
        lastFile = args.cont[1]
    else:
        if args.tempdir:
            dir_path = os.path.abspath(args.tempdir)
        else:
            dir_path = readMRtrixConfSetting("TmpFileDir")
            if not dir_path:
                if os.name == "posix":
                    dir_path = "/tmp"
                else:
                    dir_path = "."
        prefix = readMRtrixConfSetting("TmpFilePrefix")
        if not prefix:
            prefix = os.path.basename(sys.argv[0]) + "-tmp-"
        tempDir = dir_path
        while os.path.isdir(tempDir):
            random_string = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
            tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
        os.makedirs(tempDir)
        printMessage("Generated temporary directory: " + tempDir)
        with open(os.path.join(tempDir, "cwd.txt"), "w") as outfile:
            outfile.write(workingDir + "\n")
        with open(os.path.join(tempDir, "command.txt"), "w") as outfile:
            outfile.write(" ".join(sys.argv) + "\n")
    use_colour = readMRtrixConfSetting("TerminalColor")
    if use_colour:
        use_colour = use_colour.lower() in ("yes", "true", "1")
    else:
        use_colour = not sys.platform.startswith("win")
    if use_colour:
        colourClear = "\033[0m"
        colourConsole = "\033[03;34m"
        colourError = "\033[01;31m"
        colourPrint = "\033[03;32m"
        colourWarn = "\033[00;31m"
コード例 #8
0
def gotoTempDir():
    import os
    from lib.errorMessage import errorMessage
    from lib.printMessage import printMessage
    global tempDir
    if not tempDir:
        errorMessage('Script error: No temporary directory location set')
    if verbosity:
        printMessage('Changing to temporary directory (' + tempDir + ')')
    os.chdir(tempDir)
コード例 #9
0
ファイル: app.py プロジェクト: emanuele/mrtrix3
def gotoTempDir():
  import os
  from lib.errorMessage import errorMessage
  from lib.printMessage import printMessage
  global tempDir
  if not tempDir:
    errorMessage('Script error: No temporary directory location set')
  if verbosity:
    printMessage('Changing to temporary directory (' + tempDir + ')')
  os.chdir(tempDir)
コード例 #10
0
ファイル: getHeaderInfo.py プロジェクト: apprisi/mrtrix3
def getHeaderInfo(image_path, header_item):
  import lib.app, os, subprocess, sys
  from lib.printMessage import printMessage
  command = 'mrinfo ' + image_path + ' -' + header_item
  if lib.app.verbosity > 1:
    printMessage('Command: \'' + command + '\' (piping data to local storage)')
  proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
  result = proc.stdout.read()
  result = result.rstrip().decode('utf-8')
  if lib.app.verbosity > 1:
    printMessage ('Result: ' + result)
  return result
コード例 #11
0
ファイル: app.py プロジェクト: MarcRamos/mrtrix3
def complete():
  import os, shutil, sys
  from lib.printMessage import printMessage
  printMessage('Changing back to original directory (' + workingDir + ')')
  os.chdir(workingDir)
  if cleanup:
    printMessage('Deleting temporary directory ' + tempDir)
    shutil.rmtree(tempDir)
  else:
    # This needs to be printed even if the -quiet option is used
    sys.stdout.write(os.path.basename(sys.argv[0]) + ': ' + colourPrint + 'Contents of temporary directory kept, location: ' + tempDir + colourClear + '\n')
    sys.stdout.flush()
コード例 #12
0
def complete():
  import os, shutil, sys
  from lib.printMessage import printMessage
  printMessage('Changing back to original directory (' + workingDir + ')')
  os.chdir(workingDir)
  if cleanup:
    printMessage('Deleting temporary directory ' + tempDir)
    shutil.rmtree(tempDir)
  else:
    # This needs to be printed even if the -quiet option is used
    sys.stdout.write(os.path.basename(sys.argv[0]) + ': ' + colourPrint + 'Contents of temporary directory kept, location: ' + tempDir + colourClear + '\n')
    sys.stdout.flush()
コード例 #13
0
ファイル: getHeaderInfo.py プロジェクト: MarcRamos/mrtrix3
def getHeaderInfo(image_path, header_item):
  import lib.app, subprocess
  from lib.printMessage import printMessage
  command = [ 'mrinfo', image_path, '-' + header_item ]
  if lib.app.verbosity > 1:
    printMessage('Command: \'' + ' '.join(command) + '\' (piping data to local storage)')
  proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
  result, err = proc.communicate()
  result = result.rstrip().decode('utf-8')
  if lib.app.verbosity > 1:
    printMessage('Result: ' + result)
  return result
コード例 #14
0
def getHeaderInfo(image_path, header_item):
    import lib.app, subprocess
    from lib.printMessage import printMessage
    command = ['mrinfo', image_path, '-' + header_item]
    if lib.app.verbosity > 1:
        printMessage('Command: \'' + ' '.join(command) +
                     '\' (piping data to local storage)')
    proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
    result, err = proc.communicate()
    result = result.rstrip().decode('utf-8')
    if lib.app.verbosity > 1:
        printMessage('Result: ' + result)
    return result
コード例 #15
0
ファイル: getImageStat.py プロジェクト: echohenry2006/mrtrix3
def getImageStat(image_path, statistic, mask_path = ''):
  import lib.app, os, subprocess, sys
  from lib.printMessage import printMessage
  command = 'mrstats ' + image_path + ' -output ' + statistic
  if mask_path:
    command += ' -mask ' + mask_path
  if lib.app.verbosity > 1:
    printMessage('Command: \'' + command + '\' (piping data to local storage)')
  proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
  result = proc.stdout.read()
  result = result.rstrip().decode('utf-8')
  if lib.app.verbosity > 1:
    printMessage('Result: ' + result)
  return result
コード例 #16
0
ファイル: getImageStat.py プロジェクト: nakae-k/mrtrix3
def getImageStat(image_path, statistic, mask_path=''):
    import lib.app, subprocess
    from lib.printMessage import printMessage
    command = ['mrstats', image_path, '-output', statistic]
    if mask_path:
        command.extend(['-mask', mask_path])
    if lib.app.verbosity > 1:
        printMessage('Command: \'' + ' '.join(command) +
                     '\' (piping data to local storage)')
    proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
    result, err = proc.communicate()
    result = result.rstrip().decode('utf-8')
    if lib.app.verbosity > 1:
        printMessage('Result: ' + result)
    return result
コード例 #17
0
def getHeaderInfo(image_path, header_item):
    import lib.app, os, subprocess, sys
    from lib.printMessage import printMessage
    command = 'mrinfo ' + image_path + ' -' + header_item
    if lib.app.verbosity > 1:
        printMessage('Command: \'' + command +
                     '\' (piping data to local storage)')
    proc = subprocess.Popen(command,
                            stdout=subprocess.PIPE,
                            stderr=None,
                            shell=True)
    result = proc.stdout.read()
    result = result.rstrip().decode('utf-8')
    if lib.app.verbosity > 1:
        printMessage('Result: ' + result)
    return result
コード例 #18
0
ファイル: app.py プロジェクト: skeif/mrtrix3
def initialise(n):
  import os, random, string, sys
  from lib.printMessage          import printMessage
  from lib.readMRtrixConfSetting import readMRtrixConfSetting
  global cleanup, mrtrixQuiet, numArgs, tempDir, verbosity, workingDir
  #if not numArgs:
  #  sys.stderr.write('Must set numArgs value before calling initialise()\n')
  #  exit(1)
  numArgs = n
  workingDir = os.getcwd()
  for option in sys.argv[numArgs+1:]:
    if '-verbose'.startswith(option):
      verbosity = 2
      mrtrixQuiet = ''
    elif '-quiet'.startswith(option):
      verbosity = 0
      mrtrixQuiet = '-quiet'
    elif '-nocleanup'.startswith(option):
      cleanup = False
    else:
      sys.stderr.write('Unknown option: ' + option + '\n')
      exit(1)
  # Create the temporary directory
  dir_path = readMRtrixConfSetting('TmpFileDir')
  if not dir_path:
    if os.name == 'posix':
      dir_path = '/tmp'
    else:
      dir_path = '.'
  prefix = readMRtrixConfSetting('TmpFilePrefix')
  if not prefix:
    prefix = os.path.basename(sys.argv[0]) + '-tmp-'
  tempDir = dir_path
  while os.path.isdir(tempDir):
    random_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
    tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
  os.makedirs(tempDir)
  printMessage('Generated temporary directory: ' + tempDir)
コード例 #19
0
def makeTempDir():
    import os, random, string, sys
    from lib.errorMessage import errorMessage
    from lib.printMessage import printMessage
    from lib.readMRtrixConfSetting import readMRtrixConfSetting
    global args, tempDir
    if args.cont:
        printMessage(
            'Skipping temporary directory creation due to use of -continue option'
        )
        return
    if tempDir:
        errorMessage('Script error: Cannot use multiple temporary directories')
    if args.tempdir:
        dir_path = os.path.abspath(args.tempdir)
    else:
        dir_path = readMRtrixConfSetting('TmpFileDir')
        if not dir_path:
            if os.name == 'posix':
                dir_path = '/tmp'
            else:
                dir_path = '.'
    prefix = readMRtrixConfSetting('TmpFilePrefix')
    if not prefix:
        prefix = os.path.basename(sys.argv[0]) + '-tmp-'
    tempDir = dir_path
    while os.path.isdir(tempDir):
        random_string = ''.join(
            random.choice(string.ascii_uppercase + string.digits)
            for x in range(6))
        tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
    os.makedirs(tempDir)
    printMessage('Generated temporary directory: ' + tempDir)
    with open(os.path.join(tempDir, 'cwd.txt'), 'w') as outfile:
        outfile.write(workingDir + '\n')
    with open(os.path.join(tempDir, 'command.txt'), 'w') as outfile:
        outfile.write(' '.join(sys.argv) + '\n')
コード例 #20
0
ファイル: app.py プロジェクト: skeif/mrtrix3
def terminate():
  import os, shutil
  from lib.printMessage import printMessage
  printMessage('Changing back to original directory (' + workingDir + ')')
  os.chdir(workingDir)
  if cleanup:
    printMessage('Deleting temporary directory ' + tempDir)
    shutil.rmtree(tempDir)
  else:
    printMessage('Contents of temporary directory kept, location: ' + tempDir)
コード例 #21
0
ファイル: run.py プロジェクト: BIDS-Apps/FixelAnalysis
lib.app.makeTempDir()

# read in group subset if supplied
subset = []
if lib.app.args.group_subset:
  subset = lib.app.args.group_subset[0].split(',')


# running participant level 1 (basic preprocessing)
if lib.app.args.analysis_level == 'participant1':

  subprocess.check_call('bids-validator ' + lib.app.args.bids_dir, shell=True)

  for subject_label in subjects_to_analyze:
    label = 'sub-' + subject_label
    printMessage('running basic pre-processing for ' + label)

    # Read DWI(s) in BIDS folder
    all_dwi_images = glob(os.path.join(lib.app.args.bids_dir, label, '*dwi', '*_dwi.nii*'))

    # TODO handle multiple DWIs (e.g. time points) in subject directory
    if (len(all_dwi_images) > 1):
      errorMessage('Multiple DWIs found in subject folder. Multiple sessions not currently supported.')

    # Create output subject directory
    subject_dir = os.path.join(all_subjects_dir, subject_label)
    if not os.path.exists(subject_dir):
      os.mkdir(subject_dir)

    # Check existence output files from this analysis level
    dwi_preproc_file = os.path.join(subject_dir, 'dwi_preproc.mif')
コード例 #22
0
ファイル: app.py プロジェクト: MarcRamos/mrtrix3
def initialise():
  import argparse, os, random, string, sys
  from lib.printMessage          import printMessage
  from lib.printUsageMarkdown    import printUsageMarkdown
  from lib.printUsageRst         import printUsageRst
  from lib.readMRtrixConfSetting import readMRtrixConfSetting
  global args, author, cleanup, lastFile, mrtrixNThreads, mrtrixQuiet, standardOptions, parser, refList, tempDir, verbosity, workingDir
  global colourClear, colourConsole, colourError, colourPrint, colourWarn
  
  if len(sys.argv) == 2 and sys.argv[1] == '__print_usage_markdown__':
    printUsageMarkdown(parser, standardOptions, refList, author)
    exit(0)

  if len(sys.argv) == 2 and sys.argv[1] == '__print_usage_rst__':
    printUsageRst(parser, standardOptions, refList, author)
    exit(0)
  
  workingDir = os.getcwd()
  args = parser.parse_args()
  if args.help or len(sys.argv) == 1:
    parser.print_help()
    sys.exit(0)

  use_colour = readMRtrixConfSetting('TerminalColor')
  if use_colour:
    use_colour = use_colour.lower() in ('yes', 'true', '1')
  else:
    use_colour = not sys.platform.startswith('win')
  if use_colour:
    colourClear = '\033[0m'
    colourConsole = '\033[03;34m'
    colourError = '\033[01;31m'
    colourPrint = '\033[03;32m'
    colourWarn = '\033[00;31m'

  if args.nocleanup:
    cleanup = False
  if args.nthreads:
    mrtrixNThreads = ' -nthreads ' + args.nthreads
  if args.quiet:
    verbosity = 0
    mrtrixQuiet = ' -quiet'
  if args.verbose:
    verbosity = 2
    mrtrixQuiet = ''

  if citationWarning:
    printMessage('')
    printMessage(citationWarning)
    printMessage('')

  if args.cont:
    tempDir = os.path.abspath(args.cont[0])
    lastFile = args.cont[1]
  else:
    if args.tempdir:
      dir_path = os.path.abspath(args.tempdir)
    else:
      dir_path = readMRtrixConfSetting('TmpFileDir')
      if not dir_path:
        if os.name == 'posix':
          dir_path = '/tmp'
        else:
          dir_path = '.'
    prefix = readMRtrixConfSetting('TmpFilePrefix')
    if not prefix:
      prefix = os.path.basename(sys.argv[0]) + '-tmp-'
    tempDir = dir_path
    while os.path.isdir(tempDir):
      random_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
      tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
    os.makedirs(tempDir)
    printMessage('Generated temporary directory: ' + tempDir)
    with open(os.path.join(tempDir, 'cwd.txt'), 'w') as outfile:
      outfile.write(workingDir + '\n')
    with open(os.path.join(tempDir, 'command.txt'), 'w') as outfile:
      outfile.write(' '.join(sys.argv) + '\n')
コード例 #23
0
ファイル: msmt_5tt.py プロジェクト: MarcRamos/mrtrix3
def execute():
  import math, os, shutil
  import lib.app
  from lib.getHeaderInfo import getHeaderInfo
  from lib.getImageStat  import getImageStat
  from lib.getUserPath   import getUserPath
  from lib.printMessage  import printMessage
  from lib.runCommand    import runCommand
  from lib.warnMessage   import warnMessage
  from lib.errorMessage  import errorMessage
  
  # Ideally want to use the oversampling-based regridding of the 5TT image from the SIFT model, not mrtransform
  # May need to commit 5ttregrid...

  # Verify input 5tt image
  sizes = [ int(x) for x in getHeaderInfo('5tt.mif', 'size').split() ]
  datatype = getHeaderInfo('5tt.mif', 'datatype')
  if not len(sizes) == 4 or not sizes[3] == 5 or not datatype.startswith('Float'):
    errorMessage('Imported anatomical image ' + os.path.basename(lib.app.args.in_5tt) + ' is not in the 5TT format')

  # Get shell information
  shells = [ int(round(float(x))) for x in getHeaderInfo('dwi.mif', 'shells').split() ]
  if len(shells) < 3:
    warnMessage('Less than three b-value shells; response functions will not be applicable in MSMT-CSD algorithm')

  # Get lmax information (if provided)
  wm_lmax = [ ]
  if lib.app.args.lmax:
    wm_lmax = [ int(x.strip()) for x in lib.app.args.lmax.split(',') ]
    if not len(wm_lmax) == len(shells):
      errorMessage('Number of manually-defined lmax\'s (' + str(len(wm_lmax)) + ') does not match number of b-value shells (' + str(len(shells)) + ')')
    for l in wm_lmax:
      if l%2:
        errorMessage('Values for lmax must be even')
      if l<0:
        errorMessage('Values for lmax must be non-negative')

  runCommand('dwi2tensor dwi.mif - -mask mask.mif | tensor2metric - -fa fa.mif -vector vector.mif')
  if not os.path.exists('dirs.mif'):
    shutil.copy('vector.mif', 'dirs.mif')
  runCommand('mrtransform 5tt.mif 5tt_regrid.mif -template fa.mif -interp linear')

  # Basic tissue masks
  runCommand('mrconvert 5tt_regrid.mif - -coord 3 2 -axes 0,1,2 | mrcalc - ' + str(lib.app.args.pvf) + ' -gt mask.mif -mult wm_mask.mif')
  runCommand('mrconvert 5tt_regrid.mif - -coord 3 0 -axes 0,1,2 | mrcalc - ' + str(lib.app.args.pvf) + ' -gt fa.mif ' + str(lib.app.args.fa) + ' -lt -mult mask.mif -mult gm_mask.mif')
  runCommand('mrconvert 5tt_regrid.mif - -coord 3 3 -axes 0,1,2 | mrcalc - ' + str(lib.app.args.pvf) + ' -gt fa.mif ' + str(lib.app.args.fa) + ' -lt -mult mask.mif -mult csf_mask.mif')

  # Revise WM mask to only include single-fibre voxels
  printMessage('Calling dwi2response recursively to select WM single-fibre voxels using \'' + lib.app.args.wm_algo + '\' algorithm')
  recursive_cleanup_option=''
  if not lib.app.cleanup:
    recursive_cleanup_option = ' -nocleanup'
  runCommand('dwi2response -quiet -tempdir ' + lib.app.tempDir + recursive_cleanup_option + ' ' + lib.app.args.wm_algo + ' dwi.mif wm_ss_response.txt -mask wm_mask.mif -voxels wm_sf_mask.mif')

  # Check for empty masks
  wm_voxels  = int(getImageStat('wm_sf_mask.mif', 'count', 'wm_sf_mask.mif'))
  gm_voxels  = int(getImageStat('gm_mask.mif',    'count', 'gm_mask.mif'))
  csf_voxels = int(getImageStat('csf_mask.mif',   'count', 'csf_mask.mif'))
  empty_masks = [ ]
  if not wm_voxels:
    empty_masks.append('WM')
  if not gm_voxels:
    empty_masks.append('GM')
  if not csf_voxels:
    empty_masks.append('CSF')
  if empty_masks:
    message = ','.join(empty_masks)
    message += ' tissue mask'
    if len(empty_masks) > 1:
      message += 's'
    message += ' empty; cannot estimate response function'
    if len(empty_masks) > 1:
      message += 's'
    errorMessage(message)

  # For each of the three tissues, generate a multi-shell response
  # Since here we're guaranteeing that GM and CSF will be isotropic in all shells, let's use mrstats rather than sh2response (seems a bit weird passing a directions file to sh2response with lmax=0...)

  wm_responses  = [ ]
  gm_responses  = [ ]
  csf_responses = [ ]
  max_length = 0

  for index, b in enumerate(shells):
    dwi_path = 'dwi_b' + str(b) + '.mif'
    # dwiextract will yield a 4D image, even if there's only a single volume in a shell
    runCommand('dwiextract dwi.mif -shell ' + str(b) + ' ' + dwi_path)
    this_b_lmax_option = ''
    if wm_lmax:
      this_b_lmax_option = ' -lmax ' + str(wm_lmax[index])
    runCommand('amp2sh ' + dwi_path + ' - | sh2response - wm_sf_mask.mif dirs.mif wm_response_b' + str(b) + '.txt' + this_b_lmax_option)
    wm_response = open('wm_response_b' + str(b) + '.txt', 'r').read().split()
    wm_responses.append(wm_response)
    max_length = max(max_length, len(wm_response))
    mean_dwi_path = 'dwi_b' + str(b) + '_mean.mif'
    runCommand('mrmath ' + dwi_path + ' mean ' + mean_dwi_path + ' -axis 3')
    gm_mean  = float(getImageStat(mean_dwi_path, 'mean', 'gm_mask.mif'))
    csf_mean = float(getImageStat(mean_dwi_path, 'mean', 'csf_mask.mif'))
    gm_responses .append( str(gm_mean  * math.sqrt(4.0 * math.pi)) )
    csf_responses.append( str(csf_mean * math.sqrt(4.0 * math.pi)) )

  with open('wm.txt', 'w') as f:
    for line in wm_responses:
      line += ['0'] * (max_length - len(line))
      f.write(' '.join(line) + '\n')
  with open('gm.txt', 'w') as f:
    for line in gm_responses:
      f.write(line + '\n')
  with open('csf.txt', 'w') as f:
    for line in csf_responses:
      f.write(line + '\n')

  shutil.copyfile('wm.txt',  getUserPath(lib.app.args.out_wm,  False))
  shutil.copyfile('gm.txt',  getUserPath(lib.app.args.out_gm,  False))
  shutil.copyfile('csf.txt', getUserPath(lib.app.args.out_csf, False))

  # Generate output 4D binary image with voxel selections; RGB as in MSMT-CSD paper
  runCommand('mrcat csf_mask.mif gm_mask.mif wm_sf_mask.mif voxels.mif -axis 3')
コード例 #24
0
lib.app.makeTempDir()

# read in group subset if supplied
subset = []
if lib.app.args.group_subset:
  subset = lib.app.args.group_subset[0].split(',')


# running participant level 1 (calculate response function )
if lib.app.args.analysis_level == 'participant1':



  for subject_label in subjects_to_analyze:
    label = 'sub-' + subject_label
    printMessage('running pre-processing for ' + label)

    # Read DWI in BIDS derivatives folder
    all_dwi_images = glob(os.path.join(lib.app.args.bids_dir, label, '*dwi', '*_dwi.nii*'))


    # Create output subject directory
    subject_dir = os.path.join(all_subjects_dir, subject_label)
    if not os.path.exists(subject_dir):
      os.mkdir(subject_dir)

    # Check existence output files from this analysis level
    dwi_preproc_file = os.path.join(subject_dir, 'dwi_preproc.mif')
    lib.app.checkOutputFile(dwi_preproc_file)
    wm_response_file = os.path.join(subject_dir, 'wm_response.txt')
    lib.app.checkOutputFile(wm_response_file)
コード例 #25
0
ファイル: tournier.py プロジェクト: emanuele/mrtrix3
def execute():
  import os, shutil
  import lib.app
  from lib.delFile      import delFile
  from lib.getImageStat import getImageStat
  from lib.getUserPath  import getUserPath
  from lib.printMessage import printMessage
  from lib.runCommand   import runCommand
  
  lmax_option = ''
  if lib.app.args.lmax:
    lmax_option = ' -lmax ' + lib.app.args.lmax

  if lib.app.args.max_iters < 2:
    errorMessage('Number of iterations must be at least 2')

  runCommand('amp2sh dwi.mif dwiSH.mif' + lmax_option)

  for iteration in range(0, lib.app.args.max_iters):
    prefix = 'iter' + str(iteration) + '_'
  
    if iteration == 0:
      RF_in_path = 'init_RF.txt'
      mask_in_path = 'mask.mif'
      init_RF = '1 -1 1'
      with open(RF_in_path, 'w') as f:
        f.write(init_RF);
      iter_lmax_option = ' -lmax 4'
    else:
      RF_in_path = 'iter' + str(iteration-1) + '_RF.txt'
      mask_in_path = 'iter' + str(iteration-1) + '_SF_dilated.mif'
      iter_lmax_option = lmax_option

    # Run CSD
    runCommand('dwi2fod csd dwi.mif ' + RF_in_path + ' ' + prefix + 'FOD.mif -mask ' + mask_in_path + iter_lmax_option)
    # Get amplitudes of two largest peaks, and direction of largest
    # TODO Speed-test fod2fixel against sh2peaks
    # TODO Add maximum number of fixels per voxel option to fod2fixel?
    runCommand('fod2fixel ' + prefix + 'FOD.mif -peak ' + prefix + 'peaks.msf -mask ' + mask_in_path + ' -fmls_no_thresholds')
    delFile(prefix + 'FOD.mif')
    if iteration:
      delFile(mask_in_path)
    runCommand('fixel2voxel ' + prefix + 'peaks.msf split_value ' + prefix + 'amps.mif')
    runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix + 'first_peaks.mif -coord 3 0 -axes 0,1,2')
    runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix + 'second_peaks.mif -coord 3 1 -axes 0,1,2')
    delFile(prefix + 'amps.mif')
    runCommand('fixel2voxel ' + prefix + 'peaks.msf split_dir ' + prefix + 'all_dirs.mif')
    delFile(prefix + 'peaks.msf')
    runCommand('mrconvert ' + prefix + 'all_dirs.mif ' + prefix + 'first_dir.mif -coord 3 0:2')
    delFile(prefix + 'all_dirs.mif')
    # Calculate the 'cost function' Donald derived for selecting single-fibre voxels
    # https://github.com/MRtrix3/mrtrix3/pull/426
    #  sqrt(|peak1|) * (1 - |peak2| / |peak1|)^2
    runCommand('mrcalc ' + prefix + 'first_peaks.mif -sqrt 1 ' + prefix + 'second_peaks.mif ' + prefix + 'first_peaks.mif -div -sub 2 -pow -mult '+ prefix + 'CF.mif')
    delFile(prefix + 'first_peaks.mif')
    delFile(prefix + 'second_peaks.mif')
    # Select the top-ranked voxels
    runCommand('mrthreshold ' + prefix + 'CF.mif -top ' + str(lib.app.args.sf_voxels) + ' ' + prefix + 'SF.mif')
    # Generate a new response function based on this selection
    runCommand('sh2response dwiSH.mif ' + prefix + 'SF.mif ' + prefix + 'first_dir.mif ' + prefix + 'RF.txt' + iter_lmax_option)
    delFile(prefix + 'first_dir.mif')
    # Should we terminate?
    if iteration > 0:
      runCommand('mrcalc ' + prefix + 'SF.mif iter' + str(iteration-1) + '_SF.mif -sub ' + prefix + 'SF_diff.mif')
      delFile('iter' + str(iteration-1) + '_SF.mif')
      max_diff = getImageStat(prefix + 'SF_diff.mif', 'max')
      delFile(prefix + 'SF_diff.mif')
      if int(max_diff) == 0:
        printMessage('Convergence of SF voxel selection detected at iteration ' + str(iteration))
        delFile(prefix + 'CF.mif')
        shutil.copyfile(prefix + 'RF.txt', 'response.txt')
        shutil.move(prefix + 'SF.mif', 'voxels.mif')
        break

    # Select a greater number of top single-fibre voxels, and dilate (within bounds of initial mask);
    #   these are the voxels that will be re-tested in the next iteration
    runCommand('mrthreshold ' + prefix + 'CF.mif -top ' + str(lib.app.args.iter_voxels) + ' - | maskfilter - dilate - -npass ' + str(lib.app.args.dilate) + ' | mrcalc mask.mif - -mult ' + prefix + 'SF_dilated.mif')
    delFile(prefix + 'CF.mif')

  # Commence the next iteration

  # If terminating due to running out of iterations, still need to put the results in the appropriate location
  if not os.path.exists('response.txt'):
    printMessage('Exiting after maximum ' + str(lib.app.args.max_iters) + ' iterations')
    shutil.copyfile('iter' + str(lib.app.args.max_iters-1) + '_RF.txt', 'response.txt')
    shutil.move('iter' + str(lib.app.args.max_iters-1) + '_SF.mif', 'voxels.mif')
    
  shutil.copyfile('response.txt', getUserPath(lib.app.args.output, False))
コード例 #26
0
ファイル: runCommand.py プロジェクト: emanuele/mrtrix3
def runCommand(cmd, exitOnError=True):

  import lib.app, os, subprocess, sys
  from lib.errorMessage import errorMessage
  from lib.isWindows    import isWindows
  from lib.printMessage import printMessage
  from lib.warnMessage  import warnMessage
  import distutils
  from distutils.spawn import find_executable
  global mrtrix_bin_list
  global mrtrix_bin_path

  if not mrtrix_bin_list:
    mrtrix_bin_path = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(os.path.realpath(__file__))), os.pardir, os.pardir, 'release', 'bin'));
    # On Windows, strip the .exe's
    mrtrix_bin_list = [ os.path.splitext(name)[0] for name in os.listdir(mrtrix_bin_path) ]

  if lib.app.lastFile:
    # Check to see if the last file produced is produced by this command;
    #   if it is, this will be the last called command that gets skipped
    if lib.app.lastFile in cmd:
      lib.app.lastFile = ''
    if lib.app.verbosity:
      sys.stdout.write('Skipping command: ' + cmd + '\n')
      sys.stdout.flush()
    return

  # Vectorise the command string, preserving anything encased within quotation marks
  # This will eventually allow the use of subprocess rather than os.system()
  # TODO Use shlex.split()?
  quotation_split = cmd.split('\"')
  if not len(quotation_split)%2:
    errorMessage('Malformed command \"' + cmd + '\": odd number of quotation marks')
  cmdsplit = [ ]
  if len(quotation_split) == 1:
    cmdsplit = cmd.split()
  else:
    for index, item in enumerate(quotation_split):
      if index%2:
        cmdsplit.append(item)
      else:
        cmdsplit.extend(item.split())

  # For any MRtrix commands, need to insert the nthreads and quiet calls
  new_cmdsplit = [ ]
  is_mrtrix_binary = False
  next_is_binary = True
  for item in cmdsplit:
    if next_is_binary:
      is_mrtrix_binary = item in mrtrix_bin_list
      # Make sure we're not accidentally running an MRtrix command from a different installation to the script
      if is_mrtrix_binary:
        binary_sys = find_executable(item)
        binary_manual = os.path.join(mrtrix_bin_path, item)
        if (isWindows()):
          binary_manual = binary_manual + '.exe'
        use_manual_binary_path = not binary_sys
        if not use_manual_binary_path:
          # os.path.samefile() not supported on all platforms / Python versions
          if hasattr(os.path, 'samefile'):
            use_manual_binary_path = not os.path.samefile(binary_sys, binary_manual)
          else:
            # Hack equivalent of samefile(); not perfect, but should be adequate for use here
            use_manual_binary_path = not os.path.normcase(os.path.normpath(binary_sys)) == os.path.normcase(os.path.normpath(binary_manual))
        if use_manual_binary_path:
          item = binary_manual
      next_is_binary = False
    if item == '|':
      if is_mrtrix_binary:
        if lib.app.mrtrixNThreads:
          new_cmdsplit.extend(lib.app.mrtrixNThreads.strip().split())
        if lib.app.mrtrixQuiet:
          new_cmdsplit.append(lib.app.mrtrixQuiet.strip())
      next_is_binary = True
    new_cmdsplit.append(item)
  if is_mrtrix_binary:
    if lib.app.mrtrixNThreads:
      new_cmdsplit.extend(lib.app.mrtrixNThreads.strip().split())
    if lib.app.mrtrixQuiet:
      new_cmdsplit.append(lib.app.mrtrixQuiet.strip())
  cmdsplit = new_cmdsplit

  # If the piping symbol appears anywhere, we need to split this into multiple commands and execute them separately
  # If no piping symbols, the entire command should just appear as a single row in cmdstack
  cmdstack = [ ]
  prev = 0
  for index, item in enumerate(cmdsplit):
    if item == '|':
      cmdstack.append(cmdsplit[prev:index])
      prev = index + 1
  cmdstack.append(cmdsplit[prev:])

  if lib.app.verbosity:
    sys.stdout.write(lib.app.colourConsole + 'Command:' + lib.app.colourClear + ' ' + cmd + '\n')
    sys.stdout.flush()

  error = False
  error_text = ''
  # TODO If script is running in verbose mode, ideally want to duplicate stderr output in the terminal
  if len(cmdstack) == 1:
    process = subprocess.Popen(cmdstack[0], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (stdoutdata, stderrdata) = process.communicate()
    if process.returncode:
      error = True
      error_text = stdoutdata.decode('utf-8') + stderrdata.decode('utf-8')
  else:
    processes = [ ]
    for index, command in enumerate(cmdstack):
      if index > 0:
        proc_in = processes[index-1].stdout
      else:
        proc_in = None
      process = subprocess.Popen (command, stdin=proc_in, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
      processes.append(process)

    # Wait for all commands to complete
    for index, process in enumerate(processes):
      if index < len(cmdstack)-1:
        # Only capture the output if the command failed; otherwise, let it pipe to the next command
        process.wait()
        if process.returncode:
          error = True
          (stdoutdata, stderrdata) = process.communicate()
          error_text = error_text + stdoutdata.decode('utf-8') + stderrdata.decode('utf-8')
      else:
        (stdoutdata, stderrdata) = process.communicate()
        if process.returncode:
          error = True
          error_text = error_text + stdoutdata.decode('utf-8') + stderrdata.decode('utf-8')


  if (error):
    if exitOnError:
      printMessage('')
      sys.stderr.write(os.path.basename(sys.argv[0]) + ': ' + lib.app.colourError + '[ERROR] Command failed: ' + cmd + lib.app.colourClear + '\n')
      sys.stderr.write(os.path.basename(sys.argv[0]) + ': ' + lib.app.colourPrint + 'Output of failed command:' + lib.app.colourClear + '\n')
      sys.stderr.write(error_text)
      if not lib.app.cleanup and lib.app.tempDir:
        with open(os.path.join(lib.app.tempDir, 'error.txt'), 'w') as outfile:
          outfile.write(cmd + '\n\n' + error_text + '\n')
      lib.app.complete()
      exit(1)
    else:
      warnMessage('Command failed: ' + cmd)

  # Only now do we append to the script log, since the command has completed successfully
  # Note: Writing the command as it was formed as the input to runCommand():
  #   other flags may potentially change if this file is eventually used to resume the script
  if lib.app.tempDir:
    with open(os.path.join(lib.app.tempDir, 'log.txt'), 'a') as outfile:
      outfile.write(cmd + '\n')
コード例 #27
0
ファイル: app.py プロジェクト: echohenry2006/mrtrix3
def initialise():
    import argparse, os, random, string, sys
    from lib.printMessage import printMessage
    from lib.printUsageMarkdown import printUsageMarkdown
    from lib.printUsageRst import printUsageRst
    from lib.readMRtrixConfSetting import readMRtrixConfSetting
    global args, author, cleanup, lastFile, mrtrixNThreads, mrtrixQuiet, standardOptions, parser, refList, tempDir, verbosity, workingDir
    global colourClear, colourConsole, colourError, colourPrint, colourWarn

    if len(sys.argv) == 2 and sys.argv[1] == '__print_usage_markdown__':
        printUsageMarkdown(parser, standardOptions, refList, author)
        exit(0)

    if len(sys.argv) == 2 and sys.argv[1] == '__print_usage_rst__':
        printUsageRst(parser, standardOptions, refList, author)
        exit(0)

    workingDir = os.getcwd()
    args = parser.parse_args()
    if args.help or len(sys.argv) == 1:
        parser.print_help()
        sys.exit(0)

    use_colour = readMRtrixConfSetting('TerminalColor')
    if use_colour:
        use_colour = use_colour.lower() in ('yes', 'true', '1')
    else:
        use_colour = not sys.platform.startswith('win')
    if use_colour:
        colourClear = '\033[0m'
        colourConsole = '\033[03;34m'
        colourError = '\033[01;31m'
        colourPrint = '\033[03;32m'
        colourWarn = '\033[00;31m'

    if args.nocleanup:
        cleanup = False
    if args.nthreads:
        mrtrixNThreads = '-nthreads ' + args.nthreads
    if args.quiet:
        verbosity = 0
        mrtrixQuiet = '-quiet'
    if args.verbose:
        verbosity = 2
        mrtrixQuiet = ''

    if citationWarning:
        printMessage('')
        printMessage(citationWarning)
        printMessage('')

    if args.cont:
        tempDir = os.path.abspath(args.cont[0])
        lastFile = args.cont[1]
    else:
        if args.tempdir:
            dir_path = os.path.abspath(args.tempdir)
        else:
            dir_path = readMRtrixConfSetting('TmpFileDir')
            if not dir_path:
                if os.name == 'posix':
                    dir_path = '/tmp'
                else:
                    dir_path = '.'
        prefix = readMRtrixConfSetting('TmpFilePrefix')
        if not prefix:
            prefix = os.path.basename(sys.argv[0]) + '-tmp-'
        tempDir = dir_path
        while os.path.isdir(tempDir):
            random_string = ''.join(
                random.choice(string.ascii_uppercase + string.digits)
                for x in range(6))
            tempDir = os.path.join(dir_path, prefix + random_string) + os.sep
        os.makedirs(tempDir)
        printMessage('Generated temporary directory: ' + tempDir)
        with open(os.path.join(tempDir, 'cwd.txt'), 'w') as outfile:
            outfile.write(workingDir + '\n')
        with open(os.path.join(tempDir, 'command.txt'), 'w') as outfile:
            outfile.write(' '.join(sys.argv) + '\n')
コード例 #28
0
ファイル: app.py プロジェクト: echohenry2006/mrtrix3
def gotoTempDir():
    import os
    from lib.printMessage import printMessage
    if verbosity:
        printMessage('Changing to temporary directory (' + tempDir + ')')
    os.chdir(tempDir)
コード例 #29
0
ファイル: tax.py プロジェクト: nakae-k/mrtrix3
def execute():
    import math, os, shutil
    import lib.app
    from lib.getImageStat import getImageStat
    from lib.getUserPath import getUserPath
    from lib.printMessage import printMessage
    from lib.runCommand import runCommand

    lmax_option = ''
    if lib.app.args.lmax:
        lmax_option = ' -lmax ' + lib.app.args.lmax

    runCommand('amp2sh dwi.mif dwiSH.mif' + lmax_option)
    convergence_change = 0.01 * lib.app.args.convergence

    for iteration in range(0, lib.app.args.max_iters):
        prefix = 'iter' + str(iteration) + '_'

        # How to initialise response function?
        # old dwi2response command used mean & standard deviation of DWI data; however
        #   this may force the output FODs to lmax=2 at the first iteration
        # Chantal used a tensor with low FA, but it'd be preferable to get the scaling right
        # Other option is to do as before, but get the ratio between l=0 and l=2, and
        #   generate l=4,6,... using that amplitude ratio
        if iteration == 0:
            RF_in_path = 'init_RF.txt'
            mask_in_path = 'mask.mif'
            runCommand('dwiextract dwi.mif shell.mif')
            # TODO This can be changed once #71 is implemented (mrstats statistics across volumes)
            volume_means = [
                float(x)
                for x in getImageStat('shell.mif', 'mean', 'mask.mif').split()
            ]
            mean = sum(volume_means) / float(len(volume_means))
            volume_stds = [
                float(x)
                for x in getImageStat('shell.mif', 'std', 'mask.mif').split()
            ]
            std = sum(volume_stds) / float(len(volume_stds))
            # Scale these to reflect the fact that we're moving to the SH basis
            mean *= math.sqrt(4.0 * math.pi)
            std *= math.sqrt(4.0 * math.pi)
            # Now produce the initial response function
            # Let's only do it to lmax 4
            init_RF = [
                str(mean),
                str(-0.5 * std),
                str(0.25 * std * std / mean)
            ]
            with open('init_RF.txt', 'w') as f:
                f.write(' '.join(init_RF))
        else:
            RF_in_path = 'iter' + str(iteration - 1) + '_RF.txt'
            mask_in_path = 'iter' + str(iteration - 1) + '_SF.mif'

        # Run CSD
        runCommand('dwi2fod csd dwi.mif ' + RF_in_path + ' ' + prefix +
                   'FOD.mif -mask ' + mask_in_path)
        # Get amplitudes of two largest peaks, and directions of largest
        runCommand('fod2fixel ' + prefix + 'FOD.mif -peak ' + prefix +
                   'peaks.msf -mask ' + mask_in_path + ' -fmls_no_thresholds')
        runCommand('fixel2voxel ' + prefix + 'peaks.msf split_value ' +
                   prefix + 'amps.mif')
        runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix +
                   'first_peaks.mif -coord 3 0 -axes 0,1,2')
        runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix +
                   'second_peaks.mif -coord 3 1 -axes 0,1,2')
        runCommand('fixel2voxel ' + prefix + 'peaks.msf split_dir ' + prefix +
                   'all_dirs.mif')
        runCommand('mrconvert ' + prefix + 'all_dirs.mif ' + prefix +
                   'first_dir.mif -coord 3 0:2')
        # Revise single-fibre voxel selection based on ratio of tallest to second-tallest peak
        runCommand('mrcalc ' + prefix + 'second_peaks.mif ' + prefix +
                   'first_peaks.mif -div ' + prefix + 'peak_ratio.mif')
        runCommand('mrcalc ' + prefix + 'peak_ratio.mif ' +
                   str(lib.app.args.peak_ratio) + ' -lt ' + mask_in_path +
                   ' -mult ' + prefix + 'SF.mif')
        # Make sure image isn't empty
        SF_voxel_count = int(
            getImageStat(prefix + 'SF.mif', 'count', prefix + 'SF.mif'))
        if not SF_voxel_count:
            errorMessage(
                'Aborting: All voxels have been excluded from single-fibre selection'
            )
        # Generate a new response function
        runCommand('sh2response dwiSH.mif ' + prefix + 'SF.mif ' + prefix +
                   'first_dir.mif ' + prefix + 'RF.txt' + lmax_option)

        # Detect convergence
        # Look for a change > some percentage - don't bother looking at the masks
        if iteration > 0:
            old_RF_file = open(RF_in_path, 'r')
            old_RF = [float(x) for x in old_RF_file.read().split()]
            new_RF_file = open(prefix + 'RF.txt', 'r')
            new_RF = [float(x) for x in new_RF_file.read().split()]
            reiterate = False
            for index in range(0, len(old_RF)):
                mean = 0.5 * (old_RF[index] + new_RF[index])
                diff = math.fabs(0.5 * (old_RF[index] - new_RF[index]))
                ratio = diff / mean
                if ratio > convergence_change:
                    reiterate = True
            if not reiterate:
                printMessage(
                    'Exiting at iteration ' + str(iteration) + ' with ' +
                    str(SF_voxel_count) +
                    ' SF voxels due to unchanged response function coefficients'
                )
                shutil.copyfile(prefix + 'RF.txt', 'response.txt')
                shutil.copyfile(prefix + 'SF.mif', 'voxels.mif')
                break

    # Go to the next iteration

    # If we've terminated due to hitting the iteration limiter, we still need to copy the output file(s) to the correct location
    if not os.path.exists('response.txt'):
        printMessage('Exiting after maximum ' +
                     str(lib.app.args.max_iters - 1) + ' iterations with ' +
                     str(SF_voxel_count) + ' SF voxels')
        shutil.copyfile('iter' + str(lib.app.args.max_iters - 1) + '_RF.txt',
                        'response.txt')
        shutil.copyfile('iter' + str(lib.app.args.max_iters - 1) + '_SF.mif',
                        'voxels.mif')

    shutil.copyfile('response.txt', getUserPath(lib.app.args.output, False))
コード例 #30
0
def initialise():
    import os, sys
    from lib.errorMessage import errorMessage
    from lib.printMessage import printMessage
    from lib.readMRtrixConfSetting import readMRtrixConfSetting
    global args, citationList, cleanup, externalCitations, lastFile, mrtrixNThreads, mrtrixQuiet, parser, tempDir, verbosity, workingDir
    global colourClear, colourConsole, colourError, colourPrint, colourWarn

    if not parser:
        errorMessage(
            'Script error: Command-line parser must be initialised before app')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(0)

    if sys.argv[-1] == '__print_usage_rst__':
        parser.printUsageRst()
        exit(0)

    workingDir = os.getcwd()

    args = parser.parse_args()
    if args.help:
        parser.print_help()
        sys.exit(0)

    use_colour = readMRtrixConfSetting('TerminalColor')
    if use_colour:
        use_colour = use_colour.lower() in ('yes', 'true', '1')
    else:
        # Windows now also gets coloured text terminal support, so make this the default
        use_colour = True
    if use_colour:
        colourClear = '\033[0m'
        colourConsole = '\033[03;34m'
        colourError = '\033[01;31m'
        colourPrint = '\033[03;32m'
        colourWarn = '\033[00;31m'

    if args.nocleanup:
        cleanup = False
    if args.nthreads:
        mrtrixNThreads = ' -nthreads ' + args.nthreads
    if args.quiet:
        verbosity = 0
        mrtrixQuiet = ' -quiet'
    elif args.verbose:
        verbosity = 2
        mrtrixQuiet = ''

    if citationList:
        printMessage('')
        citation_warning = 'Note that this script makes use of commands / algorithms that have relevant articles for citation'
        if externalCitations:
            citation_warning += '; INCLUDING FROM EXTERNAL SOFTWARE PACKAGES'
        citation_warning += '. Please consult the help page (-help option) for more information.'
        printMessage(citation_warning)
        printMessage('')

    if args.cont:
        tempDir = os.path.abspath(args.cont[0])
        lastFile = args.cont[1]
コード例 #31
0
ファイル: app.py プロジェクト: emanuele/mrtrix3
def initialise():
  import os, sys
  from lib.errorMessage          import errorMessage
  from lib.printMessage          import printMessage
  from lib.readMRtrixConfSetting import readMRtrixConfSetting
  global args, citationList, cleanup, externalCitations, lastFile, mrtrixNThreads, mrtrixQuiet, parser, tempDir, verbosity, workingDir
  global colourClear, colourConsole, colourError, colourPrint, colourWarn

  if not parser:
    errorMessage('Script error: Command-line parser must be initialised before app')

  if len(sys.argv) == 1:
    parser.print_help()
    sys.exit(0)

  if sys.argv[-1] == '__print_usage_rst__':
    parser.printUsageRst()
    exit(0)

  workingDir = os.getcwd()

  args = parser.parse_args()
  if args.help:
    parser.print_help()
    sys.exit(0)

  use_colour = readMRtrixConfSetting('TerminalColor')
  if use_colour:
    use_colour = use_colour.lower() in ('yes', 'true', '1')
  else:
    # Windows now also gets coloured text terminal support, so make this the default
    use_colour = True 
  if use_colour:
    colourClear = '\033[0m'
    colourConsole = '\033[03;34m'
    colourError = '\033[01;31m'
    colourPrint = '\033[03;32m'
    colourWarn = '\033[00;31m'

  if args.nocleanup:
    cleanup = False
  if args.nthreads:
    mrtrixNThreads = ' -nthreads ' + args.nthreads
  if args.quiet:
    verbosity = 0
    mrtrixQuiet = ' -quiet'
  elif args.verbose:
    verbosity = 2
    mrtrixQuiet = ''

  if citationList:
    printMessage('')
    citation_warning = 'Note that this script makes use of commands / algorithms that have relevant articles for citation'
    if externalCitations:
      citation_warning += '; INCLUDING FROM EXTERNAL SOFTWARE PACKAGES'
    citation_warning += '. Please consult the help page (-help option) for more information.'
    printMessage(citation_warning)
    printMessage('')

  if args.cont:
    tempDir = os.path.abspath(args.cont[0])
    lastFile = args.cont[1]
コード例 #32
0
template_dir = os.path.join(lib.app.args.output_dir, 'template')
if not os.path.exists(template_dir):
    os.mkdir(template_dir)

# create a temporary directory for intermediate files
lib.app.makeTempDir()

# read in group subset if supplied
subset = []
if lib.app.args.group_subset:
    subset = lib.app.args.group_subset[0].split(',')

# running participant level 1 (coversion, mask, and bias correction )
if lib.app.args.analysis_level == 'participant1':

    printMessage('performing intial conversion and bias correction')
    for subject_label in subjects_to_analyze:
        label = 'sub-' + subject_label
        printMessage('running pre-processing for ' + label)

        # Read DWI in BIDS derivatives folder
        all_dwi_images = glob(
            os.path.join(lib.app.args.bids_dir, label, '*dwi', '*_dwi.nii*'))

        # Create output subject directory
        subject_dir = os.path.join(all_subjects_dir, subject_label)
        if not os.path.exists(subject_dir):
            os.mkdir(subject_dir)

        # Check existence output files from this analysis level
        dwi_preproc_file = os.path.join(subject_dir, 'dwi_preproc.mif')
コード例 #33
0
ファイル: msmt_5tt.py プロジェクト: MarcRamos/mrtrix3
def execute():
    import math, os, shutil
    import lib.app
    from lib.getHeaderInfo import getHeaderInfo
    from lib.getImageStat import getImageStat
    from lib.getUserPath import getUserPath
    from lib.printMessage import printMessage
    from lib.runCommand import runCommand
    from lib.warnMessage import warnMessage
    from lib.errorMessage import errorMessage

    # Ideally want to use the oversampling-based regridding of the 5TT image from the SIFT model, not mrtransform
    # May need to commit 5ttregrid...

    # Verify input 5tt image
    sizes = [int(x) for x in getHeaderInfo('5tt.mif', 'size').split()]
    datatype = getHeaderInfo('5tt.mif', 'datatype')
    if not len(sizes) == 4 or not sizes[3] == 5 or not datatype.startswith(
            'Float'):
        errorMessage('Imported anatomical image ' +
                     os.path.basename(lib.app.args.in_5tt) +
                     ' is not in the 5TT format')

    # Get shell information
    shells = [
        int(round(float(x)))
        for x in getHeaderInfo('dwi.mif', 'shells').split()
    ]
    if len(shells) < 3:
        warnMessage(
            'Less than three b-value shells; response functions will not be applicable in MSMT-CSD algorithm'
        )

    # Get lmax information (if provided)
    wm_lmax = []
    if lib.app.args.lmax:
        wm_lmax = [int(x.strip()) for x in lib.app.args.lmax.split(',')]
        if not len(wm_lmax) == len(shells):
            errorMessage('Number of manually-defined lmax\'s (' +
                         str(len(wm_lmax)) +
                         ') does not match number of b-value shells (' +
                         str(len(shells)) + ')')
        for l in wm_lmax:
            if l % 2:
                errorMessage('Values for lmax must be even')
            if l < 0:
                errorMessage('Values for lmax must be non-negative')

    runCommand(
        'dwi2tensor dwi.mif - -mask mask.mif | tensor2metric - -fa fa.mif -vector vector.mif'
    )
    if not os.path.exists('dirs.mif'):
        shutil.copy('vector.mif', 'dirs.mif')
    runCommand(
        'mrtransform 5tt.mif 5tt_regrid.mif -template fa.mif -interp linear')

    # Basic tissue masks
    runCommand(
        'mrconvert 5tt_regrid.mif - -coord 3 2 -axes 0,1,2 | mrcalc - ' +
        str(lib.app.args.pvf) + ' -gt mask.mif -mult wm_mask.mif')
    runCommand(
        'mrconvert 5tt_regrid.mif - -coord 3 0 -axes 0,1,2 | mrcalc - ' +
        str(lib.app.args.pvf) + ' -gt fa.mif ' + str(lib.app.args.fa) +
        ' -lt -mult mask.mif -mult gm_mask.mif')
    runCommand(
        'mrconvert 5tt_regrid.mif - -coord 3 3 -axes 0,1,2 | mrcalc - ' +
        str(lib.app.args.pvf) + ' -gt fa.mif ' + str(lib.app.args.fa) +
        ' -lt -mult mask.mif -mult csf_mask.mif')

    # Revise WM mask to only include single-fibre voxels
    printMessage(
        'Calling dwi2response recursively to select WM single-fibre voxels using \''
        + lib.app.args.wm_algo + '\' algorithm')
    recursive_cleanup_option = ''
    if not lib.app.cleanup:
        recursive_cleanup_option = ' -nocleanup'
    runCommand(
        'dwi2response -quiet -tempdir ' + lib.app.tempDir +
        recursive_cleanup_option + ' ' + lib.app.args.wm_algo +
        ' dwi.mif wm_ss_response.txt -mask wm_mask.mif -voxels wm_sf_mask.mif')

    # Check for empty masks
    wm_voxels = int(getImageStat('wm_sf_mask.mif', 'count', 'wm_sf_mask.mif'))
    gm_voxels = int(getImageStat('gm_mask.mif', 'count', 'gm_mask.mif'))
    csf_voxels = int(getImageStat('csf_mask.mif', 'count', 'csf_mask.mif'))
    empty_masks = []
    if not wm_voxels:
        empty_masks.append('WM')
    if not gm_voxels:
        empty_masks.append('GM')
    if not csf_voxels:
        empty_masks.append('CSF')
    if empty_masks:
        message = ','.join(empty_masks)
        message += ' tissue mask'
        if len(empty_masks) > 1:
            message += 's'
        message += ' empty; cannot estimate response function'
        if len(empty_masks) > 1:
            message += 's'
        errorMessage(message)

    # For each of the three tissues, generate a multi-shell response
    # Since here we're guaranteeing that GM and CSF will be isotropic in all shells, let's use mrstats rather than sh2response (seems a bit weird passing a directions file to sh2response with lmax=0...)

    wm_responses = []
    gm_responses = []
    csf_responses = []
    max_length = 0

    for index, b in enumerate(shells):
        dwi_path = 'dwi_b' + str(b) + '.mif'
        # dwiextract will yield a 4D image, even if there's only a single volume in a shell
        runCommand('dwiextract dwi.mif -shell ' + str(b) + ' ' + dwi_path)
        this_b_lmax_option = ''
        if wm_lmax:
            this_b_lmax_option = ' -lmax ' + str(wm_lmax[index])
        runCommand('amp2sh ' + dwi_path +
                   ' - | sh2response - wm_sf_mask.mif dirs.mif wm_response_b' +
                   str(b) + '.txt' + this_b_lmax_option)
        wm_response = open('wm_response_b' + str(b) + '.txt',
                           'r').read().split()
        wm_responses.append(wm_response)
        max_length = max(max_length, len(wm_response))
        mean_dwi_path = 'dwi_b' + str(b) + '_mean.mif'
        runCommand('mrmath ' + dwi_path + ' mean ' + mean_dwi_path +
                   ' -axis 3')
        gm_mean = float(getImageStat(mean_dwi_path, 'mean', 'gm_mask.mif'))
        csf_mean = float(getImageStat(mean_dwi_path, 'mean', 'csf_mask.mif'))
        gm_responses.append(str(gm_mean * math.sqrt(4.0 * math.pi)))
        csf_responses.append(str(csf_mean * math.sqrt(4.0 * math.pi)))

    with open('wm.txt', 'w') as f:
        for line in wm_responses:
            line += ['0'] * (max_length - len(line))
            f.write(' '.join(line) + '\n')
    with open('gm.txt', 'w') as f:
        for line in gm_responses:
            f.write(line + '\n')
    with open('csf.txt', 'w') as f:
        for line in csf_responses:
            f.write(line + '\n')

    shutil.copyfile('wm.txt', getUserPath(lib.app.args.out_wm, False))
    shutil.copyfile('gm.txt', getUserPath(lib.app.args.out_gm, False))
    shutil.copyfile('csf.txt', getUserPath(lib.app.args.out_csf, False))

    # Generate output 4D binary image with voxel selections; RGB as in MSMT-CSD paper
    runCommand(
        'mrcat csf_mask.mif gm_mask.mif wm_sf_mask.mif voxels.mif -axis 3')
コード例 #34
0
def runCommand(cmd, exitOnError=True):

    import lib.app, os, subprocess, sys
    from lib.errorMessage import errorMessage
    from lib.isWindows import isWindows
    from lib.printMessage import printMessage
    from lib.warnMessage import warnMessage
    import distutils
    from distutils.spawn import find_executable
    global mrtrix_bin_list
    global mrtrix_bin_path

    if not mrtrix_bin_list:
        mrtrix_bin_path = os.path.abspath(
            os.path.join(
                os.path.abspath(os.path.dirname(os.path.realpath(__file__))),
                os.pardir, os.pardir, 'release', 'bin'))
        # On Windows, strip the .exe's
        mrtrix_bin_list = [
            os.path.splitext(name)[0] for name in os.listdir(mrtrix_bin_path)
        ]

    if lib.app.lastFile:
        # Check to see if the last file produced is produced by this command;
        #   if it is, this will be the last called command that gets skipped
        if lib.app.lastFile in cmd:
            lib.app.lastFile = ''
        if lib.app.verbosity:
            sys.stdout.write('Skipping command: ' + cmd + '\n')
            sys.stdout.flush()
        return

    # Vectorise the command string, preserving anything encased within quotation marks
    # This will eventually allow the use of subprocess rather than os.system()
    # TODO Use shlex.split()?
    quotation_split = cmd.split('\"')
    if not len(quotation_split) % 2:
        errorMessage('Malformed command \"' + cmd +
                     '\": odd number of quotation marks')
    cmdsplit = []
    if len(quotation_split) == 1:
        cmdsplit = cmd.split()
    else:
        for index, item in enumerate(quotation_split):
            if index % 2:
                cmdsplit.append(item)
            else:
                cmdsplit.extend(item.split())

    # For any MRtrix commands, need to insert the nthreads and quiet calls
    new_cmdsplit = []
    is_mrtrix_binary = False
    next_is_binary = True
    for item in cmdsplit:
        if next_is_binary:
            is_mrtrix_binary = item in mrtrix_bin_list
            # Make sure we're not accidentally running an MRtrix command from a different installation to the script
            if is_mrtrix_binary:
                binary_sys = find_executable(item)
                binary_manual = os.path.join(mrtrix_bin_path, item)
                if (isWindows()):
                    binary_manual = binary_manual + '.exe'
                use_manual_binary_path = not binary_sys
                if not use_manual_binary_path:
                    # os.path.samefile() not supported on all platforms / Python versions
                    if hasattr(os.path, 'samefile'):
                        use_manual_binary_path = not os.path.samefile(
                            binary_sys, binary_manual)
                    else:
                        # Hack equivalent of samefile(); not perfect, but should be adequate for use here
                        use_manual_binary_path = not os.path.normcase(
                            os.path.normpath(binary_sys)) == os.path.normcase(
                                os.path.normpath(binary_manual))
                if use_manual_binary_path:
                    item = binary_manual
            next_is_binary = False
        if item == '|':
            if is_mrtrix_binary:
                if lib.app.mrtrixNThreads:
                    new_cmdsplit.extend(lib.app.mrtrixNThreads.strip().split())
                if lib.app.mrtrixQuiet:
                    new_cmdsplit.append(lib.app.mrtrixQuiet.strip())
            next_is_binary = True
        new_cmdsplit.append(item)
    if is_mrtrix_binary:
        if lib.app.mrtrixNThreads:
            new_cmdsplit.extend(lib.app.mrtrixNThreads.strip().split())
        if lib.app.mrtrixQuiet:
            new_cmdsplit.append(lib.app.mrtrixQuiet.strip())
    cmdsplit = new_cmdsplit

    # If the piping symbol appears anywhere, we need to split this into multiple commands and execute them separately
    # If no piping symbols, the entire command should just appear as a single row in cmdstack
    cmdstack = []
    prev = 0
    for index, item in enumerate(cmdsplit):
        if item == '|':
            cmdstack.append(cmdsplit[prev:index])
            prev = index + 1
    cmdstack.append(cmdsplit[prev:])

    if lib.app.verbosity:
        sys.stdout.write(lib.app.colourConsole + 'Command:' +
                         lib.app.colourClear + ' ' + cmd + '\n')
        sys.stdout.flush()

    error = False
    error_text = ''
    # TODO If script is running in verbose mode, ideally want to duplicate stderr output in the terminal
    if len(cmdstack) == 1:
        process = subprocess.Popen(cmdstack[0],
                                   stdin=None,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
        (stdoutdata, stderrdata) = process.communicate()
        if process.returncode:
            error = True
            error_text = stdoutdata.decode('utf-8') + stderrdata.decode(
                'utf-8')
    else:
        processes = []
        for index, command in enumerate(cmdstack):
            if index > 0:
                proc_in = processes[index - 1].stdout
            else:
                proc_in = None
            process = subprocess.Popen(command,
                                       stdin=proc_in,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
            processes.append(process)

        # Wait for all commands to complete
        for index, process in enumerate(processes):
            if index < len(cmdstack) - 1:
                # Only capture the output if the command failed; otherwise, let it pipe to the next command
                process.wait()
                if process.returncode:
                    error = True
                    (stdoutdata, stderrdata) = process.communicate()
                    error_text = error_text + stdoutdata.decode(
                        'utf-8') + stderrdata.decode('utf-8')
            else:
                (stdoutdata, stderrdata) = process.communicate()
                if process.returncode:
                    error = True
                    error_text = error_text + stdoutdata.decode(
                        'utf-8') + stderrdata.decode('utf-8')

    if (error):
        lib.app.cleanup = False
        if exitOnError:
            printMessage('')
            sys.stderr.write(
                os.path.basename(sys.argv[0]) + ': ' + lib.app.colourError +
                '[ERROR] Command failed: ' + cmd + lib.app.colourClear + '\n')
            sys.stderr.write(
                os.path.basename(sys.argv[0]) + ': ' + lib.app.colourPrint +
                'Output of failed command:' + lib.app.colourClear + '\n')
            sys.stderr.write(error_text)
            if lib.app.tempDir:
                with open(os.path.join(lib.app.tempDir, 'error.txt'),
                          'w') as outfile:
                    outfile.write(cmd + '\n\n' + error_text + '\n')
            lib.app.complete()
            exit(1)
        else:
            warnMessage('Command failed: ' + cmd)

    # Only now do we append to the script log, since the command has completed successfully
    # Note: Writing the command as it was formed as the input to runCommand():
    #   other flags may potentially change if this file is eventually used to resume the script
    if lib.app.tempDir:
        with open(os.path.join(lib.app.tempDir, 'log.txt'), 'a') as outfile:
            outfile.write(cmd + '\n')
コード例 #35
0
ファイル: tax.py プロジェクト: boegel/mrtrix3
def execute():
  import math, os, shutil
  import lib.app
  from lib.getImageStat import getImageStat
  from lib.printMessage import printMessage
  from lib.runCommand   import runCommand
  
  lmax_option = ''
  if lib.app.args.lmax:
    lmax_option = ' -lmax ' + lib.app.args.lmax
    
  runCommand('amp2sh dwi.mif dwiSH.mif' + lmax_option)
  convergence_change = 0.01 * lib.app.args.convergence

  for iteration in range(0, lib.app.args.max_iters):
    prefix = 'iter' + str(iteration) + '_'

    # How to initialise response function?
    # old dwi2response command used mean & standard deviation of DWI data; however
    #   this may force the output FODs to lmax=2 at the first iteration
    # Chantal used a tensor with low FA, but it'd be preferable to get the scaling right
    # Other option is to do as before, but get the ratio between l=0 and l=2, and
    #   generate l=4,6,... using that amplitude ratio
    if iteration == 0:
      RF_in_path = 'init_RF.txt'
      mask_in_path = 'mask.mif'
      runCommand('dwiextract dwi.mif shell.mif')
      # TODO This can be changed once #71 is implemented (mrstats statistics across volumes)
      volume_means = [float(x) for x in getImageStat('shell.mif', 'mean', 'mask.mif').split()]
      mean = sum(volume_means) / float(len(volume_means))
      volume_stds = [float(x) for x in getImageStat('shell.mif', 'std', 'mask.mif').split()]
      std = sum(volume_stds) / float(len(volume_stds))
      # Scale these to reflect the fact that we're moving to the SH basis
      mean *= math.sqrt(4.0 * math.pi)
      std  *= math.sqrt(4.0 * math.pi)
      # Now produce the initial response function
      # Let's only do it to lmax 4
      init_RF = [ str(mean), str(-0.5*std), str(0.25*std*std/mean) ]
      with open('init_RF.txt', 'w') as f:
        f.write(' '.join(init_RF))
    else:
      RF_in_path = 'iter' + str(iteration-1) + '_RF.txt'
      mask_in_path = 'iter' + str(iteration-1) + '_SF.mif'
  
    # Run CSD
    runCommand('dwi2fod dwi.mif ' + RF_in_path + ' ' + prefix + 'FOD.mif -mask ' + mask_in_path)
    # Get amplitudes of two largest peaks, and directions of largest
    runCommand('fod2fixel ' + prefix + 'FOD.mif -peak ' + prefix + 'peaks.msf -mask ' + mask_in_path + ' -fmls_no_thresholds')
    runCommand('fixel2voxel ' + prefix + 'peaks.msf split_value ' + prefix + 'amps.mif')
    runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix + 'first_peaks.mif -coord 3 0 -axes 0,1,2')
    runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix + 'second_peaks.mif -coord 3 1 -axes 0,1,2')
    runCommand('fixel2voxel ' + prefix + 'peaks.msf split_dir ' + prefix + 'all_dirs.mif')
    runCommand('mrconvert ' + prefix + 'all_dirs.mif ' + prefix + 'first_dir.mif -coord 3 0:2')
    # Revise single-fibre voxel selection based on ratio of tallest to second-tallest peak
    runCommand('mrcalc ' + prefix + 'second_peaks.mif ' + prefix + 'first_peaks.mif -div ' + prefix + 'peak_ratio.mif')
    runCommand('mrcalc ' + prefix + 'peak_ratio.mif ' + str(lib.app.args.peak_ratio) + ' -lt ' + mask_in_path + ' -mult ' + prefix + 'SF.mif')
    # Make sure image isn't empty
    SF_voxel_count = int(getImageStat(prefix + 'SF.mif', 'count', prefix + 'SF.mif'))
    if not SF_voxel_count:
      errorMessage('Aborting: All voxels have been excluded from single-fibre selection')
    # Generate a new response function
    runCommand('sh2response dwiSH.mif ' + prefix + 'SF.mif ' + prefix + 'first_dir.mif ' + prefix + 'RF.txt' + lmax_option)
    
    # Detect convergence
    # Look for a change > some percentage - don't bother looking at the masks
    if iteration > 0:
      old_RF_file = open(RF_in_path, 'r')
      old_RF = [ float(x) for x in old_RF_file.read().split() ]
      new_RF_file = open(prefix + 'RF.txt', 'r')
      new_RF = [ float(x) for x in new_RF_file.read().split() ]
      reiterate = False
      for index in range(0, len(old_RF)):
        mean = 0.5 * (old_RF[index] + new_RF[index])
        diff = math.fabs(0.5 * (old_RF[index] - new_RF[index]))
        ratio = diff / mean
        if ratio > convergence_change:
          reiterate = True
      if not reiterate:
        printMessage('Exiting at iteration ' + str(iteration) + ' with ' + str(SF_voxel_count) + ' SF voxels due to unchanged response function coefficients')
        shutil.copyfile(prefix + 'RF.txt', 'response.txt')
        shutil.copyfile(prefix + 'SF.mif', 'voxels.mif')
        break
        
  # Go to the next iteration

  # If we've terminated due to hitting the iteration limiter, we still need to copy the output file(s) to the correct location
  if not os.path.exists('response.txt'):
    printMessage('Exiting after maximum ' + str(lib.app.args.max_iters-1) + ' iterations with ' + str(SF_voxel_count) + ' SF voxels')
    shutil.copyfile('iter' + str(lib.app.args.max_iters-1) + '_RF.txt', 'response.txt')
    shutil.copyfile('iter' + str(lib.app.args.max_iters-1) + '_SF.mif', 'voxels.mif')

  shutil.copyfile('response.txt', os.path.join(lib.app.workingDir, lib.app.args.output))
コード例 #36
0
ファイル: tournier.py プロジェクト: echohenry2006/mrtrix3
def execute():
    import os, shutil
    import lib.app
    from lib.getImageStat import getImageStat
    from lib.printMessage import printMessage
    from lib.runCommand import runCommand

    lmax_option = ''
    if lib.app.args.lmax:
        lmax_option = ' -lmax ' + lib.app.args.lmax

    if lib.app.args.max_iters < 2:
        errorMessage('Number of iterations must be at least 2')

    runCommand('amp2sh dwi.mif dwiSH.mif' + lmax_option)

    for iteration in range(0, lib.app.args.max_iters):
        prefix = 'iter' + str(iteration) + '_'

        if iteration == 0:
            RF_in_path = 'init_RF.txt'
            mask_in_path = 'mask.mif'
            init_RF = '1 -1 1'
            with open('init_RF.txt', 'w') as f:
                f.write(init_RF)
            iter_lmax_option = ' -lmax 4'
        else:
            RF_in_path = 'iter' + str(iteration - 1) + '_RF.txt'
            mask_in_path = 'iter' + str(iteration - 1) + '_SF_dilated.mif'
            iter_lmax_option = lmax_option

        # Run CSD
        runCommand('dwi2fod dwi.mif ' + RF_in_path + ' ' + prefix +
                   'FOD.mif -mask ' + mask_in_path + iter_lmax_option)
        # Get amplitudes of two largest peaks, and direction of largest
        # TODO Speed-test fod2fixel against sh2peaks
        # TODO Add maximum number of fixels per voxel option to fod2fixel?
        runCommand('fod2fixel ' + prefix + 'FOD.mif -peak ' + prefix +
                   'peaks.msf -mask ' + mask_in_path + ' -fmls_no_thresholds')
        runCommand('fixel2voxel ' + prefix + 'peaks.msf split_value ' +
                   prefix + 'amps.mif')
        runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix +
                   'first_peaks.mif -coord 3 0 -axes 0,1,2')
        runCommand('mrconvert ' + prefix + 'amps.mif ' + prefix +
                   'second_peaks.mif -coord 3 1 -axes 0,1,2')
        runCommand('fixel2voxel ' + prefix + 'peaks.msf split_dir ' + prefix +
                   'all_dirs.mif')
        runCommand('mrconvert ' + prefix + 'all_dirs.mif ' + prefix +
                   'first_dir.mif -coord 3 0:2')
        # Calculate the 'cost function' Donald derived for selecting single-fibre voxels
        # https://github.com/MRtrix3/mrtrix3/pull/426
        #  sqrt(|peak1|) * (1 - |peak2| / |peak1|)^2
        runCommand('mrcalc ' + prefix + 'first_peaks.mif -sqrt 1 ' + prefix +
                   'second_peaks.mif ' + prefix +
                   'first_peaks.mif -div -sub 2 -pow -mult ' + prefix +
                   'CF.mif')
        # Select the top-ranked voxels
        runCommand('mrthreshold ' + prefix + 'CF.mif -top ' +
                   str(lib.app.args.sf_voxels) + ' ' + prefix + 'SF.mif')
        # Generate a new response function based on this selection
        runCommand('sh2response dwiSH.mif ' + prefix + 'SF.mif ' + prefix +
                   'first_dir.mif ' + prefix + 'RF.txt' + iter_lmax_option)
        # Should we terminate?
        if iteration > 0:
            runCommand('mrcalc ' + prefix + 'SF.mif iter' +
                       str(iteration - 1) + '_SF.mif -sub ' + prefix +
                       'SF_diff.mif')
            max_diff = getImageStat(prefix + 'SF_diff.mif', 'max')
            if int(max_diff) == 0:
                printMessage(
                    'Convergence of SF voxel selection detected at iteration '
                    + str(iteration))
                shutil.copyfile(prefix + 'RF.txt', 'response.txt')
                shutil.copyfile(prefix + 'SF.mif', 'voxels.mif')
                break

        # Select a greater number of top single-fibre voxels, and dilate;
        #   these are the voxels that will be re-tested in the next iteration
        runCommand('mrthreshold ' + prefix + 'CF.mif -top ' +
                   str(lib.app.args.iter_voxels) + ' - | maskfilter ' +
                   prefix + 'SF.mif dilate ' + prefix +
                   'SF_dilated.mif -npass ' + str(lib.app.args.dilate))

    # Commence the next iteration

    # If terminating due to running out of iterations, still need to put the results in the appropriate location
    if not os.path.exists('response.txt'):
        printMessage('Exiting after maximum ' +
                     str(lib.app.args.max_iters - 1) + ' iterations')
        shutil.copyfile('iter' + str(lib.app.args.max_iters - 1) + '_RF.txt',
                        'response.txt')
        shutil.copyfile('iter' + str(lib.app.args.max_iters - 1) + '_SF.mif',
                        'voxels.mif')

    shutil.copyfile('response.txt',
                    os.path.join(lib.app.workingDir, lib.app.args.output))
コード例 #37
0
def execute():
    import math, os, shutil
    import lib.app
    from lib.getHeaderInfo import getHeaderInfo
    from lib.getImageStat import getImageStat
    from lib.getUserPath import getUserPath
    from lib.printMessage import printMessage
    from lib.runCommand import runCommand
    from lib.warnMessage import warnMessage
    from lib.errorMessage import errorMessage

    # Get b-values and number of volumes per b-value.
    bvalues = [
        int(round(float(x)))
        for x in getHeaderInfo('dwi.mif', 'shells').split()
    ]
    bvolumes = [
        int(x) for x in getHeaderInfo('dwi.mif', 'shellcounts').split()
    ]
    printMessage(
        str(len(bvalues)) + ' unique b-value(s) detected: ' +
        ','.join(map(str, bvalues)) + ' with ' + ','.join(map(str, bvolumes)) +
        ' volumes.')
    if len(bvalues) < 2:
        errorMessage('Need at least 2 unique b-values (including b=0).')

    # Get lmax information (if provided).
    sfwm_lmax = []
    if lib.app.args.lmax:
        sfwm_lmax = [int(x.strip()) for x in lib.app.args.lmax.split(',')]
        if not len(sfwm_lmax) == len(bvalues):
            errorMessage('Number of lmax\'s (' + str(len(sfwm_lmax)) +
                         ', as supplied to the -lmax option: ' +
                         ','.join(map(str, sfwm_lmax)) +
                         ') does not match number of unique b-values.')
        for l in sfwm_lmax:
            if l % 2:
                errorMessage(
                    'Values supplied to the -lmax option must be even.')
            if l < 0:
                errorMessage(
                    'Values supplied to the -lmax option must be non-negative.'
                )

    # Erode (brain) mask.
    if lib.app.args.erode > 0:
        runCommand('maskfilter mask.mif erode eroded_mask.mif -npass ' +
                   str(lib.app.args.erode))
    else:
        runCommand('mrconvert mask.mif eroded_mask.mif -datatype bit')

    # Get volumes, compute mean signal and SDM per b-value; compute overall SDM; get rid of erroneous values.
    totvolumes = 0
    fullsdmcmd = 'mrcalc'
    errcmd = 'mrcalc'
    zeropath = 'mean_b' + str(bvalues[0]) + '.mif'
    for i, b in enumerate(bvalues):
        dwipath = 'dwi_b' + str(b) + '.mif'
        runCommand('dwiextract dwi.mif -shell ' + str(b) + ' ' + dwipath)
        meanpath = 'mean_b' + str(b) + '.mif'
        runCommand('mrmath ' + dwipath + ' mean ' + meanpath + ' -axis 3')
        errpath = 'err_b' + str(b) + '.mif'
        runCommand('mrcalc ' + meanpath + ' -finite ' + meanpath +
                   ' 0 -if 0 -le ' + errpath + ' -datatype bit')
        errcmd += ' ' + errpath
        if i > 0:
            errcmd += ' -add'
            sdmpath = 'sdm_b' + str(b) + '.mif'
            runCommand('mrcalc ' + zeropath + ' ' + meanpath +
                       ' -divide -log ' + sdmpath)
            totvolumes += bvolumes[i]
            fullsdmcmd += ' ' + sdmpath + ' ' + str(bvolumes[i]) + ' -mult'
            if i > 1:
                fullsdmcmd += ' -add'
    fullsdmcmd += ' ' + str(totvolumes) + ' -divide full_sdm.mif'
    runCommand(fullsdmcmd)
    runCommand(
        'mrcalc full_sdm.mif -finite full_sdm.mif 0 -if 0 -le err_sdm.mif -datatype bit'
    )
    errcmd += ' err_sdm.mif -add 0 eroded_mask.mif -if safe_mask.mif -datatype bit'
    runCommand(errcmd)
    runCommand('mrcalc safe_mask.mif full_sdm.mif 0 -if 10 -min safe_sdm.mif')

    # Compute FA and principal eigenvectors; crude WM versus GM-CSF separation based on FA.
    runCommand(
        'dwi2tensor dwi.mif - -mask safe_mask.mif | tensor2metric - -fa safe_fa.mif -vector safe_vecs.mif -modulate none -mask safe_mask.mif'
    )
    runCommand('mrcalc safe_mask.mif safe_fa.mif 0 -if ' +
               str(lib.app.args.fa) + ' -gt crude_wm.mif -datatype bit')
    runCommand(
        'mrcalc crude_wm.mif 0 safe_mask.mif -if _crudenonwm.mif -datatype bit'
    )

    # Crude GM versus CSF separation based on SDM.
    crudenonwmmedian = getImageStat('safe_sdm.mif', 'median',
                                    '_crudenonwm.mif')
    runCommand(
        'mrcalc _crudenonwm.mif safe_sdm.mif ' + str(crudenonwmmedian) +
        ' -subtract 0 -if - | mrthreshold - - -mask _crudenonwm.mif | mrcalc _crudenonwm.mif - 0 -if crude_csf.mif -datatype bit'
    )
    runCommand(
        'mrcalc crude_csf.mif 0 _crudenonwm.mif -if crude_gm.mif -datatype bit'
    )

    # Refine WM: remove high SDM outliers.
    crudewmmedian = getImageStat('safe_sdm.mif', 'median', 'crude_wm.mif')
    runCommand('mrcalc crude_wm.mif safe_sdm.mif 0 -if ' + str(crudewmmedian) +
               ' -gt _crudewmhigh.mif -datatype bit')
    runCommand(
        'mrcalc _crudewmhigh.mif 0 crude_wm.mif -if _crudewmlow.mif -datatype bit'
    )
    crudewmQ1 = float(getImageStat('safe_sdm.mif', 'median',
                                   '_crudewmlow.mif'))
    crudewmQ3 = float(
        getImageStat('safe_sdm.mif', 'median', '_crudewmhigh.mif'))
    crudewmoutlthresh = crudewmQ3 + (crudewmQ3 - crudewmQ1)
    runCommand('mrcalc crude_wm.mif safe_sdm.mif 0 -if ' +
               str(crudewmoutlthresh) +
               ' -gt _crudewmoutliers.mif -datatype bit')
    runCommand(
        'mrcalc _crudewmoutliers.mif 0 crude_wm.mif -if refined_wm.mif -datatype bit'
    )

    # Refine GM: separate safer GM from partial volumed voxels.
    crudegmmedian = getImageStat('safe_sdm.mif', 'median', 'crude_gm.mif')
    runCommand('mrcalc crude_gm.mif safe_sdm.mif 0 -if ' + str(crudegmmedian) +
               ' -gt _crudegmhigh.mif -datatype bit')
    runCommand(
        'mrcalc _crudegmhigh.mif 0 crude_gm.mif -if _crudegmlow.mif -datatype bit'
    )
    runCommand(
        'mrcalc _crudegmhigh.mif safe_sdm.mif ' + str(crudegmmedian) +
        ' -subtract 0 -if - | mrthreshold - - -mask _crudegmhigh.mif -invert | mrcalc _crudegmhigh.mif - 0 -if _crudegmhighselect.mif -datatype bit'
    )
    runCommand(
        'mrcalc _crudegmlow.mif safe_sdm.mif ' + str(crudegmmedian) +
        ' -subtract -neg 0 -if - | mrthreshold - - -mask _crudegmlow.mif -invert | mrcalc _crudegmlow.mif - 0 -if _crudegmlowselect.mif -datatype bit'
    )
    runCommand(
        'mrcalc _crudegmhighselect.mif 1 _crudegmlowselect.mif -if refined_gm.mif -datatype bit'
    )

    # Refine CSF: recover lost CSF from crude WM SDM outliers, separate safer CSF from partial volumed voxels.
    crudecsfmin = getImageStat('safe_sdm.mif', 'min', 'crude_csf.mif')
    runCommand('mrcalc _crudewmoutliers.mif safe_sdm.mif 0 -if ' +
               str(crudecsfmin) +
               ' -gt 1 crude_csf.mif -if _crudecsfextra.mif -datatype bit')
    runCommand(
        'mrcalc _crudecsfextra.mif safe_sdm.mif ' + str(crudecsfmin) +
        ' -subtract 0 -if - | mrthreshold - - -mask _crudecsfextra.mif | mrcalc _crudecsfextra.mif - 0 -if refined_csf.mif -datatype bit'
    )

    # Get final voxels for single-fibre WM response function estimation from WM using 'tournier' algorithm.
    refwmcount = float(
        getImageStat('refined_wm.mif', 'count', 'refined_wm.mif'))
    voxsfwmcount = int(round(refwmcount * lib.app.args.sfwm / 100.0))
    printMessage('Running \'tournier\' algorithm to select ' +
                 str(voxsfwmcount) + ' single-fibre WM voxels.')
    cleanopt = ''
    if not lib.app.cleanup:
        cleanopt = ' -nocleanup'
    runCommand(
        'dwi2response tournier dwi.mif _respsfwmss.txt -sf_voxels ' +
        str(voxsfwmcount) + ' -iter_voxels ' + str(voxsfwmcount * 10) +
        ' -mask refined_wm.mif -voxels voxels_sfwm.mif -quiet -tempdir ' +
        lib.app.tempDir + cleanopt)

    # Get final voxels for GM response function estimation from GM.
    refgmmedian = getImageStat('safe_sdm.mif', 'median', 'refined_gm.mif')
    runCommand('mrcalc refined_gm.mif safe_sdm.mif 0 -if ' + str(refgmmedian) +
               ' -gt _refinedgmhigh.mif -datatype bit')
    runCommand(
        'mrcalc _refinedgmhigh.mif 0 refined_gm.mif -if _refinedgmlow.mif -datatype bit'
    )
    refgmhighcount = float(
        getImageStat('_refinedgmhigh.mif', 'count', '_refinedgmhigh.mif'))
    refgmlowcount = float(
        getImageStat('_refinedgmlow.mif', 'count', '_refinedgmlow.mif'))
    voxgmhighcount = int(round(refgmhighcount * lib.app.args.gm / 100.0))
    voxgmlowcount = int(round(refgmlowcount * lib.app.args.gm / 100.0))
    runCommand(
        'mrcalc _refinedgmhigh.mif safe_sdm.mif 0 -if - | mrthreshold - - -bottom '
        + str(voxgmhighcount) +
        ' -ignorezero | mrcalc _refinedgmhigh.mif - 0 -if _refinedgmhighselect.mif -datatype bit'
    )
    runCommand(
        'mrcalc _refinedgmlow.mif safe_sdm.mif 0 -if - | mrthreshold - - -top '
        + str(voxgmlowcount) +
        ' -ignorezero | mrcalc _refinedgmlow.mif - 0 -if _refinedgmlowselect.mif -datatype bit'
    )
    runCommand(
        'mrcalc _refinedgmhighselect.mif 1 _refinedgmlowselect.mif -if voxels_gm.mif -datatype bit'
    )

    # Get final voxels for CSF response function estimation from CSF.
    refcsfcount = float(
        getImageStat('refined_csf.mif', 'count', 'refined_csf.mif'))
    voxcsfcount = int(round(refcsfcount * lib.app.args.csf / 100.0))
    runCommand(
        'mrcalc refined_csf.mif safe_sdm.mif 0 -if - | mrthreshold - - -top ' +
        str(voxcsfcount) +
        ' -ignorezero | mrcalc refined_csf.mif - 0 -if voxels_csf.mif -datatype bit'
    )

    # Show summary of voxels counts.
    textarrow = ' --> '
    printMessage('Summary of voxel counts:')
    printMessage(
        'Mask: ' + str(int(getImageStat('mask.mif', 'count', 'mask.mif'))) +
        textarrow +
        str(int(getImageStat('eroded_mask.mif', 'count', 'eroded_mask.mif'))) +
        textarrow +
        str(int(getImageStat('safe_mask.mif', 'count', 'safe_mask.mif'))))
    printMessage(
        'WM: ' +
        str(int(getImageStat('crude_wm.mif', 'count', 'crude_wm.mif'))) +
        textarrow +
        str(int(getImageStat('refined_wm.mif', 'count', 'refined_wm.mif'))) +
        textarrow +
        str(int(getImageStat('voxels_sfwm.mif', 'count', 'voxels_sfwm.mif'))) +
        ' (SF)')
    printMessage(
        'GM: ' +
        str(int(getImageStat('crude_gm.mif', 'count', 'crude_gm.mif'))) +
        textarrow +
        str(int(getImageStat('refined_gm.mif', 'count', 'refined_gm.mif'))) +
        textarrow +
        str(int(getImageStat('voxels_gm.mif', 'count', 'voxels_gm.mif'))))
    printMessage(
        'CSF: ' +
        str(int(getImageStat('crude_csf.mif', 'count', 'crude_csf.mif'))) +
        textarrow +
        str(int(getImageStat('refined_csf.mif', 'count', 'refined_csf.mif'))) +
        textarrow +
        str(int(getImageStat('voxels_csf.mif', 'count', 'voxels_csf.mif'))))

    # Generate single-fibre WM, GM and CSF responses
    sfwm_responses = []
    gm_responses = []
    csf_responses = []
    max_length = 0
    for index, b in enumerate(bvalues):
        dwipath = 'dwi_b' + str(b) + '.mif'
        this_b_lmax_option = ''
        if sfwm_lmax:
            this_b_lmax_option = ' -lmax ' + str(sfwm_lmax[index])
        runCommand(
            'amp2sh ' + dwipath +
            ' - | sh2response - voxels_sfwm.mif safe_vecs.mif _respsfwmb' +
            str(b) + '.txt' + this_b_lmax_option)
        sfwm_response = open('_respsfwmb' + str(b) + '.txt',
                             'r').read().split()
        sfwm_responses.append(sfwm_response)
        max_length = max(max_length, len(sfwm_response))
        meanpath = 'mean_b' + str(b) + '.mif'
        gm_mean = float(getImageStat(meanpath, 'mean', 'voxels_gm.mif'))
        csf_mean = float(getImageStat(meanpath, 'mean', 'voxels_csf.mif'))
        gm_responses.append(str(gm_mean * math.sqrt(4.0 * math.pi)))
        csf_responses.append(str(csf_mean * math.sqrt(4.0 * math.pi)))
    with open('response_sfwm.txt', 'w') as f:
        for line in sfwm_responses:
            line += ['0'] * (max_length - len(line))
            f.write(' '.join(line) + '\n')
    with open('response_gm.txt', 'w') as f:
        for line in gm_responses:
            f.write(line + '\n')
    with open('response_csf.txt', 'w') as f:
        for line in csf_responses:
            f.write(line + '\n')
    shutil.copyfile('response_sfwm.txt',
                    getUserPath(lib.app.args.out_sfwm, False))
    shutil.copyfile('response_gm.txt', getUserPath(lib.app.args.out_gm, False))
    shutil.copyfile('response_csf.txt', getUserPath(lib.app.args.out_csf,
                                                    False))

    # Generate 4D binary images with voxel selection at major stages in algorithm (RGB as in MSMT-CSD paper).
    runCommand(
        'mrcat crude_csf.mif crude_gm.mif crude_wm.mif crude.mif -axis 3')
    runCommand(
        'mrcat refined_csf.mif refined_gm.mif refined_wm.mif refined.mif -axis 3'
    )
    runCommand(
        'mrcat voxels_csf.mif voxels_gm.mif voxels_sfwm.mif voxels.mif -axis 3'
    )