Example #1
0
def test_volume_registration():
    """Test volume registration."""
    import nibabel as nib
    from dipy.align import resample
    T1 = nib.load(fname_t1)
    affine = np.eye(4)
    affine[0, 3] = 10
    T1_resampled = resample(moving=T1.get_fdata(),
                            static=T1.get_fdata(),
                            moving_affine=T1.affine,
                            static_affine=T1.affine,
                            between_affine=np.linalg.inv(affine))
    for pipeline in ('rigids', ('translation', 'sdr')):
        reg_affine, sdr_morph = mne.transforms.compute_volume_registration(
            T1_resampled, T1, pipeline=pipeline, zooms=10, niter=[5])
        assert_allclose(affine, reg_affine, atol=0.25)
        T1_aligned = mne.transforms.apply_volume_registration(
            T1_resampled, T1, reg_affine, sdr_morph)
        r2 = _compute_r2(_get_img_fdata(T1_aligned), _get_img_fdata(T1))
        assert 99.9 < r2

    # check that all orders of the pipeline work
    for pipeline_len in range(1, 5):
        for pipeline in itertools.combinations(
            ('translation', 'rigid', 'affine', 'sdr'), pipeline_len):
            _validate_pipeline(pipeline)
            _validate_pipeline(list(pipeline))

    with pytest.raises(ValueError, match='Steps in pipeline are out of order'):
        _validate_pipeline(('sdr', 'affine'))

    with pytest.raises(ValueError,
                       match='Steps in pipeline should not be repeated'):
        _validate_pipeline(('affine', 'affine'))
Example #2
0
def test_mixed_source_morph(_mixed_morph_srcs, vector):
    """Test mixed source space morphing."""
    import nibabel as nib
    morph, src, src_fs = _mixed_morph_srcs
    # Test some basic properties in the subject's own space
    lut, _ = read_freesurfer_lut()
    ids = [lut[s['seg_name']] for s in src[2:]]
    del lut
    vertices = [s['vertno'] for s in src]
    n_vertices = sum(len(v) for v in vertices)
    data = np.zeros((n_vertices, 3, 1))
    data[:, 1] = 1.
    klass = mne.MixedVectorSourceEstimate
    if not vector:
        data = data[:, 1]
        klass = klass._scalar_class
    stc = klass(data, vertices, 0, 1, 'sample')
    vol_info = _get_mri_info_data(fname_aseg, data=True)
    rrs = np.concatenate([src[2]['rr'][sp['vertno']] for sp in src[2:]])
    n_want = np.in1d(_get_atlas_values(vol_info, rrs), ids).sum()
    img = _get_img_fdata(stc.volume().as_volume(src, mri_resolution=False))
    assert img.astype(bool).sum() == n_want
    img_res = nib.load(fname_aseg)
    n_want = np.in1d(_get_img_fdata(img_res), ids).sum()
    img = _get_img_fdata(stc.volume().as_volume(src, mri_resolution=True))
    assert img.astype(bool).sum() > n_want  # way more get interpolated into

    with pytest.raises(TypeError, match='stc_from must be an instance'):
        morph.apply(1.)

    # Now actually morph
    stc_fs = morph.apply(stc)
    img = stc_fs.volume().as_volume(src_fs, mri_resolution=False)
    vol_info = _get_mri_info_data(fname_aseg_fs, data=True)
    rrs = np.concatenate([src_fs[2]['rr'][sp['vertno']] for sp in src_fs[2:]])
    n_want = np.in1d(_get_atlas_values(vol_info, rrs), ids).sum()
    with pytest.raises(ValueError, match=r'stc\.subject does not match src s'):
        stc_fs.volume().as_volume(src, mri_resolution=False)
    img = _get_img_fdata(
        stc_fs.volume().as_volume(src_fs, mri_resolution=False))
    assert img.astype(bool).sum() == n_want  # correct number of voxels

    # Morph separate parts and compare to morphing the entire one
    stc_fs_surf = morph.apply(stc.surface())
    stc_fs_vol = morph.apply(stc.volume())
    stc_fs_2 = stc_fs.__class__(
        np.concatenate([stc_fs_surf.data, stc_fs_vol.data]),
        stc_fs_surf.vertices + stc_fs_vol.vertices, stc_fs.tmin, stc_fs.tstep,
        stc_fs.subject)
    assert_allclose(stc_fs.data, stc_fs_2.data)
Example #3
0
def test_volume_labels_morph(tmpdir, sl, n_real, n_mri, n_orig):
    """Test generating a source space from volume label."""
    import nibabel as nib
    n_use = (sl.stop - sl.start) // (sl.step or 1)
    # see gh-5224
    evoked = mne.read_evokeds(fname_evoked)[0].crop(0, 0)
    evoked.pick_channels(evoked.ch_names[:306:8])
    evoked.info.normalize_proj()
    n_ch = len(evoked.ch_names)
    aseg_fname = op.join(subjects_dir, 'sample', 'mri', 'aseg.mgz')
    lut, _ = read_freesurfer_lut()
    label_names = sorted(get_volume_labels_from_aseg(aseg_fname))
    use_label_names = label_names[sl]
    src = setup_volume_source_space('sample',
                                    subjects_dir=subjects_dir,
                                    volume_label=use_label_names,
                                    mri=aseg_fname)
    assert len(src) == n_use
    assert src.kind == 'volume'
    n_src = sum(s['nuse'] for s in src)
    sphere = make_sphere_model('auto', 'auto', evoked.info)
    fwd = make_forward_solution(evoked.info, fname_trans, src, sphere)
    assert fwd['sol']['data'].shape == (n_ch, n_src * 3)
    inv = make_inverse_operator(evoked.info,
                                fwd,
                                make_ad_hoc_cov(evoked.info),
                                loose=1.)
    stc = apply_inverse(evoked, inv)
    assert stc.data.shape == (n_src, 1)
    img = stc.as_volume(src, mri_resolution=True)
    assert img.shape == (86, 86, 86, 1)
    n_on = np.array(img.dataobj).astype(bool).sum()
    aseg_img = _get_img_fdata(nib.load(fname_aseg))
    n_got_real = np.in1d(aseg_img.ravel(),
                         [lut[name] for name in use_label_names]).sum()
    assert n_got_real == n_real
    # - This was 291 on `master` before gh-5590
    # - Refactoring transforms it became 279 with a < 1e-8 change in vox_mri_t
    # - Dropped to 123 once nearest-voxel was used in gh-7653
    # - Jumped back up to 330 with morphing fixes actually correctly
    #   interpolating across all volumes
    assert aseg_img.shape == img.shape[:3]
    assert n_on == n_mri
    for ii in range(2):
        # should work with (ii=0) or without (ii=1) the interpolator
        if ii:
            src[0]['interpolator'] = None
        img = stc.as_volume(src, mri_resolution=False)
        n_on = np.array(img.dataobj).astype(bool).sum()
        # was 20 on `master` before gh-5590
        # then 44 before gh-7653, which took it back to 20
        assert n_on == n_orig
    # without the interpolator, this should fail
    assert src[0]['interpolator'] is None
    with pytest.raises(RuntimeError, match=r'.*src\[0\], .* mri_resolution'):
        stc.as_volume(src, mri_resolution=True)
Example #4
0
def test_volume_registration():
    """Test volume registration."""
    import nibabel as nib
    from dipy.align import resample
    T1 = nib.load(fname_t1)
    affine = np.eye(4)
    affine[0, 3] = 10
    T1_resampled = resample(moving=T1.get_fdata(),
                            static=T1.get_fdata(),
                            moving_affine=T1.affine,
                            static_affine=T1.affine,
                            between_affine=np.linalg.inv(affine))
    for pipeline in ('rigids', ('translation', 'sdr')):
        reg_affine, sdr_morph = mne.transforms.compute_volume_registration(
            T1_resampled, T1, pipeline=pipeline, zooms=10, niter=[5])
        assert_allclose(affine, reg_affine, atol=0.25)
        T1_aligned = mne.transforms.apply_volume_registration(
            T1_resampled, T1, reg_affine, sdr_morph)
        r2 = _compute_r2(_get_img_fdata(T1_aligned), _get_img_fdata(T1))
        assert 99.9 < r2
def test_vol_mask():
    """Test extraction of volume mask."""
    src = read_source_spaces(fname_vsrc)
    mask = _get_vol_mask(src)
    # Let's use an alternative way that should be equivalent
    vertices = src[0]['vertno']
    n_vertices = len(vertices)
    data = (1 + np.arange(n_vertices))[:, np.newaxis]
    stc_tmp = VolSourceEstimate(data, vertices, tmin=0., tstep=1.)
    img = stc_tmp.as_volume(src, mri_resolution=False)
    img_data = _get_img_fdata(img)[:, :, :, 0].T
    mask_nib = (img_data != 0)
    assert_array_equal(img_data[mask_nib], data[:, 0])
    assert_array_equal(np.where(mask_nib.ravel())[0], src[0]['vertno'])
    assert_array_equal(mask, mask_nib)
    assert_array_equal(img_data.shape, mask.shape)
def test_combine_source_spaces(tmpdir):
    """Test combining source spaces."""
    import nibabel as nib
    rng = np.random.RandomState(2)
    volume_labels = ['Brain-Stem', 'Right-Hippocampus']  # two fairly large

    # create a sparse surface source space to ensure all get mapped
    # when mri_resolution=False
    srf = setup_source_space('sample',
                             'oct3',
                             add_dist=False,
                             subjects_dir=subjects_dir)

    # setup 2 volume source spaces
    vol = setup_volume_source_space('sample',
                                    subjects_dir=subjects_dir,
                                    volume_label=volume_labels[0],
                                    mri=aseg_fname,
                                    add_interpolator=False)

    # setup a discrete source space
    rr = rng.randint(0, 11, (20, 3)) * 5e-3
    nn = np.zeros(rr.shape)
    nn[:, -1] = 1
    pos = {'rr': rr, 'nn': nn}
    disc = setup_volume_source_space('sample',
                                     subjects_dir=subjects_dir,
                                     pos=pos,
                                     verbose='error')

    # combine source spaces
    assert srf.kind == 'surface'
    assert vol.kind == 'volume'
    assert disc.kind == 'discrete'
    src = srf + vol + disc
    assert src.kind == 'mixed'
    assert srf.kind == 'surface'
    assert vol.kind == 'volume'
    assert disc.kind == 'discrete'

    # test addition of source spaces
    assert len(src) == 4

    # test reading and writing
    src_out_name = tmpdir.join('temp-src.fif')
    src.save(src_out_name)
    src_from_file = read_source_spaces(src_out_name)
    _compare_source_spaces(src, src_from_file, mode='approx')
    assert repr(src).split('~')[0] == repr(src_from_file).split('~')[0]
    assert_equal(src.kind, 'mixed')

    # test that all source spaces are in MRI coordinates
    coord_frames = np.array([s['coord_frame'] for s in src])
    assert (coord_frames == FIFF.FIFFV_COORD_MRI).all()

    # test errors for export_volume
    image_fname = tmpdir.join('temp-image.mgz')

    # source spaces with no volume
    with pytest.raises(ValueError, match='at least one volume'):
        srf.export_volume(image_fname, verbose='error')

    # unrecognized source type
    disc2 = disc.copy()
    disc2[0]['type'] = 'kitty'
    with pytest.raises(ValueError, match='Invalid value'):
        src + disc2
    del disc2

    # unrecognized file type
    bad_image_fname = tmpdir.join('temp-image.png')
    # vertices outside vol space warning
    pytest.raises(ValueError,
                  src.export_volume,
                  bad_image_fname,
                  verbose='error')

    # mixed coordinate frames
    disc3 = disc.copy()
    disc3[0]['coord_frame'] = 10
    src_mixed_coord = src + disc3
    with pytest.raises(ValueError, match='must be in head coordinates'):
        src_mixed_coord.export_volume(image_fname, verbose='error')

    # now actually write it
    fname_img = tmpdir.join('img.nii')
    for mri_resolution in (False, 'sparse', True):
        for src, up in ((vol, 705), (srf + vol, 27272), (disc + vol, 705)):
            src.export_volume(fname_img,
                              use_lut=False,
                              mri_resolution=mri_resolution,
                              overwrite=True)
            img_data = _get_img_fdata(nib.load(str(fname_img)))
            n_src = img_data.astype(bool).sum()
            n_want = sum(s['nuse'] for s in src)
            if mri_resolution is True:
                n_want += up
            assert n_src == n_want, src

    # gh-8004
    temp_aseg = tmpdir.join('aseg.mgz')
    aseg_img = nib.load(aseg_fname)
    aseg_affine = aseg_img.affine
    aseg_affine[:3, :3] *= 0.7
    new_aseg = nib.MGHImage(aseg_img.dataobj, aseg_affine)
    nib.save(new_aseg, str(temp_aseg))
    lh_cereb = mne.setup_volume_source_space(
        "sample",
        mri=temp_aseg,
        volume_label="Left-Cerebellum-Cortex",
        add_interpolator=False,
        subjects_dir=subjects_dir)
    src = srf + lh_cereb
    with pytest.warns(RuntimeWarning, match='2 surf vertices lay outside'):
        src.export_volume(image_fname, mri_resolution="sparse", overwrite=True)
Example #7
0
def test_volume_source_morph_round_trip(
        tmpdir, subject_from, subject_to, lower, upper, dtype, morph_mat,
        monkeypatch):
    """Test volume source estimate morph round-trips well."""
    import nibabel as nib
    from nibabel.processing import resample_from_to
    src = dict()
    if morph_mat:
        # ~1.5 minutes with pos=7. (4157 morphs!) for sample, so only test
        # morph_mat computation mode with a few labels
        label_names = sorted(get_volume_labels_from_aseg(fname_aseg))[1:2]
        if 'sample' in (subject_from, subject_to):
            src['sample'] = setup_volume_source_space(
                'sample', subjects_dir=subjects_dir,
                volume_label=label_names, mri=fname_aseg)
            assert sum(s['nuse'] for s in src['sample']) == 12
        if 'fsaverage' in (subject_from, subject_to):
            src['fsaverage'] = setup_volume_source_space(
                'fsaverage', subjects_dir=subjects_dir,
                volume_label=label_names[:3], mri=fname_aseg_fs)
            assert sum(s['nuse'] for s in src['fsaverage']) == 16
    else:
        assert not morph_mat
        if 'sample' in (subject_from, subject_to):
            src['sample'] = mne.read_source_spaces(fname_vol)
            src['sample'][0]['subject_his_id'] = 'sample'
            assert src['sample'][0]['nuse'] == 4157
        if 'fsaverage' in (subject_from, subject_to):
            # Created to save space with:
            #
            # bem = op.join(op.dirname(mne.__file__), 'data', 'fsaverage',
            #               'fsaverage-inner_skull-bem.fif')
            # src_fsaverage = mne.setup_volume_source_space(
            #     'fsaverage', pos=7., bem=bem, mindist=0,
            #     subjects_dir=subjects_dir, add_interpolator=False)
            # mne.write_source_spaces(fname_fs_vol, src_fsaverage,
            #                         overwrite=True)
            #
            # For speed we do it without the interpolator because it's huge.
            src['fsaverage'] = mne.read_source_spaces(fname_fs_vol)
            src['fsaverage'][0].update(
                vol_dims=np.array([23, 29, 25]), seg_name='brain')
            _add_interpolator(src['fsaverage'])
            assert src['fsaverage'][0]['nuse'] == 6379
    src_to, src_from = src[subject_to], src[subject_from]
    del src
    # No SDR just for speed once everything works
    kwargs = dict(niter_sdr=(), niter_affine=(1,),
                  subjects_dir=subjects_dir, verbose=True)
    morph_from_to = compute_source_morph(
        src=src_from, src_to=src_to, subject_to=subject_to, **kwargs)
    morph_to_from = compute_source_morph(
        src=src_to, src_to=src_from, subject_to=subject_from, **kwargs)
    nuse = sum(s['nuse'] for s in src_from)
    assert nuse > 10
    use = np.linspace(0, nuse - 1, 10).round().astype(int)
    data = np.eye(nuse)[:, use]
    if dtype is complex:
        data = data * 1j
    vertices = [s['vertno'] for s in src_from]
    stc_from = VolSourceEstimate(data, vertices, 0, 1)
    with catch_logging() as log:
        stc_from_rt = morph_to_from.apply(
            morph_from_to.apply(stc_from, verbose='debug'))
    log = log.getvalue()
    assert 'individual volume morph' in log
    maxs = np.argmax(stc_from_rt.data, axis=0)
    src_rr = np.concatenate([s['rr'][s['vertno']] for s in src_from])
    dists = 1000 * np.linalg.norm(src_rr[use] - src_rr[maxs], axis=1)
    mu = np.mean(dists)
    # fsaverage=5.99; 7.97 without additional src_ras_t fix
    # fsaverage=7.97; 25.4 without src_ras_t fix
    assert lower <= mu < upper, f'round-trip distance {mu}'
    # check that pre_affine is close to identity when subject_to==subject_from
    if subject_to == subject_from:
        for morph in (morph_to_from, morph_from_to):
            assert_allclose(
                morph.pre_affine.affine, np.eye(4), atol=1e-2)
    # check that power is more or less preserved (labelizing messes with this)
    if morph_mat:
        if subject_to == 'fsaverage':
            limits = (18, 18.5)
        else:
            limits = (7, 7.5)
    else:
        limits = (1, 1.2)
    stc_from_unit = stc_from.copy().crop(0, 0)
    stc_from_unit._data.fill(1.)
    stc_from_unit_rt = morph_to_from.apply(morph_from_to.apply(stc_from_unit))
    assert_power_preserved(stc_from_unit, stc_from_unit_rt, limits=limits)
    if morph_mat:
        fname = tmpdir.join('temp-morph.h5')
        morph_to_from.save(fname)
        morph_to_from = read_source_morph(fname)
        assert morph_to_from.vol_morph_mat is None
        morph_to_from.compute_vol_morph_mat(verbose=True)
        morph_to_from.save(fname, overwrite=True)
        morph_to_from = read_source_morph(fname)
        assert isinstance(morph_to_from.vol_morph_mat, csr_matrix), 'csr'
        # equivalence (plus automatic calling)
        assert morph_from_to.vol_morph_mat is None
        monkeypatch.setattr(mne.morph, '_VOL_MAT_CHECK_RATIO', 0.)
        with catch_logging() as log:
            with pytest.warns(RuntimeWarning, match=r'calling morph\.compute'):
                stc_from_rt_lin = morph_to_from.apply(
                    morph_from_to.apply(stc_from, verbose='debug'))
        assert isinstance(morph_from_to.vol_morph_mat, csr_matrix), 'csr'
        log = log.getvalue()
        assert 'sparse volume morph matrix' in log
        assert_allclose(stc_from_rt.data, stc_from_rt_lin.data)
        del stc_from_rt_lin
        stc_from_unit_rt_lin = morph_to_from.apply(
            morph_from_to.apply(stc_from_unit))
        assert_allclose(stc_from_unit_rt.data, stc_from_unit_rt_lin.data)
        del stc_from_unit_rt_lin
    del stc_from, stc_from_rt
    # before and after morph, check the proportion of vertices
    # that are inside and outside the brainmask.mgz
    brain = nib.load(op.join(subjects_dir, subject_from, 'mri', 'brain.mgz'))
    mask = _get_img_fdata(brain) > 0
    if subject_from == subject_to == 'sample':
        for stc in [stc_from_unit, stc_from_unit_rt]:
            img = stc.as_volume(src_from, mri_resolution=True)
            img = nib.Nifti1Image(  # abs to convert complex
                np.abs(_get_img_fdata(img)[:, :, :, 0]), img.affine)
            img = _get_img_fdata(resample_from_to(img, brain, order=1))
            assert img.shape == mask.shape
            in_ = img[mask].astype(bool).mean()
            out = img[~mask].astype(bool).mean()
            if morph_mat:
                out_max = 0.001
                in_min, in_max = 0.005, 0.007
            else:
                out_max = 0.02
                in_min, in_max = 0.97, 0.98
            assert out < out_max, f'proportion out of volume {out}'
            assert in_min < in_ < in_max, f'proportion inside volume {in_}'
Example #8
0
def test_warp_montage_volume():
    """Test warping an montage based on intracranial electrode positions."""
    import nibabel as nib
    subject_T1 = nib.load(op.join(subjects_dir, 'sample', 'mri', 'T1.mgz'))
    subject_brain = nib.load(
        op.join(subjects_dir, 'sample', 'mri', 'brain.mgz'))
    template_brain = nib.load(
        op.join(subjects_dir, 'fsaverage', 'mri', 'brain.mgz'))
    reg_affine, sdr_morph = compute_volume_registration(
        subject_brain,
        template_brain,
        zooms=5,
        niter=dict(translation=[5, 5, 5], rigid=[5, 5, 5], sdr=[3, 3, 3]),
        pipeline=('translation', 'rigid', 'sdr'))
    # make fake image with three coordinates
    CT_data = np.zeros(subject_brain.shape)
    # make electrode contact hyperintensities
    CT_data[45:47, 39:41, 49:50] = 500  # surround high intensity
    CT_data[46, 40, 49] = 1000  # center even higher intensity
    CT_data[47:49, 39:40, 49:50] = 500
    CT_data[48, 39, 50] = 1000
    CT_data[50:52, 38:40, 50:51] = 500
    CT_data[50, 39, 50] = 1000
    CT = nib.Nifti1Image(CT_data, subject_T1.affine)
    ch_coords = np.array([[-8.7040273, 17.99938754, 10.29604017],
                          [-14.03007764, 19.69978401, 12.07236939],
                          [-21.1130506, 21.98310911, 13.25658887]])
    ch_pos = dict(zip(['1', '2', '3'], ch_coords / 1000))  # mm -> m
    montage = make_dig_montage(ch_pos, coord_frame='mri')
    montage_warped, image_from, image_to = warp_montage_volume(
        montage,
        CT,
        reg_affine,
        sdr_morph,
        'sample',
        subjects_dir=subjects_dir,
        thresh=0.99)
    # checked with nilearn plot from `tut-ieeg-localize`
    # check montage in surface RAS
    ground_truth_warped = np.array([[-0.27778788, 0.24251515, -0.35693939],
                                    [-0.30033333, 0.24785714, -0.35014286],
                                    [-0.32261947, 0.25295575, -0.34614159]])
    for i in range(len(montage.ch_names)):
        assert np.linalg.norm(  # off by less than 1.5 cm
            montage_warped.dig[i]['r'] - ground_truth_warped[i]) < 0.015
    # check image_from
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 1)),
                       np.array([[45, 46, 46], [40, 39, 40], [49, 49, 49]]))
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 2)),
                       np.array([[48, 48], [39, 39], [49, 50]]))
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 3)),
                       np.array([[50, 50, 51], [38, 39, 39], [50, 50, 50]]))
    # check image_to, too many, just check center
    ground_truth_warped_voxels = np.array(
        [[135.5959596, 161.97979798, 123.83838384],
         [143.11111111, 159.71428571, 125.61904762],
         [150.53982301, 158.38053097, 127.31858407]])
    for i in range(len(montage.ch_names)):
        assert np.linalg.norm(
            np.array(np.where(_get_img_fdata(image_to) == i + 1)).mean(
                axis=1) - ground_truth_warped_voxels[i]) < 5

    # test inputs
    with pytest.raises(ValueError, match='`thresh` must be between 0 and 1'):
        warp_montage_volume(montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            thresh=11.)
    with pytest.raises(ValueError, match='subject folder is incorrect'):
        warp_montage_volume(montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            subject_from='foo')
    CT_unaligned = nib.Nifti1Image(CT_data, subject_brain.affine)
    with pytest.raises(RuntimeError, match='not aligned to Freesurfer'):
        warp_montage_volume(montage,
                            CT_unaligned,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
    bad_montage = make_dig_montage(ch_pos, coord_frame='mri')
    bad_montage.dig[0]['coord_frame'] = 99
    with pytest.raises(RuntimeError,
                       match='Only single coordinate frame in '
                       'dig is supported'):
        warp_montage_volume(bad_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
    wrong_montage = make_dig_montage(ch_pos, coord_frame='head')
    with pytest.raises(RuntimeError, match='Coordinate frame not supported'):
        warp_montage_volume(wrong_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)

    # check channel not warped
    ch_pos_doubled = ch_pos.copy()
    ch_pos_doubled.update(zip(['4', '5', '6'], ch_coords / 1000))
    doubled_montage = make_dig_montage(ch_pos_doubled, coord_frame='mri')
    with pytest.warns(RuntimeWarning, match='not assigned'):
        warp_montage_volume(doubled_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
Example #9
0
def test_volume_source_morph_round_trip(tmpdir, subject_from, subject_to,
                                        lower, upper):
    """Test volume source estimate morph round-trips well."""
    import nibabel as nib
    from nibabel.processing import resample_from_to
    src = dict()
    if 'sample' in (subject_from, subject_to):
        src['sample'] = mne.read_source_spaces(fname_vol)
        src['sample'][0]['subject_his_id'] = 'sample'
        assert src['sample'][0]['nuse'] == 4157
    if 'fsaverage' in (subject_from, subject_to):
        # Created to save space with:
        #
        # bem = op.join(op.dirname(mne.__file__), 'data', 'fsaverage',
        #               'fsaverage-inner_skull-bem.fif')
        # src_fsaverage = mne.setup_volume_source_space(
        #     'fsaverage', pos=7., bem=bem, mindist=0,
        #     subjects_dir=subjects_dir, add_interpolator=False)
        # mne.write_source_spaces(fname_fs_vol, src_fsaverage, overwrite=True)
        #
        # For speed we do it without the interpolator because it's huge.
        src['fsaverage'] = mne.read_source_spaces(fname_fs_vol)
        src['fsaverage'][0].update(vol_dims=np.array([23, 29, 25]),
                                   seg_name='brain')
        _add_interpolator(src['fsaverage'], True)
        assert src['fsaverage'][0]['nuse'] == 6379
    src_to, src_from = src[subject_to], src[subject_from]
    del src
    # No SDR just for speed once everything works
    kwargs = dict(niter_sdr=(),
                  niter_affine=(1, ),
                  subjects_dir=subjects_dir,
                  verbose=True)
    morph_from_to = compute_source_morph(src=src_from,
                                         src_to=src_to,
                                         subject_to=subject_to,
                                         **kwargs)
    morph_to_from = compute_source_morph(src=src_to,
                                         src_to=src_from,
                                         subject_to=subject_from,
                                         **kwargs)
    use = np.linspace(0, src_from[0]['nuse'] - 1, 10).round().astype(int)
    stc_from = VolSourceEstimate(
        np.eye(src_from[0]['nuse'])[:, use], [src_from[0]['vertno']], 0, 1)
    stc_from_rt = morph_to_from.apply(morph_from_to.apply(stc_from))
    maxs = np.argmax(stc_from_rt.data, axis=0)
    src_rr = src_from[0]['rr'][src_from[0]['vertno']]
    dists = 1000 * np.linalg.norm(src_rr[use] - src_rr[maxs], axis=1)
    mu = np.mean(dists)
    assert lower <= mu < upper  # fsaverage=7.97; 25.4 without src_ras_t fix
    # check that pre_affine is close to identity when subject_to==subject_from
    if subject_to == subject_from:
        for morph in (morph_to_from, morph_from_to):
            assert_allclose(morph.pre_affine.affine, np.eye(4), atol=1e-2)
    # check that power is more or less preserved
    ratio = stc_from.data.size / stc_from_rt.data.size
    limits = ratio * np.array([1, 1.2])
    stc_from.crop(0, 0)._data.fill(1.)
    stc_from_rt = morph_to_from.apply(morph_from_to.apply(stc_from))
    assert_power_preserved(stc_from, stc_from_rt, limits=limits)
    # before and after morph, check the proportion of vertices
    # that are inside and outside the brainmask.mgz
    brain = nib.load(op.join(subjects_dir, subject_from, 'mri', 'brain.mgz'))
    mask = _get_img_fdata(brain) > 0
    if subject_from == subject_to == 'sample':
        for stc in [stc_from, stc_from_rt]:
            img = stc.as_volume(src_from, mri_resolution=True)
            img = nib.Nifti1Image(_get_img_fdata(img)[:, :, :, 0], img.affine)
            img = _get_img_fdata(resample_from_to(img, brain, order=1))
            assert img.shape == mask.shape
            in_ = img[mask].astype(bool).mean()
            out = img[~mask].astype(bool).mean()
            assert 0.97 < in_ < 0.98
            assert out < 0.02