Beispiel #1
0
def _compare_positions(a, b, max_dist=0.003, max_angle=5.):
    """Compare estimated cHPI positions"""
    from scipy.interpolate import interp1d
    trans, rot, t = a
    trans_est, rot_est, t_est = b
    quats_est = rot_to_quat(rot_est)

    # maxfilter produces some times that are implausibly large (weird)
    use_mask = (t >= t_est[0]) & (t <= t_est[-1])
    t = t[use_mask]
    trans = trans[use_mask]
    quats = rot_to_quat(rot)
    quats = quats[use_mask]

    # double-check our angle function
    for q in (quats, quats_est):
        angles = _angle_between_quats(q, q)
        assert_allclose(angles, 0., atol=1e-5)

    # < 3 mm translation difference between MF and our estimation
    trans_est_interp = interp1d(t_est, trans_est, axis=0)(t)
    worst = np.sqrt(np.sum((trans - trans_est_interp)**2, axis=1)).max()
    assert_true(worst <= max_dist,
                '%0.1f > %0.1f mm' % (1000 * worst, 1000 * max_dist))

    # < 5 degrees rotation difference between MF and our estimation
    # (note that the interpolation will make this slightly worse)
    quats_est_interp = interp1d(t_est, quats_est, axis=0)(t)
    worst = 180 * _angle_between_quats(quats_est_interp, quats).max() / np.pi
    assert_true(worst <= max_angle, '%0.1f > %0.1f deg' % (
        worst,
        max_angle,
    ))
Beispiel #2
0
def _compare_positions(a, b, max_dist=0.003, max_angle=5.):
    """Compare estimated cHPI positions"""
    from scipy.interpolate import interp1d
    trans, rot, t = a
    trans_est, rot_est, t_est = b
    quats_est = rot_to_quat(rot_est)

    # maxfilter produces some times that are implausibly large (weird)
    use_mask = (t >= t_est[0]) & (t <= t_est[-1])
    t = t[use_mask]
    trans = trans[use_mask]
    quats = rot_to_quat(rot)
    quats = quats[use_mask]

    # double-check our angle function
    for q in (quats, quats_est):
        angles = _angle_between_quats(q, q)
        assert_allclose(angles, 0., atol=1e-5)

    # < 3 mm translation difference between MF and our estimation
    trans_est_interp = interp1d(t_est, trans_est, axis=0)(t)
    worst = np.sqrt(np.sum((trans - trans_est_interp) ** 2, axis=1)).max()
    assert_true(worst <= max_dist, '%0.1f > %0.1f mm'
                % (1000 * worst, 1000 * max_dist))

    # < 5 degrees rotation difference between MF and our estimation
    # (note that the interpolation will make this slightly worse)
    quats_est_interp = interp1d(t_est, quats_est, axis=0)(t)
    worst = 180 * _angle_between_quats(quats_est_interp, quats).max() / np.pi
    assert_true(worst <= max_angle, '%0.1f > %0.1f deg' % (worst, max_angle,))
Beispiel #3
0
def _assert_quats(actual, desired, dist_tol=0.003, angle_tol=5., err_rtol=0.5,
                  gof_rtol=0.001, vel_atol=2e-3):  # 2 mm/s
    """Compare estimated cHPI positions."""
    __tracebackhide__ = True
    trans_est, rot_est, t_est = head_pos_to_trans_rot_t(actual)
    trans, rot, t = head_pos_to_trans_rot_t(desired)
    quats_est = rot_to_quat(rot_est)
    gofs, errs, vels = desired[:, 7:].T
    gofs_est, errs_est, vels_est = actual[:, 7:].T
    del actual, desired

    # maxfilter produces some times that are implausibly large (weird)
    if not np.isclose(t[0], t_est[0], atol=1e-1):  # within 100 ms
        raise AssertionError('Start times not within 100 ms: %0.3f != %0.3f'
                             % (t[0], t_est[0]))
    use_mask = (t >= t_est[0]) & (t <= t_est[-1])
    t = t[use_mask]
    trans = trans[use_mask]
    quats = rot_to_quat(rot)
    quats = quats[use_mask]
    gofs, errs, vels = gofs[use_mask], errs[use_mask], vels[use_mask]

    # double-check our angle function
    for q in (quats, quats_est):
        angles = _angle_between_quats(q, q)
        assert_allclose(angles, 0., atol=1e-5)

    # limit translation difference between MF and our estimation
    trans_est_interp = interp1d(t_est, trans_est, axis=0)(t)
    distances = np.sqrt(np.sum((trans - trans_est_interp) ** 2, axis=1))
    assert np.isfinite(distances).all()
    arg_worst = np.argmax(distances)
    assert distances[arg_worst] <= dist_tol, (
        '@ %0.3f seconds: %0.3f > %0.3f mm'
        % (t[arg_worst], 1000 * distances[arg_worst], 1000 * dist_tol))

    # limit rotation difference between MF and our estimation
    # (note that the interpolation will make this slightly worse)
    quats_est_interp = interp1d(t_est, quats_est, axis=0)(t)
    angles = 180 * _angle_between_quats(quats_est_interp, quats) / np.pi
    arg_worst = np.argmax(angles)
    assert angles[arg_worst] <= angle_tol, (
        '@ %0.3f seconds: %0.3f > %0.3f deg'
        % (t[arg_worst], angles[arg_worst], angle_tol))

    # error calculation difference
    errs_est_interp = interp1d(t_est, errs_est)(t)
    assert_allclose(errs_est_interp, errs, rtol=err_rtol, atol=1e-3,
                    err_msg='err')  # 1 mm

    # gof calculation difference
    gof_est_interp = interp1d(t_est, gofs_est)(t)
    assert_allclose(gof_est_interp, gofs, rtol=gof_rtol, atol=1e-7,
                    err_msg='gof')

    # velocity calculation difference
    vel_est_interp = interp1d(t_est, vels_est)(t)
    assert_allclose(vel_est_interp, vels, atol=vel_atol,
                    err_msg='velocity')
Beispiel #4
0
def test_quaternions():
    """Test quaternion calculations."""
    rots = [np.eye(3)]
    for fname in [test_fif_fname, ctf_fname, hp_fif_fname]:
        rots += [read_info(fname)['dev_head_t']['trans'][:3, :3]]
    # nasty numerical cases
    rots += [
        np.array([
            [-0.99978541, -0.01873462, -0.00898756],
            [-0.01873462, 0.62565561, 0.77987608],
            [-0.00898756, 0.77987608, -0.62587152],
        ])
    ]
    rots += [
        np.array([
            [0.62565561, -0.01873462, 0.77987608],
            [-0.01873462, -0.99978541, -0.00898756],
            [0.77987608, -0.00898756, -0.62587152],
        ])
    ]
    rots += [
        np.array([
            [-0.99978541, -0.00898756, -0.01873462],
            [-0.00898756, -0.62587152, 0.77987608],
            [-0.01873462, 0.77987608, 0.62565561],
        ])
    ]
    for rot in rots:
        assert_allclose(rot,
                        quat_to_rot(rot_to_quat(rot)),
                        rtol=1e-5,
                        atol=1e-5)
        rot = rot[np.newaxis, np.newaxis, :, :]
        assert_allclose(rot,
                        quat_to_rot(rot_to_quat(rot)),
                        rtol=1e-5,
                        atol=1e-5)

    # let's make sure our angle function works in some reasonable way
    for ii in range(3):
        for jj in range(3):
            a = np.zeros(3)
            b = np.zeros(3)
            a[ii] = 1.
            b[jj] = 1.
            expected = np.pi if ii != jj else 0.
            assert_allclose(_angle_between_quats(a, b), expected, atol=1e-5)

    y_180 = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1.]])
    assert_allclose(_angle_between_quats(rot_to_quat(y_180), np.zeros(3)),
                    np.pi)
    h_180_attitude_90 = np.array([[0, 1, 0], [1, 0, 0], [0, 0, -1.]])
    assert_allclose(
        _angle_between_quats(rot_to_quat(h_180_attitude_90), np.zeros(3)),
        np.pi)
def _check_fit_matched_points(
        p, x, weights, do_scale, angtol=1e-5, dtol=1e-5, stol=1e-7):
    __tracebackhide__ = True
    mne.coreg._ALLOW_ANALITICAL = False
    try:
        params = mne.coreg.fit_matched_points(
            p, x, weights=weights, scale=do_scale, out='params')
    finally:
        mne.coreg._ALLOW_ANALITICAL = True
    quat_an, scale_an = _fit_matched_points(p, x, weights, scale=do_scale)
    assert len(params) == 6 + int(do_scale)
    q_co = _euler_to_quat(params[:3])
    translate_co = params[3:6]
    angle = np.rad2deg(_angle_between_quats(quat_an[:3], q_co))
    dist = np.linalg.norm(quat_an[3:] - translate_co)
    assert 0 <= angle < angtol, 'angle'
    assert 0 <= dist < dtol, 'dist'
    if do_scale:
        scale_co = params[6]
        assert_allclose(scale_an, scale_co, rtol=stol, err_msg='scale')
    # errs
    trans = _quat_to_affine(quat_an)
    trans[:3, :3] *= scale_an
    weights = np.ones(1) if weights is None else weights
    err_an = np.linalg.norm(
        weights[:, np.newaxis] * apply_trans(trans, p) - x)
    trans = mne.coreg._trans_from_params((True, True, do_scale), params)
    err_co = np.linalg.norm(
        weights[:, np.newaxis] * apply_trans(trans, p) - x)
    if err_an > 1e-14:
        assert err_an < err_co * 1.5
    return quat_an, scale_an
Beispiel #6
0
def test_average_quats():
    """Test averaging of quaternions."""
    sq2 = 1. / np.sqrt(2.)
    quats = np.array(
        [[0, sq2, sq2], [0, sq2, sq2], [0, sq2, 0], [0, 0, sq2], [sq2, 0, 0]],
        float)
    # In MATLAB:
    # quats = [[0, sq2, sq2, 0]; [0, sq2, sq2, 0];
    #          [0, sq2, 0, sq2]; [0, 0, sq2, sq2]; [sq2, 0, 0, sq2]];
    expected = [
        quats[0], quats[0], [0, 0.788675134594813, 0.577350269189626],
        [0, 0.657192299694123, 0.657192299694123],
        [0.100406058540540, 0.616329446922803, 0.616329446922803]
    ]
    # Averaging the first two should give the same thing:
    for lim, ex in enumerate(expected):
        assert_allclose(_average_quats(quats[:lim + 1]), ex, atol=1e-7)
    quats[1] *= -1  # same quaternion (hidden value is zero here)!
    rot_0, rot_1 = quat_to_rot(quats[:2])
    assert_allclose(rot_0, rot_1, atol=1e-7)
    for lim, ex in enumerate(expected):
        assert_allclose(_average_quats(quats[:lim + 1]), ex, atol=1e-7)
    # Assert some symmetry
    count = 0
    extras = [[sq2, sq2, 0]] + list(np.eye(3))
    for quat in np.concatenate((quats, expected, extras)):
        if np.isclose(_quat_real(quat), 0., atol=1e-7):  # can flip sign
            count += 1
            angle = _angle_between_quats(quat, -quat)
            assert_allclose(angle, 0., atol=1e-7)
            rot_0, rot_1 = quat_to_rot(np.array((quat, -quat)))
            assert_allclose(rot_0, rot_1, atol=1e-7)
    assert count == 4 + len(extras)
Beispiel #7
0
def test_vector_rotation():
    """Test basic rotation matrix math."""
    x = np.array([1., 0., 0.])
    y = np.array([0., 1., 0.])
    rot = _find_vector_rotation(x, y)
    assert_array_equal(rot, [[0, -1, 0], [1, 0, 0], [0, 0, 1]])
    quat_1 = rot_to_quat(rot)
    quat_2 = rot_to_quat(np.eye(3))
    assert_allclose(_angle_between_quats(quat_1, quat_2), np.pi / 2.)
def test_fit_matched_points(quats, scaling, do_scale):
    """Test analytical least-squares matched point fitting."""
    if scaling != 1 and not do_scale:
        return  # no need to test this, it will not be good
    rng = np.random.RandomState(0)
    fro = rng.randn(10, 3)
    translation = rng.randn(3)
    for qi, quat in enumerate(quats):
        to = scaling * np.dot(quat_to_rot(quat), fro.T).T + translation
        for corrupted in (False, True):
            # mess up a point
            if corrupted:
                to[0, 2] += 100
                weights = np.ones(len(to))
                weights[0] = 0
            else:
                weights = None
            est, scale_est = _check_fit_matched_points(
                fro, to, weights=weights, do_scale=do_scale)
            assert_allclose(scale_est, scaling, rtol=1e-5)
            assert_allclose(est[:3], quat, atol=1e-14)
            assert_allclose(est[3:], translation, atol=1e-14)
        # if we don't adjust for the corruption above, it should get worse
        angle = dist = None
        for weighted in (False, True):
            if not weighted:
                weights = None
                dist_bounds = (5, 20)
                if scaling == 1:
                    angle_bounds = (5, 95)
                    angtol, dtol, stol = 1, 15, 3
                else:
                    angle_bounds = (5, 105)
                    angtol, dtol, stol = 20, 15, 3
            else:
                weights = np.ones(len(to))
                weights[0] = 10  # weighted=True here means "make it worse"
                angle_bounds = (angle, 180)  # unweighted values as new min
                dist_bounds = (dist, 100)
                if scaling == 1:
                    # XXX this angtol is not great but there is a hard to
                    # identify linalg/angle calculation bug on Travis...
                    angtol, dtol, stol = 180, 70, 3
                else:
                    angtol, dtol, stol = 50, 70, 3
            est, scale_est = _check_fit_matched_points(
                fro, to, weights=weights, do_scale=do_scale,
                angtol=angtol, dtol=dtol, stol=stol)
            assert not np.allclose(est[:3], quat, atol=1e-5)
            assert not np.allclose(est[3:], translation, atol=1e-5)
            angle = np.rad2deg(_angle_between_quats(est[:3], quat))
            assert_array_less(angle_bounds[0], angle)
            assert_array_less(angle, angle_bounds[1])
            dist = np.linalg.norm(est[3:] - translation)
            assert_array_less(dist_bounds[0], dist)
            assert_array_less(dist, dist_bounds[1])
def test_vector_rotation():
    """Test basic rotation matrix math."""
    x = np.array([1., 0., 0.])
    y = np.array([0., 1., 0.])
    rot = _find_vector_rotation(x, y)
    assert_array_equal(rot,
                       [[0, -1, 0], [1, 0, 0], [0, 0, 1]])
    quat_1 = rot_to_quat(rot)
    quat_2 = rot_to_quat(np.eye(3))
    assert_allclose(_angle_between_quats(quat_1, quat_2), np.pi / 2.)
Beispiel #10
0
def test_talxfm_rigid():
    """Test that talxfm_rigid gives reasonable results."""
    rigid = _estimate_talxfm_rigid('fsaverage', subjects_dir=subjects_dir)
    assert_allclose(rigid, np.eye(4), atol=1e-6)
    rigid = _estimate_talxfm_rigid('sample', subjects_dir=subjects_dir)
    assert_allclose(np.linalg.norm(rigid[:3, :3], axis=1), 1., atol=1e-6)
    move = 1000 * np.linalg.norm(rigid[:3, 3])
    assert 30 < move < 70
    ang = np.rad2deg(_angle_between_quats(rot_to_quat(rigid[:3, :3])))
    assert 20 < ang < 25
Beispiel #11
0
def _assert_trans(actual, desired, dist_tol=0.003, angle_tol=5.):
    trans_est = actual[0:3, 3]
    quat_est = rot_to_quat(actual[0:3, 0:3])
    trans = desired[0:3, 3]
    quat = rot_to_quat(desired[0:3, 0:3])

    angle = 180 * _angle_between_quats(quat_est, quat) / np.pi
    dist = np.sqrt(np.sum((trans - trans_est) ** 2))
    assert dist <= dist_tol, '%0.3f > %0.3f mm' % (1000 * dist,
                                                   1000 * dist_tol)
    assert angle <= angle_tol, '%0.3f > %0.3f deg' % (angle, angle_tol)
Beispiel #12
0
def _assert_trans(actual, desired, dist_tol=0.003, angle_tol=5.):
    trans_est = actual[0:3, 3]
    quat_est = rot_to_quat(actual[0:3, 0:3])
    trans = desired[0:3, 3]
    quat = rot_to_quat(desired[0:3, 0:3])

    angle = 180 * _angle_between_quats(quat_est, quat) / np.pi
    dist = np.sqrt(np.sum((trans - trans_est)**2))
    assert_true(dist <= dist_tol,
                '%0.3f > %0.3f mm' % (1000 * dist, 1000 * dist_tol))
    assert_true(angle <= angle_tol, '%0.3f > %0.3f deg' % (angle, angle_tol))
def _assert_trans(actual, desired, dist_tol=0.017, angle_tol=5.):
    __tracebackhide__ = True
    trans_est = actual[0:3, 3]
    quat_est = rot_to_quat(actual[0:3, 0:3])
    trans = desired[0:3, 3]
    quat = rot_to_quat(desired[0:3, 0:3])

    angle = np.rad2deg(_angle_between_quats(quat_est, quat))
    dist = np.linalg.norm(trans - trans_est)
    assert dist <= dist_tol, \
        '%0.3f > %0.3f mm translation' % (1000 * dist, 1000 * dist_tol)
    assert angle <= angle_tol, \
        '%0.3f > %0.3f° rotation' % (angle, angle_tol)
Beispiel #14
0
def _assert_quats(actual, desired, dist_tol=0.003, angle_tol=5.):
    """Compare estimated cHPI positions."""
    __tracebackhide__ = True
    trans_est, rot_est, t_est = head_pos_to_trans_rot_t(actual)
    trans, rot, t = head_pos_to_trans_rot_t(desired)
    quats_est = rot_to_quat(rot_est)

    # maxfilter produces some times that are implausibly large (weird)
    if not np.isclose(t[0], t_est[0], atol=1e-1):  # within 100 ms
        raise AssertionError('Start times not within 100 ms: %0.3f != %0.3f'
                             % (t[0], t_est[0]))
    use_mask = (t >= t_est[0]) & (t <= t_est[-1])
    t = t[use_mask]
    trans = trans[use_mask]
    quats = rot_to_quat(rot)
    quats = quats[use_mask]

    # double-check our angle function
    for q in (quats, quats_est):
        angles = _angle_between_quats(q, q)
        assert_allclose(angles, 0., atol=1e-5)

    # limit translation difference between MF and our estimation
    trans_est_interp = interp1d(t_est, trans_est, axis=0)(t)
    distances = np.sqrt(np.sum((trans - trans_est_interp) ** 2, axis=1))
    assert np.isfinite(distances).all()
    arg_worst = np.argmax(distances)
    assert distances[arg_worst] <= dist_tol, (
        '@ %0.3f seconds: %0.3f > %0.3f mm'
        % (t[arg_worst], 1000 * distances[arg_worst], 1000 * dist_tol))

    # limit rotation difference between MF and our estimation
    # (note that the interpolation will make this slightly worse)
    quats_est_interp = interp1d(t_est, quats_est, axis=0)(t)
    angles = 180 * _angle_between_quats(quats_est_interp, quats) / np.pi
    arg_worst = np.argmax(angles)
    assert angles[arg_worst] <= angle_tol, (
        '@ %0.3f seconds: %0.3f > %0.3f deg'
        % (t[arg_worst], angles[arg_worst], angle_tol))
def _assert_quats(actual, desired, dist_tol=0.003, angle_tol=5.):
    """Compare estimated cHPI positions."""
    from scipy.interpolate import interp1d
    trans_est, rot_est, t_est = head_pos_to_trans_rot_t(actual)
    trans, rot, t = head_pos_to_trans_rot_t(desired)
    quats_est = rot_to_quat(rot_est)

    # maxfilter produces some times that are implausibly large (weird)
    if not np.isclose(t[0], t_est[0], atol=1e-1):  # within 100 ms
        raise AssertionError('Start times not within 100 ms: %0.3f != %0.3f'
                             % (t[0], t_est[0]))
    use_mask = (t >= t_est[0]) & (t <= t_est[-1])
    t = t[use_mask]
    trans = trans[use_mask]
    quats = rot_to_quat(rot)
    quats = quats[use_mask]

    # double-check our angle function
    for q in (quats, quats_est):
        angles = _angle_between_quats(q, q)
        assert_allclose(angles, 0., atol=1e-5)

    # limit translation difference between MF and our estimation
    trans_est_interp = interp1d(t_est, trans_est, axis=0)(t)
    distances = np.sqrt(np.sum((trans - trans_est_interp) ** 2, axis=1))
    arg_worst = np.argmax(distances)
    assert_true(distances[arg_worst] <= dist_tol,
                '@ %0.3f seconds: %0.3f > %0.3f mm'
                % (t[arg_worst], 1000 * distances[arg_worst], 1000 * dist_tol))

    # limit rotation difference between MF and our estimation
    # (note that the interpolation will make this slightly worse)
    quats_est_interp = interp1d(t_est, quats_est, axis=0)(t)
    angles = 180 * _angle_between_quats(quats_est_interp, quats) / np.pi
    arg_worst = np.argmax(angles)
    assert_true(angles[arg_worst] <= angle_tol,
                '@ %0.3f seconds: %0.3f > %0.3f deg'
                % (t[arg_worst], angles[arg_worst], angle_tol))
Beispiel #16
0
def test_set_montage_artinis_fsaverage(kind):
    """Test that artinis montages match fsaverage's head<->MRI transform."""
    # Compare OctaMon and Brite23 to fsaverage
    trans_fs, _ = _get_trans('fsaverage')
    montage = make_standard_montage(f'artinis-{kind}')
    trans = compute_native_head_t(montage)
    assert trans['to'] == trans_fs['to']
    assert trans['from'] == trans_fs['from']
    translation = 1000 * np.linalg.norm(trans['trans'][:3, 3] -
                                        trans_fs['trans'][:3, 3])
    assert 0 < translation < 1  # mm
    rotation = np.rad2deg(
        _angle_between_quats(rot_to_quat(trans['trans'][:3, :3]),
                             rot_to_quat(trans_fs['trans'][:3, :3])))
    assert 0 < rotation < 1  # degrees
Beispiel #17
0
def test_initial_fit_redo():
    """Test that initial fits can be redone based on moments."""
    raw = read_raw_fif(chpi_fif_fname, allow_maxshield='yes')
    slopes = np.array(
        [[c['slopes'] for c in raw.info['hpi_meas'][0]['hpi_coils']]])
    amps = np.linalg.norm(slopes, axis=-1)
    amps /= slopes.shape[-1]
    assert_array_less(amps, 5e-11)
    assert_array_less(1e-12, amps)
    proj, _, _ = _setup_ext_proj(raw.info, ext_order=1)
    chpi_amplitudes = dict(times=np.zeros(1), slopes=slopes, proj=proj)
    chpi_locs = compute_chpi_locs(raw.info, chpi_amplitudes)

    # check GOF
    coil_gof = raw.info['hpi_results'][0]['goodness']
    assert_allclose(chpi_locs['gofs'][0], coil_gof, atol=0.3)  # XXX not good

    # check moment
    # XXX our forward and theirs differ by an extra mult by _MAG_FACTOR
    coil_moment = raw.info['hpi_results'][0]['moments'] / _MAG_FACTOR
    py_moment = chpi_locs['moments'][0]
    coil_amp = np.linalg.norm(coil_moment, axis=-1, keepdims=True)
    py_amp = np.linalg.norm(py_moment, axis=-1, keepdims=True)
    assert_allclose(coil_amp, py_amp, rtol=0.2)
    coil_ori = coil_moment / coil_amp
    py_ori = py_moment / py_amp
    angles = np.rad2deg(np.arccos(np.abs(np.sum(coil_ori * py_ori, axis=1))))
    assert_array_less(angles, 20)

    # check resulting dev_head_t
    head_pos = compute_head_pos(raw.info, chpi_locs)
    assert head_pos.shape == (1, 10)
    nm_pos = raw.info['dev_head_t']['trans']
    dist = 1000 * np.linalg.norm(nm_pos[:3, 3] - head_pos[0, 4:7])
    assert 0.1 < dist < 2
    angle = np.rad2deg(
        _angle_between_quats(rot_to_quat(nm_pos[:3, :3]), head_pos[0, 1:4]))
    assert 0.1 < angle < 2
    gof = head_pos[0, 7]
    assert_allclose(gof, 0.9999, atol=1e-4)
def test_quaternions():
    """Test quaternion calculations
    """
    rots = [np.eye(3)]
    for fname in [test_fif_fname, ctf_fname, hp_fif_fname]:
        rots += [read_info(fname)['dev_head_t']['trans'][:3, :3]]
    # nasty numerical cases
    rots += [np.array([
        [-0.99978541, -0.01873462, -0.00898756],
        [-0.01873462, 0.62565561, 0.77987608],
        [-0.00898756, 0.77987608, -0.62587152],
    ])]
    rots += [np.array([
        [0.62565561, -0.01873462, 0.77987608],
        [-0.01873462, -0.99978541, -0.00898756],
        [0.77987608, -0.00898756, -0.62587152],
    ])]
    rots += [np.array([
        [-0.99978541, -0.00898756, -0.01873462],
        [-0.00898756, -0.62587152, 0.77987608],
        [-0.01873462, 0.77987608, 0.62565561],
    ])]
    for rot in rots:
        assert_allclose(rot, quat_to_rot(rot_to_quat(rot)),
                        rtol=1e-5, atol=1e-5)
        rot = rot[np.newaxis, np.newaxis, :, :]
        assert_allclose(rot, quat_to_rot(rot_to_quat(rot)),
                        rtol=1e-5, atol=1e-5)

    # let's make sure our angle function works in some reasonable way
    for ii in range(3):
        for jj in range(3):
            a = np.zeros(3)
            b = np.zeros(3)
            a[ii] = 1.
            b[jj] = 1.
            expected = np.pi if ii != jj else 0.
            assert_allclose(_angle_between_quats(a, b), expected, atol=1e-5)
R = quat_to_rot(Rq)

# translation vectors
T, _ = raw[picks_chpi_t, :]
T = T[:, ind_ok].T

# head origin (see above)
nrot = R.shape[0]
Y = np.zeros((nrot, 3))
A = np.zeros((nrot, 3))
for k in np.arange(nrot):
    Y[k, :] = -np.dot(R[k].T, T[k])

# get rot. angle changes directly from quaternion data
#Rq = lowpass(Rq, raw.info['sfreq'], args.lpcorner, axis=0)
dA = _angle_between_quats(Rq[1:, :], Rq[:-1, :]) / np.pi * 180

# get pos. changes
#Yf = lowpass(Y, raw.info['sfreq'], args.lpcorner, axis=0)
dY = np.diff(Y, axis=0)
dYv = np.sqrt(np.sum(dY**2, axis=1))  # len of movement at each time point
tlen = times_ok[-1] - times_ok[0]

trans_ok_ind = np.where(dYv < MAX_TRANS)[0]
if len(trans_ok_ind) < len(dYv):
    print('Warning: ignoring %d translation steps that are larger '
          'than %g m' % (len(dYv) - len(trans_ok_ind), MAX_TRANS))
rot_ok_ind = np.where(dA < MAX_ROT)[0]
if len(rot_ok_ind) < len(dA):
    print('Warning: ignoring %d rotation steps that are larger '
          'than %g deg' % (len(dA) - len(rot_ok_ind), MAX_ROT))
Beispiel #20
0
def test_coregistration(scale_mode, ref_scale, grow_hair, fiducials,
                        fid_match):
    """Test automated coregistration."""
    subject = 'sample'
    if fiducials is None:
        fiducials, coord_frame = read_fiducials(fid_fname)
        assert coord_frame == FIFF.FIFFV_COORD_MRI
    info = read_info(raw_fname)
    for d in info['dig']:
        d['r'] = d['r'] * ref_scale
    trans = read_trans(trans_fname)
    coreg = Coregistration(info,
                           subject=subject,
                           subjects_dir=subjects_dir,
                           fiducials=fiducials)
    assert np.allclose(coreg._last_parameters, coreg._parameters)
    coreg.set_fid_match(fid_match)
    default_params = list(coreg._default_parameters)
    coreg.set_rotation(default_params[:3])
    coreg.set_translation(default_params[3:6])
    coreg.set_scale(default_params[6:9])
    coreg.set_grow_hair(grow_hair)
    coreg.set_scale_mode(scale_mode)
    # Identity transform
    errs_id = coreg.compute_dig_mri_distances()
    is_scaled = ref_scale != [1., 1., 1.]
    id_max = 0.03 if is_scaled and scale_mode == '3-axis' else 0.02
    assert 0.005 < np.median(errs_id) < id_max
    # Fiducial transform + scale
    coreg.fit_fiducials(verbose=True)
    assert coreg._extra_points_filter is None
    coreg.omit_head_shape_points(distance=0.02)
    assert coreg._extra_points_filter is not None
    errs_fid = coreg.compute_dig_mri_distances()
    assert_array_less(0, errs_fid)
    if is_scaled or scale_mode is not None:
        fid_max = 0.05
        fid_med = 0.02
    else:
        fid_max = 0.03
        fid_med = 0.01
    assert_array_less(errs_fid, fid_max)
    assert 0.001 < np.median(errs_fid) < fid_med
    assert not np.allclose(coreg._parameters, default_params)
    coreg.omit_head_shape_points(distance=-1)
    coreg.omit_head_shape_points(distance=5. / 1000)
    assert coreg._extra_points_filter is not None
    # ICP transform + scale
    coreg.fit_icp(verbose=True)
    assert isinstance(coreg.trans, Transform)
    errs_icp = coreg.compute_dig_mri_distances()
    assert_array_less(0, errs_icp)
    if is_scaled or scale_mode == '3-axis':
        icp_max = 0.015
    else:
        icp_max = 0.01
    assert_array_less(errs_icp, icp_max)
    assert 0.001 < np.median(errs_icp) < 0.004
    assert np.rad2deg(
        _angle_between_quats(rot_to_quat(coreg.trans['trans'][:3, :3]),
                             rot_to_quat(trans['trans'][:3, :3]))) < 13
    if scale_mode is None:
        atol = 1e-7
    else:
        atol = 0.35
    assert_allclose(coreg._scale, ref_scale, atol=atol)
    coreg.reset()
    assert_allclose(coreg._parameters, default_params)
Beispiel #21
0
def test_compute_fine_cal():
    """Test computing fine calibration coefficients."""
    raw = read_raw_fif(erm_fname)
    want_cal = read_fine_calibration(cal_mf_fname)
    got_cal, counts = compute_fine_calibration(raw,
                                               cross_talk=ctc,
                                               n_imbalance=1,
                                               verbose='debug')
    assert counts == 1
    assert set(got_cal.keys()) == set(want_cal.keys())
    assert got_cal['ch_names'] == want_cal['ch_names']
    # in practice these should never be exactly 1.
    assert sum([(ic == 1.).any() for ic in want_cal['imb_cals']]) == 0
    assert sum([(ic == 1.).any() for ic in got_cal['imb_cals']]) == 0

    got_imb = np.array(got_cal['imb_cals'], float)
    want_imb = np.array(want_cal['imb_cals'], float)
    assert got_imb.shape == want_imb.shape == (306, 1)
    got_imb, want_imb = got_imb[:, 0], want_imb[:, 0]

    orig_locs = np.array([ch['loc'] for ch in raw.info['chs'][:306]])
    want_locs = want_cal['locs']
    got_locs = got_cal['locs']
    assert want_locs.shape == got_locs.shape

    orig_trans = _loc_to_coil_trans(orig_locs)
    want_trans = _loc_to_coil_trans(want_locs)
    got_trans = _loc_to_coil_trans(got_locs)
    dist = np.linalg.norm(got_trans[:, :3, 3] - want_trans[:, :3, 3], axis=1)
    assert_allclose(dist, 0., atol=1e-6)
    dist = np.linalg.norm(got_trans[:, :3, 3] - orig_trans[:, :3, 3], axis=1)
    assert_allclose(dist, 0., atol=1e-6)
    orig_quat = rot_to_quat(orig_trans[:, :3, :3])
    want_quat = rot_to_quat(want_trans[:, :3, :3])
    got_quat = rot_to_quat(got_trans[:, :3, :3])
    want_orig_angles = np.rad2deg(_angle_between_quats(want_quat, orig_quat))
    got_want_angles = np.rad2deg(_angle_between_quats(got_quat, want_quat))
    got_orig_angles = np.rad2deg(_angle_between_quats(got_quat, orig_quat))
    for key in ('mag', 'grad'):
        # imb_cals value
        p = pick_types(raw.info, meg=key, exclude=())
        r2 = np.dot(got_imb[p], want_imb[p]) / (np.linalg.norm(want_imb[p]) *
                                                np.linalg.norm(got_imb[p]))
        assert 0.99 < r2 <= 1.00001, f'{key}: {r2:0.3f}'
        # rotation angles
        want_orig_max_angle = want_orig_angles[p].max()
        got_orig_max_angle = got_orig_angles[p].max()
        got_want_max_angle = got_want_angles[p].max()
        if key == 'mag':
            assert 8 < want_orig_max_angle < 11, want_orig_max_angle
            assert 1 < got_orig_max_angle < 2, got_orig_max_angle
            assert 9 < got_want_max_angle < 11, got_want_max_angle
        else:
            # Some of these angles are large, but mostly this has to do with
            # processing a very short (one 10-sec segment), downsampled (90 Hz)
            # file
            assert 66 < want_orig_max_angle < 68, want_orig_max_angle
            assert 67 < got_orig_max_angle < 107, got_orig_max_angle
            assert 53 < got_want_max_angle < 60, got_want_max_angle

    kwargs = dict(bad_condition='warning', cross_talk=ctc, coord_frame='meg')
    raw_sss = maxwell_filter(raw, **kwargs)
    raw_sss_mf = maxwell_filter(raw, calibration=cal_mf_fname, **kwargs)
    raw_sss_py = maxwell_filter(raw, calibration=got_cal, **kwargs)
    _assert_shielding(raw_sss, raw, 26, 27)
    _assert_shielding(raw_sss_mf, raw, 61, 63)
    _assert_shielding(raw_sss_py, raw, 61, 63)

    # redoing with given mag data should yield same result
    got_cal_redo, _ = compute_fine_calibration(raw,
                                               cross_talk=ctc,
                                               n_imbalance=1,
                                               calibration=got_cal,
                                               verbose='debug')
    assert got_cal['ch_names'] == got_cal_redo['ch_names']
    assert_allclose(got_cal['imb_cals'], got_cal_redo['imb_cals'], atol=5e-5)
    assert_allclose(got_cal['locs'], got_cal_redo['locs'], atol=1e-6)
    assert sum([(ic == 1.).any() for ic in got_cal['imb_cals']]) == 0

    # redoing with 3 imlabance parameters should improve the shielding factor
    grad_picks = pick_types(raw.info, meg='grad')
    assert len(grad_picks) == 204 and grad_picks[0] == 0
    got_grad_imbs = np.array(
        [got_cal['imb_cals'][pick] for pick in grad_picks])
    assert got_grad_imbs.shape == (204, 1)
    got_cal_3, _ = compute_fine_calibration(raw,
                                            cross_talk=ctc,
                                            n_imbalance=3,
                                            calibration=got_cal,
                                            verbose='debug')
    got_grad_3_imbs = np.array(
        [got_cal_3['imb_cals'][pick] for pick in grad_picks])
    assert got_grad_3_imbs.shape == (204, 3)
    corr = np.corrcoef(got_grad_3_imbs[:, 0], got_grad_imbs[:, 0])[0, 1]
    assert 0.6 < corr < 0.7
    raw_sss_py = maxwell_filter(raw, calibration=got_cal_3, **kwargs)
    _assert_shielding(raw_sss_py, raw, 68, 70)
R = quat_to_rot(Rq)

# translation vectors
T, _ = raw[picks_chpi_t, :]
T = T[:, ind_ok].T

# head origin (see above)
nrot = R.shape[0]
Y = np.zeros((nrot, 3))
A = np.zeros((nrot, 3))
for k in np.arange(nrot):
    Y[k, :] = -np.dot(R[k].T, T[k])

# get rot. angle changes directly from quaternion data
#Rq = lowpass(Rq, raw.info['sfreq'], args.lpcorner, axis=0)
dA = _angle_between_quats(Rq[1:, :], Rq[:-1, :]) / np.pi * 180

# get pos. changes
#Yf = lowpass(Y, raw.info['sfreq'], args.lpcorner, axis=0)
dY = np.diff(Y, axis=0)
dYv = np.sqrt(np.sum(dY**2, axis=1))  # len of movement at each time point
tlen = times_ok[-1] - times_ok[0]

trans_ok_ind = np.where(dYv < MAX_TRANS)[0]
if len(trans_ok_ind) < len(dYv):
    print('Warning: ignoring %d translation steps that are larger '
          'than %g m' % (len(dYv) - len(trans_ok_ind), MAX_TRANS))
rot_ok_ind = np.where(dA < MAX_ROT)[0]
if len(rot_ok_ind) < len(dA):
    print('Warning: ignoring %d rotation steps that are larger '
          'than %g deg' % (len(dA) - len(rot_ok_ind), MAX_ROT))