def test_fit_matched_points(): """Test fit_matched_points: fitting two matching sets of points.""" tgt_pts = np.random.RandomState(42).uniform(size=(6, 3)) # rotation only trans = rotation(2, 6, 3) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, translate=False, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation") # rotation & translation trans = np.dot(translation(2, -6, 3), rotation(2, 6, 3)) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation and translation.") # rotation & translation & scaling trans = reduce(np.dot, (translation(2, -6, 3), rotation(1.5, .3, 1.4), scaling(.5, .5, .5))) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, scale=1, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation, translation and scaling.") # test exceeding tolerance tgt_pts[0, :] += 20 pytest.raises(RuntimeError, fit_matched_points, tgt_pts, src_pts, tol=10)
def test_fit_matched_points(): """Test fit_matched_points: fitting two matching sets of points""" tgt_pts = np.random.RandomState(42).uniform(size=(6, 3)) # rotation only trans = rotation(2, 6, 3) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, translate=False, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation") # rotation & translation trans = np.dot(translation(2, -6, 3), rotation(2, 6, 3)) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation and translation.") # rotation & translation & scaling trans = reduce(np.dot, (translation(2, -6, 3), rotation(1.5, .3, 1.4), scaling(.5, .5, .5))) src_pts = apply_trans(trans, tgt_pts) trans_est = fit_matched_points(src_pts, tgt_pts, scale=1, out='trans') est_pts = apply_trans(trans_est, src_pts) assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with " "rotation, translation and scaling.") # test exceeding tolerance tgt_pts[0, :] += 20 assert_raises(RuntimeError, fit_matched_points, tgt_pts, src_pts, tol=10)
def _deface(t1w, mri_landmarks, deface, trans, raw): if not has_nibabel(): # pragma: no cover raise ImportError('This function requires nibabel.') import nibabel as nib inset, theta = (20, 35.) if isinstance(deface, dict): if 'inset' in deface: inset = deface['inset'] if 'theta' in deface: theta = deface['theta'] if not _is_numeric(inset): raise ValueError('inset must be numeric (float, int). ' 'Got %s' % type(inset)) if not _is_numeric(theta): raise ValueError('theta must be numeric (float, int). ' 'Got %s' % type(theta)) if inset < 0: raise ValueError('inset should be positive, ' 'Got %s' % inset) if not 0 < theta < 90: raise ValueError('theta should be between 0 and 90 ' 'degrees. Got %s' % theta) # x: L/R L+, y: S/I I+, z: A/P A+ t1w_data = t1w.get_data().copy() idxs_vox = np.meshgrid(np.arange(t1w_data.shape[0]), np.arange(t1w_data.shape[1]), np.arange(t1w_data.shape[2]), indexing='ij') idxs_vox = np.array(idxs_vox) # (3, *t1w_data.shape) idxs_vox = np.transpose(idxs_vox, [1, 2, 3, 0]) # (*t1w_data.shape, 3) idxs_vox = idxs_vox.reshape(-1, 3) # (n_voxels, 3) mri_landmarks_ras = apply_trans(t1w.affine, mri_landmarks) ras_meg_t = \ get_ras_to_neuromag_trans(*mri_landmarks_ras[[1, 0, 2]]) idxs_ras = apply_trans(t1w.affine, idxs_vox) idxs_meg = apply_trans(ras_meg_t, idxs_ras) # now comes the actual defacing # 1. move center of voxels to (nasion - inset) # 2. rotate the head by theta from the normal to the plane passing # through anatomical coordinates trans_y = -mri_landmarks_ras[1, 1] + inset idxs_meg = apply_trans(translation(y=trans_y), idxs_meg) idxs_meg = apply_trans(rotation(x=-np.deg2rad(theta)), idxs_meg) coords = idxs_meg.reshape(t1w.shape + (3, )) # (*t1w_data.shape, 3) mask = (coords[..., 2] < 0) # z < 0 t1w_data[mask] = 0. # smooth decided against for potential lack of anonymizaton # https://gist.github.com/alexrockhill/15043928b716a432db3a84a050b241ae t1w = nib.Nifti1Image(t1w_data, t1w.affine, t1w.header) return t1w
def test_fit_point_cloud(): """Test fit_point_cloud: fitting a set of points to a point cloud""" # evenly spaced target points on a sphere u = np.linspace(0, np.pi, 150) v = np.linspace(0, np.pi, 150) x = np.outer(np.cos(u), np.sin(v)).reshape((-1, 1)) y = np.outer(np.sin(u), np.sin(v)).reshape((-1, 1)) z = np.outer(np.ones(np.size(u)), np.cos(v)).reshape((-1, 1)) * 3 tgt_pts = np.hstack((x, y, z)) tgt_pts = _decimate_points(tgt_pts, .05) # pick some points to fit some_tgt_pts = tgt_pts[::362] # rotation only trans = rotation(1.5, .3, -0.4) src_pts = apply_trans(trans, some_tgt_pts) trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False, scale=0, out='trans') est_pts = apply_trans(trans_est, src_pts) err = _point_cloud_error(est_pts, tgt_pts) assert_array_less(err, .1, "fit_point_cloud with rotation.") # rotation and translation trans = np.dot(rotation(0.5, .3, -0.4), translation(.3, .2, -.2)) src_pts = apply_trans(trans, some_tgt_pts) trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=True, scale=0, out='trans') est_pts = apply_trans(trans_est, src_pts) err = _point_cloud_error(est_pts, tgt_pts) assert_array_less(err, .1, "fit_point_cloud with rotation and " "translation.") # rotation and 1 scale parameter trans = np.dot(rotation(0.5, .3, -0.4), scaling(1.5, 1.5, 1.5)) src_pts = apply_trans(trans, some_tgt_pts) trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False, scale=1, out='trans') est_pts = apply_trans(trans_est, src_pts) err = _point_cloud_error(est_pts, tgt_pts) assert_array_less(err, .1, "fit_point_cloud with rotation and 1 scaling " "parameter.") # rotation and 3 scale parameter trans = np.dot(rotation(0.5, .3, -0.4), scaling(1.5, 1.7, 1.1)) src_pts = apply_trans(trans, some_tgt_pts) trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False, scale=3, out='trans') est_pts = apply_trans(trans_est, src_pts) err = _point_cloud_error(est_pts, tgt_pts) assert_array_less(err, .1, "fit_point_cloud with rotation and 3 scaling " "parameters.")
def test_get_ras_to_neuromag_trans(): """Test the coordinate transformation from ras to neuromag""" # create model points in neuromag-like space anterior = [0, 1, 0] left = [-1, 0, 0] right = [.8, 0, 0] up = [0, 0, 1] rand_pts = np.random.uniform(-1, 1, (3, 3)) pts = np.vstack((anterior, left, right, up, rand_pts)) # change coord system rx, ry, rz, tx, ty, tz = np.random.uniform(-2 * np.pi, 2 * np.pi, 6) trans = np.dot(translation(tx, ty, tz), rotation(rx, ry, rz)) pts_changed = apply_trans(trans, pts) # transform back into original space nas, lpa, rpa = pts_changed[:3] hsp_trans = get_ras_to_neuromag_trans(nas, lpa, rpa) pts_restored = apply_trans(hsp_trans, pts_changed) err = "Neuromag transformation failed" assert_array_almost_equal(pts_restored, pts, 6, err)
def test_get_ras_to_neuromag_trans(): """Test the coordinate transformation from ras to neuromag""" # create model points in neuromag-like space anterior = [0, 1, 0] left = [-1, 0, 0] right = [0.8, 0, 0] up = [0, 0, 1] rand_pts = np.random.uniform(-1, 1, (3, 3)) pts = np.vstack((anterior, left, right, up, rand_pts)) # change coord system rx, ry, rz, tx, ty, tz = np.random.uniform(-2 * np.pi, 2 * np.pi, 6) trans = np.dot(translation(tx, ty, tz), rotation(rx, ry, rz)) pts_changed = apply_trans(trans, pts) # transform back into original space nas, lpa, rpa = pts_changed[:3] hsp_trans = get_ras_to_neuromag_trans(nas, lpa, rpa) pts_restored = apply_trans(hsp_trans, pts_changed) err = "Neuromag transformation failed" assert_array_almost_equal(pts_restored, pts, 6, err)
def test_coregister_fiducials(): """Test coreg.coregister_fiducials().""" # prepare head and MRI fiducials trans = Transform('head', 'mri', rotation(.4, .1, 0).dot(translation(.1, -.1, .1))) coords_orig = np.array([[-0.08061612, -0.02908875, -0.04131077], [0.00146763, 0.08506715, -0.03483611], [0.08436285, -0.02850276, -0.04127743]]) coords_trans = apply_trans(trans, coords_orig) def make_dig(coords, cf): return ({'coord_frame': cf, 'ident': 1, 'kind': 1, 'r': coords[0]}, {'coord_frame': cf, 'ident': 2, 'kind': 1, 'r': coords[1]}, {'coord_frame': cf, 'ident': 3, 'kind': 1, 'r': coords[2]}) mri_fiducials = make_dig(coords_trans, FIFF.FIFFV_COORD_MRI) info = {'dig': make_dig(coords_orig, FIFF.FIFFV_COORD_HEAD)} # test coregister_fiducials() trans_est = coregister_fiducials(info, mri_fiducials) assert trans_est.from_str == trans.from_str assert trans_est.to_str == trans.to_str assert_array_almost_equal(trans_est['trans'], trans['trans'])
def test_coregister_fiducials(): """Test coreg.coregister_fiducials()""" # prepare head and MRI fiducials trans = Transform('head', 'mri', rotation(.4, .1, 0).dot(translation(.1, -.1, .1))) coords_orig = np.array([[-0.08061612, -0.02908875, -0.04131077], [0.00146763, 0.08506715, -0.03483611], [0.08436285, -0.02850276, -0.04127743]]) coords_trans = apply_trans(trans, coords_orig) def make_dig(coords, cf): return ({'coord_frame': cf, 'ident': 1, 'kind': 1, 'r': coords[0]}, {'coord_frame': cf, 'ident': 2, 'kind': 1, 'r': coords[1]}, {'coord_frame': cf, 'ident': 3, 'kind': 1, 'r': coords[2]}) mri_fiducials = make_dig(coords_trans, FIFF.FIFFV_COORD_MRI) info = {'dig': make_dig(coords_orig, FIFF.FIFFV_COORD_HEAD)} # test coregister_fiducials() trans_est = coregister_fiducials(info, mri_fiducials) assert_equal(trans_est.from_str, trans.from_str) assert_equal(trans_est.to_str, trans.to_str) assert_array_almost_equal(trans_est['trans'], trans['trans'])
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 90.0 # mm big_rad = 120.0 center = np.array([0.5, -10.0, 40.0]) # mm dev_trans = np.array([0.0, -0.005, -10.0]) dev_center = center - dev_trans dig = [ # Left auricular { "coord_frame": FIFF.FIFFV_COORD_HEAD, "ident": FIFF.FIFFV_POINT_LPA, "kind": FIFF.FIFFV_POINT_CARDINAL, "r": np.array([-1.0, 0.0, 0.0]), }, # Nasion { "coord_frame": FIFF.FIFFV_COORD_HEAD, "ident": FIFF.FIFFV_POINT_NASION, "kind": FIFF.FIFFV_POINT_CARDINAL, "r": np.array([0.0, 1.0, 0.0]), }, # Right auricular { "coord_frame": FIFF.FIFFV_COORD_HEAD, "ident": FIFF.FIFFV_POINT_RPA, "kind": FIFF.FIFFV_POINT_CARDINAL, "r": np.array([1.0, 0.0, 0.0]), }, # Top of the head (extra point) {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EXTRA, "r": np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EEG, "r": np.array([0, 0.72, 0.69])}, # F3 {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EEG, "r": np.array([-0.55, 0.67, 0.50])}, # F4 {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EEG, "r": np.array([0.55, 0.67, 0.50])}, # Cz {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EEG, "r": np.array([0.0, 0.0, 1.0])}, # Pz {"coord_frame": FIFF.FIFFV_COORD_HEAD, "kind": FIFF.FIFFV_POINT_EEG, "r": np.array([0, -0.72, 0.69])}, ] for d in dig: d["r"] *= rad / 1000.0 d["r"] += center / 1000.0 # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform("meg", "head", translation(*(dev_trans / 1000.0))) info = {"dig": dig, "dev_head_t": dev_head_t} # Degenerate conditions assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) info["dig"][0]["coord_frame"] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info) info["dig"][0]["coord_frame"] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=1e-2) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA, FIFF.FIFFV_POINT_EEG) kwargs = dict(rtol=1e-3, atol=1.0) # in mm r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = (FIFF.FIFFV_POINT_EEG,) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=10.0) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_big = deepcopy(info) for d in info_big["dig"]: d["r"] -= center / 1000.0 d["r"] *= big_rad / rad d["r"] += center / 1000.0 with warnings.catch_warnings(record=True): # fit with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, verbose="warning") log_file = log_file.getvalue().strip() assert_equal(len(log_file.split("\n")), 1) assert_true(log_file.startswith("Estimated head size")) assert_allclose(oh, center, atol=1e-3) assert_allclose(r, big_rad, atol=1e-3) del info_big # Test offcenter dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_shift = deepcopy(info) shift_center = np.array([0.0, -30, 0.0]) for d in info_shift["dig"]: d["r"] -= center / 1000.0 d["r"] += shift_center / 1000.0 with warnings.catch_warnings(record=True): with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_shift, dig_kinds=dig_kinds, verbose="warning") log_file = log_file.getvalue().strip() assert_equal(len(log_file.split("\n")), 1) assert_true("from head frame origin" in log_file) assert_allclose(oh, shift_center, atol=1e-3) assert_allclose(r, rad, atol=1e-3)
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points.""" # Create points of various kinds rad = 0.09 big_rad = 0.12 center = np.array([0.0005, -0.01, 0.04]) dev_trans = np.array([0., -0.005, -0.01]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'ident': 0, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'ident': 0, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'ident': 1, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'ident': 2, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'ident': 3, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'ident': 4, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad d['r'] += center # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans))) info = Info(dig=dig, dev_head_t=dev_head_t) # Degenerate conditions pytest.raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) pytest.raises(ValueError, fit_sphere_to_headshape, info, dig_kinds='foo', units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE pytest.raises(RuntimeError, fit_sphere_to_headshape, info, units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-5) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = ('cardinal', FIFF.FIFFV_POINT_EXTRA, 'eeg') kwargs = dict(rtol=1e-3, atol=1e-3) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = 'eeg' with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-2) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = ('cardinal', 'extra') info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center d['r'] *= big_rad / rad d['r'] += center with pytest.warns(RuntimeWarning, match='Estimated head size'): r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, units='mm') assert_allclose(oh, center * 1000, atol=1e-3) assert_allclose(r, big_rad * 1000, atol=1e-3) del info_big # Test offcenter dig_kinds = ('cardinal', 'extra') info_shift = deepcopy(info) shift_center = np.array([0., -0.03, 0.]) for d in info_shift['dig']: d['r'] -= center d['r'] += shift_center with pytest.warns(RuntimeWarning, match='from head frame origin'): r, oh, od = fit_sphere_to_headshape( info_shift, dig_kinds=dig_kinds, units='m') assert_allclose(oh, shift_center, atol=1e-6) assert_allclose(r, rad, atol=1e-6) # Test "auto" mode (default) # Should try "extra", fail, and go on to EEG with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, units='m') kwargs = dict(rtol=1e-3, atol=1e-3) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r2, oh2, od2 = fit_sphere_to_headshape(info, units='m') assert_allclose(r, r2, atol=1e-7) assert_allclose(oh, oh2, atol=1e-7) assert_allclose(od, od2, atol=1e-7) # this one should pass, 1 EXTRA point and 3 EEG (but the fit is terrible) info = Info(dig=dig[:7], dev_head_t=dev_head_t) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, units='m') # this one should fail, 1 EXTRA point and 3 EEG (but the fit is terrible) info = Info(dig=dig[:6], dev_head_t=dev_head_t) pytest.raises(ValueError, fit_sphere_to_headshape, info, units='m') pytest.raises(TypeError, fit_sphere_to_headshape, 1, units='m')
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points.""" # Create points of various kinds rad = 0.09 big_rad = 0.12 center = np.array([0.0005, -0.01, 0.04]) dev_trans = np.array([0., -0.005, -0.01]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad d['r'] += center # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans))) info = Info(dig=dig, dev_head_t=dev_head_t) # Degenerate conditions pytest.raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) pytest.raises(ValueError, fit_sphere_to_headshape, info, dig_kinds='foo', units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE pytest.raises(RuntimeError, fit_sphere_to_headshape, info, units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-5) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = ('cardinal', FIFF.FIFFV_POINT_EXTRA, 'eeg') kwargs = dict(rtol=1e-3, atol=1e-3) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = 'eeg' with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-2) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = ('cardinal', 'extra') info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center d['r'] *= big_rad / rad d['r'] += center with pytest.warns(RuntimeWarning, match='Estimated head size'): r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, units='mm') assert_allclose(oh, center * 1000, atol=1e-3) assert_allclose(r, big_rad * 1000, atol=1e-3) del info_big # Test offcenter dig_kinds = ('cardinal', 'extra') info_shift = deepcopy(info) shift_center = np.array([0., -0.03, 0.]) for d in info_shift['dig']: d['r'] -= center d['r'] += shift_center with pytest.warns(RuntimeWarning, match='from head frame origin'): r, oh, od = fit_sphere_to_headshape( info_shift, dig_kinds=dig_kinds, units='m') assert_allclose(oh, shift_center, atol=1e-6) assert_allclose(r, rad, atol=1e-6) # Test "auto" mode (default) # Should try "extra", fail, and go on to EEG with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, units='m') kwargs = dict(rtol=1e-3, atol=1e-3) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r2, oh2, od2 = fit_sphere_to_headshape(info, units='m') assert_allclose(r, r2, atol=1e-7) assert_allclose(oh, oh2, atol=1e-7) assert_allclose(od, od2, atol=1e-7) # this one should pass, 1 EXTRA point and 3 EEG (but the fit is terrible) info = Info(dig=dig[:7], dev_head_t=dev_head_t) with pytest.warns(RuntimeWarning, match='Only .* head digitization'): r, oh, od = fit_sphere_to_headshape(info, units='m') # this one should fail, 1 EXTRA point and 3 EEG (but the fit is terrible) info = Info(dig=dig[:6], dev_head_t=dev_head_t) pytest.raises(ValueError, fit_sphere_to_headshape, info, units='m') pytest.raises(TypeError, fit_sphere_to_headshape, 1, units='m')
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 0.09 big_rad = 0.12 center = np.array([0.0005, -0.01, 0.04]) dev_trans = np.array([0., -0.005, -0.01]) dev_center = center - dev_trans dig = [ # Left auricular { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0]) }, # Nasion { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0]) }, # Right auricular { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0]) }, # Top of the head (extra point) { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0]) }, # EEG points # Fz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69]) }, # F3 { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50]) }, # F4 { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50]) }, # Cz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0]) }, # Pz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69]) }, ] for d in dig: d['r'] *= rad d['r'] += center # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions with warnings.catch_warnings(record=True) as w: assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI, )) assert_equal(len(w), 1) assert_true(w[0].category == DeprecationWarning) assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds='foo', units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info, units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-5) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = ('cardinal', FIFF.FIFFV_POINT_EXTRA, 'eeg') kwargs = dict(rtol=1e-3, atol=1e-3) with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = 'eeg' with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-2) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = ('cardinal', 'extra') info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center d['r'] *= big_rad / rad d['r'] += center with warnings.catch_warnings(record=True): # fit with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, verbose='warning', units='mm') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 2) assert_true('Estimated head size' in log_file) assert_allclose(oh, center * 1000, atol=1e-3) assert_allclose(r, big_rad * 1000, atol=1e-3) del info_big # Test offcenter dig_kinds = ('cardinal', 'extra') info_shift = deepcopy(info) shift_center = np.array([0., -0.03, 0.]) for d in info_shift['dig']: d['r'] -= center d['r'] += shift_center with warnings.catch_warnings(record=True): with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_shift, dig_kinds=dig_kinds, verbose='warning', units='m') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 2) assert_true('from head frame origin' in log_file) assert_allclose(oh, shift_center, atol=1e-6) assert_allclose(r, rad, atol=1e-6) # Test "auto" mode (default) # Should try "extra", fail, and go on to EEG with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, units='m') kwargs = dict(rtol=1e-3, atol=1e-3) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) with warnings.catch_warnings(record=True): # not enough points r2, oh2, od2 = fit_sphere_to_headshape(info, units='m') assert_allclose(r, r2, atol=1e-7) assert_allclose(oh, oh2, atol=1e-7) assert_allclose(od, od2, atol=1e-7) # this one should pass, 1 EXTRA point and 3 EEG (but the fit is terrible) info = {'dig': dig[:7], 'dev_head_t': dev_head_t} with warnings.catch_warnings(record=True): # bad fit r, oh, od = fit_sphere_to_headshape(info, units='m') # this one should fail, 1 EXTRA point and 3 EEG (but the fit is terrible) info = {'dig': dig[:6], 'dev_head_t': dev_head_t} assert_raises(ValueError, fit_sphere_to_headshape, info, units='m')
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 90. # mm big_rad = 120. center = np.array([0.5, -10., 40.]) # mm dev_trans = np.array([0., -0.005, -10.]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad / 1000. d['r'] += center / 1000. # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans / 1000.))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=1e-2) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA, FIFF.FIFFV_POINT_EEG) kwargs = dict(rtol=1e-3, atol=1.) # in mm r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = (FIFF.FIFFV_POINT_EEG,) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=10.) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center / 1000. d['r'] *= big_rad / rad d['r'] += center / 1000. with warnings.catch_warnings(record=True): # fit with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, verbose='warning') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 1) assert_true(log_file.startswith('Estimated head size')) assert_allclose(oh, center, atol=1e-3) assert_allclose(r, big_rad, atol=1e-3) del info_big # Test offcenter dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_shift = deepcopy(info) shift_center = np.array([0., -30, 0.]) for d in info_shift['dig']: d['r'] -= center / 1000. d['r'] += shift_center / 1000. with warnings.catch_warnings(record=True): with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape( info_shift, dig_kinds=dig_kinds, verbose='warning') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 1) assert_true('from head frame origin' in log_file) assert_allclose(oh, shift_center, atol=1e-3) assert_allclose(r, rad, atol=1e-3)
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 90. # mm center = np.array([0.5, -10., 40.]) # mm dev_trans = np.array([0., -0.005, -10.]) dev_center = center - dev_trans dig = [ # Left auricular { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0]) }, # Nasion { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0]) }, # Right auricular { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0]) }, # Top of the head (extra point) { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0]) }, # EEG points # Fz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69]) }, # F3 { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50]) }, # F4 { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50]) }, # Cz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0]) }, # Pz { 'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69]) }, ] for d in dig: d['r'] *= rad / 1000. d['r'] += center / 1000. # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans / 1000.))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI, )) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=1e-2) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = (FIFF.FIFFV_POINT_EEG, ) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=10.) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) dig = [dict(coord_frame=FIFF.FIFFV_COORD_DEVICE, )]
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 0.09 big_rad = 0.12 center = np.array([0.0005, -0.01, 0.04]) dev_trans = np.array([0., -0.005, -0.01]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad d['r'] += center # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions with warnings.catch_warnings(record=True) as w: assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) assert_equal(len(w), 1) assert_true(w[0].category == DeprecationWarning) assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds='foo', units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info, units='m') info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-5) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = ('cardinal', FIFF.FIFFV_POINT_EXTRA, 'eeg') kwargs = dict(rtol=1e-3, atol=1e-3) with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = 'eeg' with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds, units='m') kwargs = dict(rtol=1e-3, atol=1e-2) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = ('cardinal', 'extra') info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center d['r'] *= big_rad / rad d['r'] += center with warnings.catch_warnings(record=True): # fit with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, verbose='warning', units='mm') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 2) assert_true('Estimated head size' in log_file) assert_allclose(oh, center * 1000, atol=1e-3) assert_allclose(r, big_rad * 1000, atol=1e-3) del info_big # Test offcenter dig_kinds = ('cardinal', 'extra') info_shift = deepcopy(info) shift_center = np.array([0., -0.03, 0.]) for d in info_shift['dig']: d['r'] -= center d['r'] += shift_center with warnings.catch_warnings(record=True): with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape( info_shift, dig_kinds=dig_kinds, verbose='warning', units='m') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 2) assert_true('from head frame origin' in log_file) assert_allclose(oh, shift_center, atol=1e-6) assert_allclose(r, rad, atol=1e-6) # Test "auto" mode (default) # Should try "extra", fail, and go on to EEG with warnings.catch_warnings(record=True): # not enough points r, oh, od = fit_sphere_to_headshape(info, units='m') kwargs = dict(rtol=1e-3, atol=1e-3) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) with warnings.catch_warnings(record=True): # not enough points r2, oh2, od2 = fit_sphere_to_headshape(info, units='m') assert_allclose(r, r2, atol=1e-7) assert_allclose(oh, oh2, atol=1e-7) assert_allclose(od, od2, atol=1e-7) # this one should pass, 1 EXTRA point and 3 EEG (but the fit is terrible) info = {'dig': dig[:7], 'dev_head_t': dev_head_t} with warnings.catch_warnings(record=True): # bad fit r, oh, od = fit_sphere_to_headshape(info, units='m') # this one should fail, 1 EXTRA point and 3 EEG (but the fit is terrible) info = {'dig': dig[:6], 'dev_head_t': dev_head_t} assert_raises(ValueError, fit_sphere_to_headshape, info, units='m')
def test_scale_mri_xfm(tmp_path, few_surfaces, subjects_dir_tmp_few): """Test scale_mri transforms and MRI scaling.""" # scale fsaverage tempdir = str(subjects_dir_tmp_few) sample_dir = subjects_dir_tmp_few / 'sample' subject_to = 'flachkopf' spacing = 'oct2' for subject_from in ('fsaverage', 'sample'): if subject_from == 'fsaverage': scale = 1. # single dim else: scale = [0.9, 2, .8] # separate src_from_fname = op.join(tempdir, subject_from, 'bem', '%s-%s-src.fif' % (subject_from, spacing)) src_from = mne.setup_source_space(subject_from, spacing, subjects_dir=tempdir, add_dist=False) write_source_spaces(src_from_fname, src_from) vertices_from = np.concatenate([s['vertno'] for s in src_from]) assert len(vertices_from) == 36 hemis = ([0] * len(src_from[0]['vertno']) + [1] * len(src_from[0]['vertno'])) mni_from = mne.vertex_to_mni(vertices_from, hemis, subject_from, subjects_dir=tempdir) if subject_from == 'fsaverage': # identity transform source_rr = np.concatenate( [s['rr'][s['vertno']] for s in src_from]) * 1e3 assert_allclose(mni_from, source_rr) if subject_from == 'fsaverage': overwrite = skip_fiducials = False else: with pytest.raises(IOError, match='No fiducials file'): scale_mri(subject_from, subject_to, scale, subjects_dir=tempdir) skip_fiducials = True with pytest.raises(IOError, match='already exists'): scale_mri(subject_from, subject_to, scale, subjects_dir=tempdir, skip_fiducials=skip_fiducials) overwrite = True if subject_from == 'sample': # support for not needing all surf files os.remove(op.join(sample_dir, 'surf', 'lh.curv')) scale_mri(subject_from, subject_to, scale, subjects_dir=tempdir, verbose='debug', overwrite=overwrite, skip_fiducials=skip_fiducials) if subject_from == 'fsaverage': assert _is_mri_subject(subject_to, tempdir), "Scaling failed" src_to_fname = op.join(tempdir, subject_to, 'bem', '%s-%s-src.fif' % (subject_to, spacing)) assert op.exists(src_to_fname), "Source space was not scaled" # Check MRI scaling fname_mri = op.join(tempdir, subject_to, 'mri', 'T1.mgz') assert op.exists(fname_mri), "MRI was not scaled" # Check MNI transform src = mne.read_source_spaces(src_to_fname) vertices = np.concatenate([s['vertno'] for s in src]) assert_array_equal(vertices, vertices_from) mni = mne.vertex_to_mni(vertices, hemis, subject_to, subjects_dir=tempdir) assert_allclose(mni, mni_from, atol=1e-3) # 0.001 mm # Check head_to_mni (the `trans` here does not really matter) trans = rotation(0.001, 0.002, 0.003) @ translation(0.01, 0.02, 0.03) trans = Transform('head', 'mri', trans) pos_head_from = np.random.RandomState(0).randn(4, 3) pos_mni_from = mne.head_to_mni(pos_head_from, subject_from, trans, tempdir) pos_mri_from = apply_trans(trans, pos_head_from) pos_mri = pos_mri_from * scale pos_head = apply_trans(invert_transform(trans), pos_mri) pos_mni = mne.head_to_mni(pos_head, subject_to, trans, tempdir) assert_allclose(pos_mni, pos_mni_from, atol=1e-3)
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 90. # mm big_rad = 120. center = np.array([0.5, -10., 40.]) # mm dev_trans = np.array([0., -0.005, -10.]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad / 1000. d['r'] += center / 1000. # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans / 1000.))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=1e-2) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA, FIFF.FIFFV_POINT_EEG) kwargs = dict(rtol=1e-3, atol=1.) # in mm r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = (FIFF.FIFFV_POINT_EEG,) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=10.) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) # Test big size dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_big = deepcopy(info) for d in info_big['dig']: d['r'] -= center / 1000. d['r'] *= big_rad / rad d['r'] += center / 1000. with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_big, dig_kinds=dig_kinds, verbose='warning') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 1) assert_true(log_file.startswith('Estimated head size')) assert_allclose(oh, center, atol=1e-3) assert_allclose(r, big_rad, atol=1e-3) del info_big # Test offcenter dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) info_shift = deepcopy(info) shift_center = np.array([0., -30, 0.]) for d in info_shift['dig']: d['r'] -= center / 1000. d['r'] += shift_center / 1000. with catch_logging() as log_file: r, oh, od = fit_sphere_to_headshape(info_shift, dig_kinds=dig_kinds, verbose='warning') log_file = log_file.getvalue().strip() assert_equal(len(log_file.split('\n')), 1) assert_true('from head frame origin' in log_file) assert_allclose(oh, shift_center, atol=1e-3) assert_allclose(r, rad, atol=1e-3)
def test_fit_sphere_to_headshape(): """Test fitting a sphere to digitization points""" # Create points of various kinds rad = 90. # mm center = np.array([0.5, -10., 40.]) # mm dev_trans = np.array([0., -0.005, -10.]) dev_center = center - dev_trans dig = [ # Left auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_LPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([-1.0, 0.0, 0.0])}, # Nasion {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_NASION, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([0.0, 1.0, 0.0])}, # Right auricular {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'ident': FIFF.FIFFV_POINT_RPA, 'kind': FIFF.FIFFV_POINT_CARDINAL, 'r': np.array([1.0, 0.0, 0.0])}, # Top of the head (extra point) {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EXTRA, 'r': np.array([0.0, 0.0, 1.0])}, # EEG points # Fz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, .72, .69])}, # F3 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([-.55, .67, .50])}, # F4 {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([.55, .67, .50])}, # Cz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0.0, 0.0, 1.0])}, # Pz {'coord_frame': FIFF.FIFFV_COORD_HEAD, 'kind': FIFF.FIFFV_POINT_EEG, 'r': np.array([0, -.72, .69])}, ] for d in dig: d['r'] *= rad / 1000. d['r'] += center / 1000. # Device to head transformation (rotate .2 rad over X-axis) dev_head_t = Transform('meg', 'head', translation(*(dev_trans / 1000.))) info = {'dig': dig, 'dev_head_t': dev_head_t} # Degenerate conditions assert_raises(ValueError, fit_sphere_to_headshape, info, dig_kinds=(FIFF.FIFFV_POINT_HPI,)) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_DEVICE assert_raises(RuntimeError, fit_sphere_to_headshape, info) info['dig'][0]['coord_frame'] = FIFF.FIFFV_COORD_HEAD # # Test with 4 points that match a perfect sphere dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=1e-2) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with all points dig_kinds = (FIFF.FIFFV_POINT_CARDINAL, FIFF.FIFFV_POINT_EXTRA, FIFF.FIFFV_POINT_EXTRA) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, dev_center, **kwargs) # Test with some noisy EEG points only. dig_kinds = (FIFF.FIFFV_POINT_EEG,) r, oh, od = fit_sphere_to_headshape(info, dig_kinds=dig_kinds) kwargs = dict(rtol=1e-3, atol=10.) # in mm assert_allclose(r, rad, **kwargs) assert_allclose(oh, center, **kwargs) assert_allclose(od, center, **kwargs) dig = [dict(coord_frame=FIFF.FIFFV_COORD_DEVICE, )]