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_read_dig_montage(): """Test read_dig_montage""" names = ['nasion', 'lpa', 'rpa', '1', '2', '3', '4', '5'] montage = read_dig_montage(hsp, hpi, elp, names, unit='m', transform=False) elp_points = _read_dig_points(elp) hsp_points = _read_dig_points(hsp) hpi_points = read_mrk(hpi) assert_equal(montage.point_names, names) assert_array_equal(montage.elp, elp_points) assert_array_equal(montage.hsp, hsp_points) assert_array_equal(montage.hpi, hpi_points) assert_array_equal(montage.dev_head_t, np.identity(4)) montage = read_dig_montage(hsp, hpi, elp, names, transform=True, dev_head_t=True) # check coordinate transformation # nasion assert_almost_equal(montage.nasion[0], 0) assert_almost_equal(montage.nasion[2], 0) # lpa and rpa assert_allclose(montage.lpa[1:], 0, atol=1e-16) assert_allclose(montage.rpa[1:], 0, atol=1e-16) # device head transform dev_head_t = fit_matched_points(tgt_pts=montage.elp, src_pts=montage.hpi, out='trans') assert_array_equal(montage.dev_head_t, dev_head_t)
def test_read_dig_montage(): """Test read_dig_montage""" names = ['nasion', 'lpa', 'rpa', '1', '2', '3', '4', '5'] montage = read_dig_montage(hsp, hpi, elp, names, transform=False) elp_points = _read_dig_points(elp) hsp_points = _read_dig_points(hsp) hpi_points = read_mrk(hpi) assert_equal(montage.point_names, names) assert_array_equal(montage.elp, elp_points) assert_array_equal(montage.hsp, hsp_points) assert_array_equal(montage.hpi, hpi_points) assert_true(montage.dev_head_t is None) montage = read_dig_montage(hsp, hpi, elp, names, transform=True, dev_head_t=True) # check coordinate transformation # nasion assert_almost_equal(montage.nasion[0], 0) assert_almost_equal(montage.nasion[2], 0) # lpa and rpa assert_allclose(montage.lpa[1:], 0, atol=1e-16) assert_allclose(montage.rpa[1:], 0, atol=1e-16) # device head transform dev_head_t = fit_matched_points(tgt_pts=montage.elp, src_pts=montage.hpi, out='trans') assert_array_equal(montage.dev_head_t, dev_head_t) # Digitizer as array m2 = read_dig_montage(hsp_points, hpi_points, elp_points, names, unit='m') assert_array_equal(m2.hsp, montage.hsp) m3 = read_dig_montage(hsp_points * 1000, hpi_points, elp_points * 1000, names) assert_allclose(m3.hsp, montage.hsp) # test unit parameter and .mat support tempdir = _TempDir() mat_hsp = op.join(tempdir, 'test.mat') savemat(mat_hsp, dict(Points=(1000 * hsp_points).T)) montage_cm = read_dig_montage(mat_hsp, hpi, elp, names, unit='cm') assert_allclose(montage_cm.hsp, montage.hsp * 10.) assert_allclose(montage_cm.elp, montage.elp * 10.) assert_array_equal(montage_cm.hpi, montage.hpi) assert_raises(ValueError, read_dig_montage, hsp, hpi, elp, names, unit='km') # extra columns extra_hsp = op.join(tempdir, 'test.txt') with open(hsp, 'rb') as fin: with open(extra_hsp, 'wb') as fout: for line in fin: if line.startswith(b'%'): fout.write(line) else: # extra column fout.write(line.rstrip() + b' 0.0 0.0 0.0\n') with warnings.catch_warnings(record=True) as w: montage_extra = read_dig_montage(extra_hsp, hpi, elp, names) assert_true(len(w) == 1 and all('columns' in str(ww.message) for ww in w)) assert_allclose(montage_extra.hsp, montage.hsp) assert_allclose(montage_extra.elp, montage.elp)
def test_read_dig_montage(): """Test read_dig_montage""" names = ['nasion', 'lpa', 'rpa', '1', '2', '3', '4', '5'] montage = read_dig_montage(hsp, hpi, elp, names, transform=False) elp_points = _read_dig_points(elp) hsp_points = _read_dig_points(hsp) hpi_points = read_mrk(hpi) assert_equal(montage.point_names, names) assert_array_equal(montage.elp, elp_points) assert_array_equal(montage.hsp, hsp_points) assert_array_equal(montage.hpi, hpi_points) assert_true(montage.dev_head_t is None) montage = read_dig_montage(hsp, hpi, elp, names, transform=True, dev_head_t=True) # check coordinate transformation # nasion assert_almost_equal(montage.nasion[0], 0) assert_almost_equal(montage.nasion[2], 0) # lpa and rpa assert_allclose(montage.lpa[1:], 0, atol=1e-16) assert_allclose(montage.rpa[1:], 0, atol=1e-16) # device head transform dev_head_t = fit_matched_points(tgt_pts=montage.elp, src_pts=montage.hpi, out='trans') assert_array_equal(montage.dev_head_t, dev_head_t) # Digitizer as array m2 = read_dig_montage(hsp_points, hpi_points, elp_points, names, unit='m') assert_array_equal(m2.hsp, montage.hsp) m3 = read_dig_montage(hsp_points * 1000, hpi_points, elp_points * 1000, names) assert_allclose(m3.hsp, montage.hsp) # test unit parameter and .mat support tempdir = _TempDir() mat_hsp = op.join(tempdir, 'test.mat') savemat(mat_hsp, dict(Points=(1000 * hsp_points).T)) montage_cm = read_dig_montage(mat_hsp, hpi, elp, names, unit='cm') assert_allclose(montage_cm.hsp, montage.hsp * 10.) assert_allclose(montage_cm.elp, montage.elp * 10.) assert_array_equal(montage_cm.hpi, montage.hpi) assert_raises(ValueError, read_dig_montage, hsp, hpi, elp, names, unit='km')
def get_head_mri_trans(bids_fname, bids_root): """Produce transformation matrix from MEG and MRI landmark points. Will attempt to read the landmarks of Nasion, LPA, and RPA from the sidecar files of (i) the MEG and (ii) the T1 weighted MRI data. The two sets of points will then be used to calculate a transformation matrix from head coordinates to MRI coordinates. Parameters ---------- bids_fname : str Full name of the MEG data file bids_root : str Path to root of the BIDS folder Returns ------- trans : instance of mne.transforms.Transform The data transformation matrix from head to MRI coordinates """ if not has_nibabel(): # pragma: no cover raise ImportError('This function requires nibabel.') import nibabel as nib # Get the sidecar file for MRI landmarks bids_fname = op.basename(bids_fname) t1w_json_path = _find_matching_sidecar(bids_fname, bids_root, 'T1w.json') # Get MRI landmarks from the JSON sidecar with open(t1w_json_path, 'r') as f: t1w_json = json.load(f) mri_coords_dict = t1w_json.get('AnatomicalLandmarkCoordinates', dict()) mri_landmarks = np.asarray( (mri_coords_dict.get('LPA', np.nan), mri_coords_dict.get('NAS', np.nan), mri_coords_dict.get('RPA', np.nan))) if np.isnan(mri_landmarks).any(): raise RuntimeError( 'Could not parse T1w sidecar file: "{}"\n\n' 'The sidecar file MUST contain a key ' '"AnatomicalLandmarkCoordinates" pointing to a ' 'dict with keys "LPA", "NAS", "RPA". ' 'Yet, the following structure was found:\n\n"{}"'.format( t1w_json_path, t1w_json)) # The MRI landmarks are in "voxels". We need to convert the to the # neuromag RAS coordinate system in order to compare the with MEG landmarks # see also: `mne_bids.write.write_anat` t1w_path = t1w_json_path.replace('.json', '.nii') if not op.exists(t1w_path): t1w_path += '.gz' # perhaps it is .nii.gz? ... else raise an error if not op.exists(t1w_path): raise RuntimeError( 'Could not find the T1 weighted MRI associated ' 'with "{}". Tried: "{}" but it does not exist.'.format( t1w_json_path, t1w_path)) t1_nifti = nib.load(t1w_path) # Convert to MGH format to access vox2ras method t1_mgh = nib.MGHImage(t1_nifti.dataobj, t1_nifti.affine) # now extract transformation matrix and put back to RAS coordinates of MRI vox2ras_tkr = t1_mgh.header.get_vox2ras_tkr() mri_landmarks = apply_trans(vox2ras_tkr, mri_landmarks) mri_landmarks = mri_landmarks * 1e-3 # Get MEG landmarks from the raw file raw = read_raw_bids(bids_fname, bids_root) meg_coords_dict = _extract_landmarks(raw.info['dig']) meg_landmarks = np.asarray((meg_coords_dict['LPA'], meg_coords_dict['NAS'], meg_coords_dict['RPA'])) # Given the two sets of points, fit the transform trans_fitted = fit_matched_points(src_pts=meg_landmarks, tgt_pts=mri_landmarks) trans = mne.transforms.Transform(fro='head', to='mri', trans=trans_fitted) return trans