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'))
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)
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)
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)
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_}'
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)
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