Skip to content

Commit

Permalink
Merge pull request gallantlab#309 from gallantlab/fsalign_manual
Browse files Browse the repository at this point in the history
fsalign manual
  • Loading branch information
ctseng12 authored Jan 16, 2019
2 parents 12d0565 + d8f346b commit c69da36
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
96 changes: 96 additions & 0 deletions cortex/align.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,98 @@ def view_callback(aligner):

return m

def fs_manual(subject, xfmname, output_name="register.lta", wm_color="blue", pial_color="red", noclean=False):
"""Open Freesurfer FreeView GUI for manually aligning/adjusting a functional
volume to the cortical surface for `subject`. This creates a new transform
called `xfmname`. The name of a nibabel-readable file (e.g. NIfTI) should be
supplied as `reference`. This image will be copied into the database.
IMPORTANT: This function assumes that the resulting .lta file is saved as:
"{default folder chosen by FreeView (should be /tmp/fsalign_xxx)}/{output_name}".
Parameters
----------
subject : str
Subject identifier.
xfmname : str
The name of the transform to be modified.
output_name : str
The name of the .lta file generated after FreeView editing.
wm_color : str | "blue"
Color of the white matter surface. Default is "blue". This can
also be adjusted in the FreeView GUI.
pial_color : str | "red"
Color of the pial surface. Default is "red". This can also be adjusted
the FreeView GUI.
noclean : boolean | False
If True, intermediate files will not be removed from /tmp/fsalign_xxx
(this is useful for debugging things), and the returned value will be
the name of the temp directory. Default False.
Returns
-------
Nothing unless noclean is true.
"""

import subprocess as sp
import tempfile
import shutil
from .xfm import Transform
from .database import db

retval = None

try:
try:
cache = tempfile.mkdtemp(prefix="fsalign_")
sub_xfm = db.get_xfm(subject, xfmname)

# if masks have been cached, quit! user must remove them by hand
from glob import glob
if len(glob(db.get_paths(subject)['masks'].format(xfmname=xfmname, type='*'))):
print('Refusing to overwrite existing transform %s because there are cached masks. Delete the masks manually if you want to modify the transform.' % xfmname)
raise ValueError('Exiting...')
except IOError:
print("Transform does not exist!")

# Load transform-relevant things
reference = sub_xfm.reference.get_filename()
xfm_dir = os.path.dirname(reference)
_ = sub_xfm.to_freesurfer(os.path.join(cache, "register.dat"), subject) # Transform in freesurfer .dat format

# Command for FreeView and run
cmd = ("freeview -v $SUBJECTS_DIR/{sub}/mri/orig.mgz "
"{ref}:reg={reg} "
"-f $SUBJECTS_DIR/{sub}/surf/lh.white:edgecolor={wmc} $SUBJECTS_DIR/{sub}/surf/rh.white:edgecolor={wmc} "
"$SUBJECTS_DIR/{sub}/surf/lh.pial:edgecolor={pialc} $SUBJECTS_DIR/{sub}/surf/rh.pial:edgecolor={pialc}")
cmd = cmd.format(sub=subject, ref=reference, reg=os.path.join(cache, "register.dat"),
wmc=wm_color, pialc=pial_color)

# Run and save transform when user is done editing
if sp.call(cmd, shell=True) != 0:
raise IOError("Problem with FreeView!")
else:
# Convert transform into .dat format
reg_dat = os.path.join(cache, os.path.splitext(output_name)[0] + ".dat")
cmd = "lta_convert --inlta {inlta} --outreg {regdat}"
cmd = cmd.format(inlta=os.path.join(cache, output_name), regdat=reg_dat)
if sp.call(cmd, shell=True) != 0:
raise IOError("Error converting lta into dat!")

# Save transform to pycortex
xfm = Transform.from_freesurfer(reg_dat, reference, subject)
db.save_xfm(subject, xfmname, xfm.xfm, xfmtype='coord', reference=reference)
print("saved xfm")

finally:
if not noclean:
shutil.rmtree(cache)
else:
retval = cache

return retval


def automatic(subject, xfmname, reference, noclean=False, bbrtype="signed", pre_flirt_args='', use_fs_bbr=False):
"""Create an automatic alignment using the FLIRT boundary-based alignment (BBR) from FSL.
Expand Down Expand Up @@ -113,6 +205,9 @@ def automatic(subject, xfmname, reference, noclean=False, bbrtype="signed", pre_
Additional arguments that are passed to the FLIRT pre-alignment step (not BBR).
use_fs_bbr : bool, optional
If True will use freesurfer bbregister instead of FSL BBR.
save_dat : bool, optional
If True, will save the register.dat file from freesurfer bbregister into
freesurfer's $SUBJECTS_DIR/subject/tmp.
Returns
-------
Expand All @@ -139,6 +234,7 @@ def automatic(subject, xfmname, reference, noclean=False, bbrtype="signed", pre_
print('Running freesurfer BBR')
cmd = 'bbregister --s {sub} --mov {absref} --init-fsl --reg {cache}/register.dat --t1'
cmd = cmd.format(sub=subject, absref=absreference, cache=cache)

if sp.call(cmd, shell=True) != 0:
raise IOError('Error calling freesurfer BBR!')

Expand Down
9 changes: 5 additions & 4 deletions cortex/xfm.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ def from_freesurfer(cls, fs_register, func_nii, subject, freesurfer_subject_dir=
Parameters
----------
fs_register : array
4x4 transformation matrix, described in an FreeSurfer register.dat file, for a transform computed
4x4 transformation matrix, described in an FreeSurfer .dat or .lta file, for a transform computed
FROM the func_nii volume TO the anatomical volume of the FreeSurfer subject `subject`.
Alternatively, a string file name for the FreeSurfer register.dat file.
Alternatively, a string file name for the FreeSurfer .dat or .lta file.
func_nii : str or nibabel.Nifti1Image
nibabel image object (or string path to nibabel-readable image) for (functional) data volume
to be projected onto cortical surface
Expand Down Expand Up @@ -246,6 +246,7 @@ def from_freesurfer(cls, fs_register, func_nii, subject, freesurfer_subject_dir=
if isinstance(fs_register, string_types):
with open(fs_register, 'r') as fid:
L = fid.readlines()

anat2func = np.array([[np.float(s) for s in ll.split() if s] for ll in L[4:8]])
else:
anat2func = fs_register
Expand Down Expand Up @@ -353,7 +354,7 @@ def to_freesurfer(self, fs_register, subject, freesurfer_subject_dir=None):
# Read tkvox2ras transform for the functional volume
try:
cmd = ('mri_info', '--vox2ras-tkr', func_nii)
L = subprocess.check_output(cmd).splitlines()
L = subprocess.check_output(cmd).splitlines()[1:]
func_tkrvox2ras = np.array([[np.float(s) for s in ll.split() if s] for ll in L])
except OSError:
print ("Error occured while executing:\n{}".format(' '.join(cmd)))
Expand All @@ -362,7 +363,7 @@ def to_freesurfer(self, fs_register, subject, freesurfer_subject_dir=None):
# Read voxel resolution of the functional volume
try:
cmd = ('mri_info', '--res', func_nii)
ll = subprocess.check_output(cmd)
ll = subprocess.check_output(cmd).split("\n")[1]
func_voxres = np.array([np.float(s) for s in ll.split() if s])
except OSError:
print ("Error occured while executing:\n{}".format(' '.join(cmd)))
Expand Down

0 comments on commit c69da36

Please sign in to comment.