Source code for cortex.mni
"""
Functions for finding MNI transforms for individual subjects and transforming
functional data and surfaces to and from MNI space.
"""
import os
import nibabel
import tempfile
import subprocess
import numpy as np
from . import options
from . import db
import shlex
fslprefix = options.config.get("basic", "fsl_prefix")
fsldir = os.getenv("FSLDIR")
if fsldir is None:
import warnings
warnings.warn("Can't find FSLDIR environment variable, assuming default FSL location..")
fsldir = "/usr/share/fsl/5.0"
default_template = os.path.join(fsldir, "data", "standard", "MNI152_T1_1mm_brain.nii.gz")
def _save_fsl_xfm(filename, xfm):
np.savetxt(filename, xfm, "%0.10f")
def _load_fsl_xfm(filename):
return np.loadtxt(filename)
[docs]def compute_mni_transform(subject, xfm,
template=default_template):
"""
Compute transform from the space specified by `xfm` to MNI standard space.
Parameters
----------
subject : str
Subject identifier
xfm : str
Name of functional space transform. Can be 'identity' for anat space.
template : str, optional
Path to MNI template volume. Defaults to FSL's MNI152_T1_1mm_brain.
Returns
-------
numpy.ndarray
Transformation matrix from the space specified by `xfm` to MNI space.
"""
# Set up some paths
anat_to_mni_xfm = tempfile.mktemp()
# Get anatomical image
anat_filename = db.get_anat(subject, "brainmask").get_filename()
# First use flirt to align masked subject anatomical to MNI template
cmd = shlex.split(" ".join(["{fslprefix}flirt".format(fslprefix=fslprefix),
"-searchrx -180 180",
"-searchry -180 180",
"-searchrz -180 180",
"-ref", template,
"-in", anat_filename,
"-omat", anat_to_mni_xfm]))
subprocess.call(cmd)
# Then load that transform and concatenate it with the functional to anatomical transform
anat_to_mni = np.loadtxt(anat_to_mni_xfm)
func_to_anat = db.get_xfm(subject, xfm).to_fsl(anat_filename)
func_to_mni = np.dot(anat_to_mni, func_to_anat)
return func_to_mni
[docs]def transform_to_mni(volumedata, func_to_mni,
template=default_template):
"""
Transform data in `volumedata` to MNI space, resample at the resolution of
the atlas image.
Parameters
----------
volumedata : VolumeData
Data to be transformed to MNI space.
func_to_mni : numpy.ndarray
Transformation matrix from the space of `volumedata` to MNI space. Get this
from `compute_mni_transform`.
template : str, optional
Path to MNI template volume, used as reference for flirt. Defaults to FSL's
MNI152_T1_1mm_brain.
Returns
-------
nibabel.nifti1.Nifti1Image
`volumedata` after transformation to MNI space.
"""
# Set up paths
func_nii = tempfile.mktemp(".nii.gz")
func_to_mni_xfm = tempfile.mktemp(".mat")
func_in_mni = tempfile.mktemp(".nii.gz")
# Save out relevant things
volumedata.save_nii(func_nii)
_save_fsl_xfm(func_to_mni_xfm, func_to_mni)
# Use flirt to resample functional data
subprocess.call(["{fslprefix}flirt".format(fslprefix=fslprefix),
"-in", func_nii,
"-ref", template,
"-applyxfm", "-init", func_to_mni_xfm,
"-out", func_in_mni])
return nibabel.load(func_in_mni)
[docs]def transform_surface_to_mni(subject, surfname):
"""
Transform the surface named `surfname` for subject called `subject` into
MNI coordinates. Returns [(lpts, lpolys), (rpts, rpolys)].
Parameters
----------
subject : str
Subject identifier
surfname : str
Surface identifier
Returns
-------
[(mni_lpts, lpolys), (mni_rpts, rpolys)]
MNI-transformed surface in same format returned by db.get_surf.
"""
# Get MNI affine transform
mni_affine = nibabel.load(default_template).get_affine()
# Get subject anatomical-to-MNI transform
mni_xfm = np.dot(mni_affine, db.get_mnixfm(subject, "identity"))
# Get transform from surface points to anatomical space
ident_xfm = db.get_xfm(subject, "identity", xfmtype="coord")
# Get surfaces
(lpts, lpolys), (rpts, rpolys) = db.get_surf(subject, surfname)
# Transform surface points into anatomical space
anat_lpts, anat_rpts = ident_xfm(lpts), ident_xfm(rpts)
# Transform anatomical space points to MNI space
mni_lpts, mni_rpts = [np.dot(mni_xfm, np.hstack([p, np.ones((p.shape[0],1))]).T).T[:,:3]
for p in (anat_lpts, anat_rpts)]
return [(mni_lpts, lpolys), (mni_rpts, rpolys)]
[docs]def transform_mni_to_subject(subject, xfm, volarray, func_to_mni,
template=default_template):
"""
Transform data in `volarray` from MNI space to functional space specified by `xfm`.
Parameters
----------
subject : str
Subject identifier
xfm : str
Name of functional space that data will be transformed into.
volarray : numpy.ndarray
3D volume in MNI space (should have same size as `template`)
func_to_mni : numpy.ndarray
Transformation matrix from `xfm` space to MNI space. Get this
from compute_mni_transform.
template : str, optional
Path to MNI template volume, used as reference. Defaults to FSL's
MNI152_T1_1mm_brain.
Returns
-------
nibabel.nifti1.Nifti1Image
`volarray` after transformation from MNI space to space specified by `xfm`.
"""
# Set up paths
mnispace_func_nii = tempfile.mktemp(".nii.gz")
mni_to_func_xfm = tempfile.mktemp(".mat")
funcspace_nii = tempfile.mktemp(".nii.gz")
# Save out relevant things
affine = nibabel.load(template).get_affine()
nibabel.save(nibabel.Nifti1Image(volarray, affine), mnispace_func_nii)
_save_fsl_xfm(mni_to_func_xfm, np.linalg.inv(func_to_mni))
# Use flirt to resample data to functional space
ref_filename = db.get_xfm(subject, xfm).reference.get_filename()
subprocess.call(["{fslprefix}flirt".format(fslprefix=fslprefix),
"-in", mnispace_func_nii,
"-ref", ref_filename,
"-applyxfm", "-init", mni_to_func_xfm,
"-out", funcspace_nii])
return nibabel.load(funcspace_nii)