Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
executable file 127 lines (123 sloc) 6.26 KB
#! /usr/bin/env python
####################################################################################################
# Script to reorient volumes into anatomical orientation and to create surface time-series.
# This script is made for use with a registration file (in FreeSurfer's tkreg format) and
# a series of unwarped time-series volumes: i.e., the output of Serra's preprocessing
# script.
# Author: Noah C. Benson <nben@nyu.edu>
import argparse, sys, os, six
import neuropythy as ny, numpy as np, nibabel as nib
if six.PY3:
from functools import reduce
def main(args):
# Parse the arguments...
parser = argparse.ArgumentParser()
parser.add_argument('reg', metavar='registration_file', nargs=1,
help=('The distort2anat_tkreg.dat or similar file: the registration'
' file, in FreeSurfer\'s tkreg format, to apply to the EPIs.'))
parser.add_argument('epis', metavar='EPI', type=str, nargs='+',
help='The EPI files to be converted to anatomical orientation')
parser.add_argument('-t', '--tag', required=False, default='-', dest='tag', nargs=1,
help=('A tag to append to the output filenames; if given as - or'
' omitted, overwrites original files.'))
parser.add_argument('-s', '--surf', required=False, default=False,
dest='surface', action='store_true',
help=('If provided, instructs the script to also produce files of the '
'time-series resampled on the cortical surface.'))
parser.add_argument('-o', '--out', required=False, default='.', dest='outdir',
help=('The output directory to which the files should be written; by'
' default this is the current directory (.); note that if this'
' directory also contains the EPI files and there is no tag given,'
' then the EPIs will be overwritten.'))
parser.add_argument('-m', '--method', required=False, default='linear', dest='method',
help=('The method to use for volume-to-surface interpolation; this may'
' be nearest or linear; the default is linear.'))
parser.add_argument('-l', '--layer', required=False, default='midgray', dest='layer',
help=('Specifies the cortical layer to user in interpolation from volume'
' to surface. By default, uses midgray. May be set to a value'
' between 0 (white) and 1 (pial) to specify an intermediate surface'
' or may be simply white, pial, or midgray.'))
parser.add_argument('-d', '--subjects-dir', required=False, default=None, dest='sdir',
help=('Specifies the subjects directory to use; by default uses the'
' environment variable SUBJECTS_DIR.'))
parser.add_argument('-v', '--verbose', required=False, default=False, action='store_true',
dest='verbose', help='Print verbose output')
if args[0].startswith('python'): args = args[2:]
else: args = args[1:]
args = parser.parse_args(args)
# Check some of the arguments...
epis = args.epis
if len(epis) < 1: raise RuntimeError('No EPIs given')
tag = args.tag[0]
if tag == '-': tag = ''
dosurf = args.surface
outdir = args.outdir
if not os.path.isdir(outdir):
raise RuntimeError('Directory %s does not exist' % outdir)
if args.verbose:
def note(*args):
six.print_(*args, flush=True)
return True
else:
def note(*args):
return False
try: args.layer = float(args.layer)
except: pass
# Read in the registration file
args.reg = args.reg[0]
if not os.path.isfile(args.reg):
raise RuntimeError('Given registration file not found: %s' % args.reg)
with open(args.reg, 'r') as f:
lines = []
while True:
s = f.readline()
if s is None or s == '': break
lines.append(s)
# This tells us some info...
sub = lines[0].strip()
if args.sdir is not None:
ny.add_subject_path(args.sdir)
try: sub = ny.freesurfer_subject(sub)
except: raise ValueError('No subject %s; you may need to set your SUBJECTS_DIR' % sub)
affine = np.asarray([[float(ss) for ss in s.split()] for s in lines[4:8]])
affinv = np.linalg.inv(affine)
displm = sub.lh.affine
# loop over the given EPIs
for epi in epis:
note('Processing EPI %s...' % epi)
# import the epi file..
img = ny.load(epi, to='image')
# edit the header...
note(' - Correcting volume orientation...')
new_affine = np.dot(displm, np.dot(affinv, ny.freesurfer.tkr_vox2ras(img)))
newimg = nib.Nifti1Image(img.dataobj, new_affine, img.header)
(epi_dir,epi_flnm) = os.path.split(epi)
if epi_flnm[:-4] in ['.mgz', '.mgh', '.nii']:
pre = epi_flnm[:-4]
suf = epi_flnm[-4:]
else:
pre = epi_flnm[:-7]
suf = epi_flnm[-7:]
srf_flnm = pre + tag + '.mgz'
epi_flnm = pre + tag + suf
newimg.to_filename(os.path.join(args.outdir, epi_flnm))
# okay, now project to the surface
if args.surface:
note(' - Projecting to surface...')
(ldat, rdat) = sub.image_to_cortex(newimg, surface=args.layer,
method=args.method, dtype=np.float32)
# we need to fix the dimensions...
for (d,h) in zip([ldat,rdat], ['lh','rh']):
if d.shape[-1] == 1:
# then this should properly be a 3d MGH image, not a 4d one.
im = nib.freesurfer.mghformat.MGHImage(
np.transpose(reduce(np.expand_dims, [-1], d), (0,2,1)),
np.eye(4))
else:
im = nib.freesurfer.mghformat.MGHImage(
np.transpose(reduce(np.expand_dims, [-1,-1], d), (0,2,3,1)),
np.eye(4))
im.to_filename(os.path.join(args.outdir, h + '.' + srf_flnm))
# That's it!
return 0
main(sys.argv)