Exemple #1
0
def test_head_to_mni():
    """Test conversion of aseg vertices to MNI coordinates."""
    # obtained using freeview
    coords = np.array([[22.52, 11.24, 17.72], [22.52, 5.46, 21.58],
                       [16.10, 5.46, 22.23], [21.24, 8.36, 22.23]]) / 1000.

    xfm = read_talxfm('sample', subjects_dir)
    coords_MNI = apply_trans(xfm['trans'], coords) * 1000.

    mri_head_t, _ = _get_trans(trans_fname, 'mri', 'head', allow_none=False)

    # obtained from sample_audvis-meg-oct-6-mixed-fwd.fif
    coo_right_amygdala = np.array([[0.01745682, 0.02665809, 0.03281873],
                                   [0.01014125, 0.02496262, 0.04233755],
                                   [0.01713642, 0.02505193, 0.04258181],
                                   [0.01720631, 0.03073877, 0.03850075]])
    coords_MNI_2 = head_to_mni(coo_right_amygdala, 'sample', mri_head_t,
                               subjects_dir)
    # less than 1mm error
    assert_allclose(coords_MNI, coords_MNI_2, atol=10.0)
Exemple #2
0
# %%
# Let use the Talairach transform computed in the Freesurfer recon-all
# to apply the Freesurfer surface RAS ('mri') to MNI ('mni_tal') transform.

montage = epochs.get_montage()

# first we need a head to mri transform since the data is stored in "head"
# coordinates, let's load the mri to head transform and invert it
this_subject_dir = op.join(misc_path, 'seeg')
head_mri_t = mne.coreg.estimate_head_mri_t('sample_seeg', this_subject_dir)
# apply the transform to our montage
montage.apply_trans(head_mri_t)

# now let's load our Talairach transform and apply it
mri_mni_t = mne.read_talxfm('sample_seeg', op.join(misc_path, 'seeg'))
montage.apply_trans(mri_mni_t)  # mri to mni_tal (MNI Taliarach)

# for fsaverage, "mri" and "mni_tal" are equivalent and, since
# we want to plot in fsaverage "mri" space, we need use an identity
# transform to equate these coordinate frames
montage.apply_trans(
    mne.transforms.Transform(fro='mni_tal', to='mri', trans=np.eye(4)))

epochs.set_montage(montage)

# %%
# Let's check to make sure everything is aligned.
#
# .. note::
#    The most rostral electrode in the temporal lobe is outside the
#
# FreeSurfer's MNI affine transformation
# --------------------------------------
# In addition to surface-based approaches, FreeSurfer also provides a simple
# affine coregistration of each subject's data to the ``fsaverage`` subject.
# Let's pick a point for ``sample`` and plot it on the brain:

brain = mne.viz.Brain('sample', 'lh', 'white', subjects_dir=subjects_dir,
                      background='w')
xyz = np.array([[-55, -10, 35]])
brain.add_foci(xyz, hemi='lh', color='k')
brain.show_view('lat')

# %%
# We can take this point and transform it to MNI space:

mri_mni_trans = mne.read_talxfm(subject, subjects_dir)
print(mri_mni_trans)
xyz_mni = apply_trans(mri_mni_trans, xyz / 1000.) * 1000.
print(np.round(xyz_mni, 1))

# %%
# And because ``fsaverage`` is special in that it's already in MNI space
# (its MRI-to-MNI transform is identity), it should land in the equivalent
# anatomical location:

brain = mne.viz.Brain('fsaverage', 'lh', 'white', subjects_dir=subjects_dir,
                      background='w')
brain.add_foci(xyz_mni, hemi='lh', color='k')
brain.show_view('lat')
def test_convert_coordunits(_temp_bids_root, to_frame, to_unit):
    """Test conversion of coordinate units between voxel and xyz."""
    bids_path = _bids_path.copy().update(root=_temp_bids_root)
    subject = bids_path.subject
    coordsystem_fpath = bids_path.copy().update(suffix='coordsystem',
                                                extension='.json')

    # read dig bids
    sensors_mm = read_dig_bids(bids_path, root=_temp_bids_root)
    img_fpath = sensors_mm.intended_for

    # check error on unexpected kwarg
    if to_unit == 'm':
        sensors_m = convert_coord_units(sensors=sensors_mm,
                                        to_unit=to_unit,
                                        round=False)
        np.testing.assert_array_almost_equal(1000. * sensors_m.get_coords(),
                                             sensors_mm.get_coords())
        with pytest.raises(ValueError,
                           match='Converting coordinates '
                           'to km is not accepted.'):
            convert_coord_units(sensors=sensors_mm, to_unit='km')
        return
    elif to_frame in ['tkras', 'mni']:
        # conversion should not work if starting from xyz coords
        with pytest.raises(ValueError,
                           match='Converting coordinates '
                           'to .* is not accepted.'):
            convert_coord_units(sensors=sensors_mm, to_unit=to_frame)

        # conversion should not work if trying to go to mm
        with pytest.raises(ValueError,
                           match='Converting coordinates '
                           'to mm is not accepted.'):
            convert_coord_space(sensors=sensors_mm, to_frame='mm')

        # conversion should not work if trying to start
        # from mm xyz coords
        with pytest.raises(ValueError,
                           match='Converting coordinates '
                           'requires sensor'):
            convert_coord_space(sensors=sensors_mm, to_frame='tkras')

    # default settings for the read in coordinates file
    assert sensors_mm.coord_unit == 'mm'
    assert sensors_mm.coord_system == 'mri'

    # test units
    if to_unit == 'mm':
        # convert sensors
        sensors_conv = convert_coord_units(sensors=sensors_mm,
                                           to_unit=to_unit,
                                           round=False)
        np.testing.assert_array_almost_equal(sensors_conv.get_coords(),
                                             sensors_mm.get_coords())
    elif to_unit == 'voxel':
        pass

    # convert to voxel should just require convert elec coords
    if to_frame == 'mri':
        # convert sensors first to voxels
        sensors_conv = convert_coord_units(sensors=sensors_mm,
                                           to_unit='voxel',
                                           round=False)

        # returning nothing should be the same
        sensors_mm_mri = convert_coord_space(sensors_mm, to_frame=to_frame)

        # apply affine yourself to go from mm -> voxels
        img = nb.load(img_fpath)
        inv_affine = np.linalg.inv(img.affine)
        coords = apply_affine(inv_affine, sensors_mm.get_coords().copy())

        # round trip should be the same
        sensors_mm_new = convert_coord_units(sensors=sensors_conv,
                                             to_unit='mm',
                                             round=False)
        # the coordinates should match
        np.testing.assert_array_almost_equal(sensors_mm_new.get_coords(),
                                             sensors_mm.get_coords())

    elif to_frame == 'fsaverage':
        # convert to voxels
        sensors_vox = convert_coord_units(sensors=sensors_mm,
                                          to_unit='voxel',
                                          round=False)
        # convert voxels to mni
        sensors_conv = convert_coord_space(sensors_vox,
                                           to_frame=to_frame,
                                           subjects_dir=subjects_dir)

        # load FreeSurfer -> MNI transform (i.e. fsaverage)
        mni_mri_t = read_talxfm(subject=f'sub-{subject}',
                                subjects_dir=subjects_dir)

        # go voxels -> tkras
        coords = apply_affine(mni_mri_t['trans'] * 1000.,
                              sensors_vox.get_coords())

        # the coordinates should match
        np.testing.assert_array_almost_equal(sensors_conv.get_coords(), coords)
    elif to_frame == 'tkras':
        # convert to voxels
        sensors_vox = convert_coord_units(sensors=sensors_mm,
                                          to_unit='voxel',
                                          round=False)
        # convert voxels to tkras
        sensors_conv = convert_coord_space(sensors_vox, to_frame=to_frame)

        # load FreeSurfer MGH file
        img = nb.load(T1mgz)

        # go voxels -> tkras
        coords = apply_affine(img.header.get_vox2ras_tkr(),
                              sensors_vox.get_coords())

        # the coordinates should match
        np.testing.assert_array_almost_equal(sensors_conv.get_coords(), coords)

    # intended for image path should match
    assert img_fpath == sensors_conv.intended_for

    # new coordinate unit should be set
    if to_frame == 'tkras':
        sensors_conv.coord_unit == 'mm'
    else:
        assert sensors_conv.coord_unit == 'voxel'
    assert sensors_conv.coord_system == to_frame

    # the coordinates should match
    np.testing.assert_array_equal(coords, sensors_conv.get_coords())
    assert all([
        sensors_conv.__dict__[key] == sensors_mm.__dict__[key]
        for key in sensors_conv.__dict__.keys()
        if key not in ['x', 'y', 'z', 'coord_unit', 'coord_system']
    ])
Exemple #5
0
#     so that ``scanner RAS`` is equivalent to ``surface RAS``.
#     BIDS requires that template data be in ``scanner RAS`` so for
#     coordinate frames where this is not the case, the coordinates
#     must be converted (see below).

# ensure the output path doesn't contain any leftover files from previous
# tests and example runs
if op.exists(bids_root):
    shutil.rmtree(bids_root)

# load our raw data again
raw = mne.io.read_raw_fif(op.join(misc_path, 'seeg', 'sample_seeg_ieeg.fif'))
raw.info['line_freq'] = 60  # specify power line frequency as required by BIDS

# get Talairach transform
mri_mni_t = mne.read_talxfm('sample_seeg', subjects_dir)

# %%
# Now let's convert the montage to MNI Talairach ("mni_tal").
montage = raw.get_montage()
montage.apply_trans(trans)  # head->mri
montage.apply_trans(mri_mni_t)

# write to BIDS, this time with a template coordinate system
write_raw_bids(raw,
               bids_path,
               anonymize=dict(daysback=40000),
               montage=montage,
               overwrite=True)

# read in the BIDS dataset
def _handle_mni_trans(
    elec_coords,
    img_fpath: Union[str, Path],
    subjects_dir: Union[str, Path, None],
    revert_mni: bool,
    verbose: bool = True,
):
    """Handle FreeSurfer MRI <-> MNI voxels."""
    entities = get_entities_from_fname(img_fpath)
    subject = entities.get("subject")
    if subject is None:
        raise RuntimeError(
            f"Could not interpret the subject from "
            f"IntendedFor Image filepath {img_fpath}. "
            f"This file path is possibly not named "
            f"according to BIDS."
        )

    # Try to get Norig and Torig
    # (i.e. vox_ras_t and vox_mri_t, respectively)
    subj_fs_dir = Path(subjects_dir) / subject  # type: ignore
    if not op.exists(subj_fs_dir):
        subject = f"sub-{subject}"
        subj_fs_dir = Path(subjects_dir) / subject  # type: ignore

    path = op.join(subj_fs_dir, "mri", "orig.mgz")  # type: ignore
    if not op.isfile(path):
        path = op.join(subj_fs_dir, "mri", "T1.mgz")  # type: ignore
    if not op.isfile(path):
        raise IOError("mri not found: %s" % path)
    _, _, mri_ras_t, _, _ = _read_mri_info(path, units="mm")

    # get the intended affine transform from vox -> RAS
    img = nb.load(img_fpath)
    # voxel -> xyz
    intended_affine = img.affine

    # check that vox2ras is the same as our affine
    # if not np.all(np.isclose(intended_affine, mri_ras_t['trans'],
    #                          atol=1e-6)):
    #     print(np.isclose(intended_affine, mri_ras_t['trans'],
    #                          atol=1e-6))
    #     print(intended_affine)
    #     print(mri_ras_t['trans'])
    #     raise RuntimeError(
    #         f"You are trying to convert data "
    #         f"to MNI coordinates for {img_fpath}, "
    #         f"but this does not correspond to the "
    #         f"original T1.mgz file of FreeSurfer. "
    #         f"This is a limitation..."
    #     )

    # read mri voxel of T1.mgz -> MNI tal xfm
    mri_mni_t = read_talxfm(subject=subject, subjects_dir=subjects_dir, verbose=verbose)

    # make sure these are in mm
    mri_to_mni_aff = mri_mni_t["trans"] * 1000.0

    # if reversing MNI, invert affine transform
    # else keep the same as read in
    if revert_mni:
        affine = np.linalg.inv(mri_to_mni_aff)
    else:
        affine = mri_to_mni_aff

    # first convert to voxels
    elec_coords = apply_affine(affine, elec_coords)

    return elec_coords
Exemple #7
0
# %%
# Let use the Talairach transform computed in the Freesurfer recon-all
# to apply the Freesurfer surface RAS ('mri') to MNI ('mni_tal') transform.

montage = epochs.get_montage()

# first we need a head to mri transform since the data is stored in "head"
# coordinates, let's load the mri to head transform and invert it
this_subject_dir = misc_path / 'seeg'
head_mri_t = mne.coreg.estimate_head_mri_t('sample_seeg', this_subject_dir)
# apply the transform to our montage
montage.apply_trans(head_mri_t)

# now let's load our Talairach transform and apply it
mri_mni_t = mne.read_talxfm('sample_seeg', misc_path / 'seeg')
montage.apply_trans(mri_mni_t)  # mri to mni_tal (MNI Taliarach)

# for fsaverage, "mri" and "mni_tal" are equivalent and, since
# we want to plot in fsaverage "mri" space, we need use an identity
# transform to equate these coordinate frames
montage.apply_trans(
    mne.transforms.Transform(fro='mni_tal', to='mri', trans=np.eye(4)))

epochs.set_montage(montage)

# %%
# Let's check to make sure everything is aligned.
#
# .. note::
#    The most rostral electrode in the temporal lobe is outside the