def test_get_mni_fiducials(): """Test get_mni_fiducials.""" fids, coord_frame = read_fiducials(fid_fname) assert coord_frame == FIFF.FIFFV_COORD_MRI assert [f['ident'] for f in fids] == list(range(1, 4)) fids = np.array([f['r'] for f in fids]) fids_est = get_mni_fiducials('sample', subjects_dir) fids_est = np.array([f['r'] for f in fids_est]) dists = np.linalg.norm(fids - fids_est, axis=-1) * 1000. # -> mm assert (dists < 8).all(), dists
def test_warp_montage_volume(): """Test warping an montage based on intracranial electrode positions.""" import nibabel as nib subject_brain = nib.load( op.join(subjects_dir, 'sample', 'mri', 'brain.mgz')) template_brain = nib.load( op.join(subjects_dir, 'fsaverage', 'mri', 'brain.mgz')) zooms = dict(translation=10, rigid=10, sdr=10) reg_affine, sdr_morph = compute_volume_registration( subject_brain, template_brain, zooms=zooms, niter=[3, 3, 3], pipeline=('translation', 'rigid', 'sdr')) # make an info object with three channels with positions 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 lpa, nasion, rpa = get_mni_fiducials('sample', subjects_dir) montage = make_dig_montage(ch_pos, lpa=lpa['r'], nasion=nasion['r'], rpa=rpa['r'], coord_frame='mri') # make fake image based on the info CT_data = np.zeros(subject_brain.shape) # convert to voxels ch_coords_vox = apply_trans( np.linalg.inv(subject_brain.header.get_vox2ras_tkr()), ch_coords) for (x, y, z) in ch_coords_vox.round().astype(int): # make electrode contact hyperintensities # first, make the surrounding voxels high intensity CT_data[x - 1:x + 2, y - 1:y + 2, z - 1:z + 2] = 500 # then, make the center even higher intensity CT_data[x, y, z] = 1000 CT = nib.Nifti1Image(CT_data, subject_brain.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 lpa, nasion, rpa = get_mni_fiducials('sample', subjects_dir) montage = make_dig_montage(ch_pos, lpa=lpa['r'], nasion=nasion['r'], rpa=rpa['r'], coord_frame='mri') montage_warped, image_from, image_to = warp_montage_volume( montage, CT, reg_affine, sdr_morph, 'sample', subjects_dir_from=subjects_dir, thresh=0.99) # checked with nilearn plot from `tut-ieeg-localize` # check montage in surface RAS ground_truth_warped = np.array([[-0.009, -0.00133333, -0.033], [-0.01445455, 0.00127273, -0.03163636], [-0.022, 0.00285714, -0.031]]) for i, d in enumerate(montage_warped.dig): assert np.linalg.norm( # off by less than 1.5 cm d['r'] - ground_truth_warped[i]) < 0.015 # check image_from for idx, contact in enumerate(range(1, len(ch_pos) + 1)): voxels = np.array(np.where(np.array(image_from.dataobj) == contact)).T assert ch_coords_vox.round()[idx] in voxels assert ch_coords_vox.round()[idx] + 5 not in voxels # 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(np.array(image_to.dataobj) == i + 1) ).mean(axis=1) - ground_truth_warped_voxels[i]) < 8 # 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, template_brain.affine) with pytest.raises(RuntimeError, match='not aligned to Freesurfer'): warp_montage_volume(montage, CT_unaligned, reg_affine, sdr_morph, 'sample', subjects_dir_from=subjects_dir) bad_montage = montage.copy() for d in bad_montage.dig: d['coord_frame'] = 99 with pytest.raises(RuntimeError, match='Coordinate frame not supported'): warp_montage_volume(bad_montage, CT, reg_affine, sdr_morph, 'sample', subjects_dir_from=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, lpa=lpa['r'], nasion=nasion['r'], rpa=rpa['r'], coord_frame='mri') with pytest.warns(RuntimeWarning, match='not assigned'): warp_montage_volume(doubled_montage, CT, reg_affine, None, 'sample', subjects_dir_from=subjects_dir)