Exemplo n.º 1
0
def get_data():

    #dname = '/home/eleftherios/Data/Test_data_Jasmeen/Elef_Test_RecoBundles/'
    dname = '/home/eleftherios/Data/Elef_Test_RecoBundles/'
    fname = dname + 'tracts.trk'
    fname_npz = dname + 'tracts.npz'

    streamlines = nib.streamlines.compact_list.load_compact_list(fname_npz)

    streamlines = streamlines[::10].copy()
    streamlines._data -= np.mean(streamlines._data, axis=0)

    # Rotate brain to see a sagital view.
    R1 = np.eye(4)
    R1[:3, :3] = rodrigues_axis_rotation((0, 1, 0), theta=90)
    R2 = np.eye(4)
    R2[:3, :3] = rodrigues_axis_rotation((0, 0, 1), theta=90)
    R = np.dot(R2, R1)
    streamlines._data = apply_affine(R, streamlines._data)

#    renderer = window.Renderer()
#    bundle_actor = actor.line(streamlines)
#    renderer.add(bundle_actor)
#    window.show(renderer)

    return streamlines
Exemplo n.º 2
0
def calc_euler(evecs):
    """
    Calculate the Euler angles that rotate from the canonical coordinate frame
    to a coordinate frame defined by a set of eigenvectors.

    Parameters
    ----------
    evecs : 3-by-3 array

    """
    rot0 = np.eye(4)
    # What is the rotation from the first eigenvector to eye(3)?
    rot0[:3, :3] = vec2vec_rotmat(evecs[0], np.eye(3)[0])
    # Decompose (we only need the angles)
    scale, shear, angles0, translate, perspective = decompose_matrix(rot0)
    # Convert angles to Euler matrix:
    em = euler_matrix(*angles0)
    # Now, we need another rotation to bring the second eigenvector to the right
    # direction
    ang1 = np.arccos(
        np.dot(evecs[1], em[1, :3]) /
        (np.linalg.norm(evecs[1]) * np.linalg.norm(em[1, :3])))
    rar = np.eye(4)
    # The rar is a matrix that rotates for a given angle around a given
    # vector:
    rar[:3, :3] = rodrigues_axis_rotation(evecs[0], np.rad2deg(ang1))
    # We combine these two rotations and decompose the combined matrix to give
    # us three Euler angles, which will be our parameters
    scale, shear, angles, translate, perspective = decompose_matrix(em @ rar)
    return angles
Exemplo n.º 3
0
def create_affine_transforms(dim,
                             translations,
                             rotations,
                             scales,
                             rot_axis=None):
    r""" Creates a list of affine transforms with all combinations of params

    This function is intended to be used for testing only. It generates
    affine transforms for all combinations of the input parameters in the
    following order: let T be a translation, R a rotation and S a scale. The
    generated affine will be:

    A = T.dot(S).dot(R).dot(T^{-1})

    Translation is handled this way because it is convenient to provide
    the translation parameters in terms of the center of rotation we wish
    to generate.

    Parameters
    ----------
    dim: int (either dim=2 or dim=3)
        dimension of the affine transforms
    translations: sequence of dim-tuples
        each dim-tuple represents a translation parameter
    rotations: sequence of floats
        each number represents a rotation angle in radians
    scales: sequence of floats
        each number represents a scale
    rot_axis: rotation axis (used for dim=3 only)

    Returns
    -------
    transforms: sequence of (dim + 1)x(dim + 1) matrices
        each matrix correspond to an affine transform with a combination
        of the input parameters
    """
    transforms = []
    for t in translations:
        trans_inv = np.eye(dim + 1)
        trans_inv[:dim, dim] = -t[:dim]
        trans = npl.inv(trans_inv)
        for theta in rotations:  # rotation angle
            if dim == 2:
                ct = np.cos(theta)
                st = np.sin(theta)
                rot = np.array([[ct, -st, 0], [st, ct, 0], [0, 0, 1]])
            else:
                rot = np.eye(dim + 1)
                rot[:3, :3] = geometry.rodrigues_axis_rotation(rot_axis, theta)

            for s in scales:  # scale
                scale = np.eye(dim + 1) * s
                scale[dim, dim] = 1

            affine = trans.dot(scale.dot(rot.dot(trans_inv)))
            transforms.append(affine)
    return transforms
Exemplo n.º 4
0
def create_affine_transforms(
        dim, translations, rotations, scales, rot_axis=None):
    r""" Creates a list of affine transforms with all combinations of params

    This function is intended to be used for testing only. It generates
    affine transforms for all combinations of the input parameters in the
    following order: let T be a translation, R a rotation and S a scale. The
    generated affine will be:

    A = T.dot(S).dot(R).dot(T^{-1})

    Translation is handled this way because it is convenient to provide
    the translation parameters in terms of the center of rotation we wish
    to generate.

    Parameters
    ----------
    dim: int (either dim=2 or dim=3)
        dimension of the affine transforms
    translations: sequence of dim-tuples
        each dim-tuple represents a translation parameter
    rotations: sequence of floats
        each number represents a rotation angle in radians
    scales: sequence of floats
        each number represents a scale
    rot_axis: rotation axis (used for dim=3 only)

    Returns
    -------
    transforms: sequence of (dim + 1)x(dim + 1) matrices
        each matrix correspond to an affine transform with a combination
        of the input parameters
    """
    transforms = []
    for t in translations:
        trans_inv = np.eye(dim + 1)
        trans_inv[:dim, dim] = -t[:dim]
        trans = npl.inv(trans_inv)
        for theta in rotations:  # rotation angle
            if dim == 2:
                ct = np.cos(theta)
                st = np.sin(theta)
                rot = np.array([[ct, -st, 0],
                                [st, ct, 0],
                                [0, 0, 1]])
            else:
                rot = np.eye(dim + 1)
                rot[:3, :3] = geometry.rodrigues_axis_rotation(rot_axis, theta)

            for s in scales:  # scale
                scale = np.eye(dim + 1) * s
                scale[dim, dim] = 1

            affine = trans.dot(scale.dot(rot.dot(trans_inv)))
            transforms.append(affine)
    return transforms
Exemplo n.º 5
0
def test_transform_centers_of_mass_3d():
    np.random.seed(1246592)
    shape = (64, 64, 64)
    rm = 8
    sp = vf.create_sphere(shape[0] // 2, shape[1] // 2, shape[2] // 2, rm)
    moving = np.zeros(shape)
    # The center of mass will be (16, 16, 16), in image coordinates
    moving[:shape[0] // 2, :shape[1] // 2, :shape[2] // 2] = sp[...]

    rs = 16
    # The center of mass will be (32, 32, 32), in image coordinates
    static = vf.create_sphere(shape[0], shape[1], shape[2], rs)

    # Create arbitrary image-to-space transforms
    axis = np.array([.5, 2.0, 1.5])
    t = 0.15  # translation factor
    trans = np.array([[1, 0, 0, -t * shape[0]],
                      [0, 1, 0, -t * shape[1]],
                      [0, 0, 1, -t * shape[2]],
                      [0, 0, 0, 1]])
    trans_inv = npl.inv(trans)

    for rotation_angle in [-1 * np.pi / 6.0, 0.0, np.pi / 5.0]:
        for scale_factor in [0.83, 1.3, 2.07]:  # scale
            rot = np.zeros(shape=(4, 4))
            rot[:3, :3] = geometry.rodrigues_axis_rotation(axis,
                                                           rotation_angle)
            rot[3, 3] = 1.0
            scale = np.array([[1 * scale_factor, 0, 0, 0],
                              [0, 1 * scale_factor, 0, 0],
                              [0, 0, 1 * scale_factor, 0],
                              [0, 0, 0, 1]])

            static_grid2world = trans_inv.dot(scale.dot(rot.dot(trans)))
            moving_grid2world = npl.inv(static_grid2world)

            # Expected translation
            c_static = static_grid2world.dot((32, 32, 32, 1))[:3]
            c_moving = moving_grid2world.dot((16, 16, 16, 1))[:3]
            expected = np.eye(4)
            expected[:3, 3] = c_moving - c_static

            # Implementation under test
            actual = imaffine.transform_centers_of_mass(static,
                                                        static_grid2world,
                                                        moving,
                                                        moving_grid2world)
            assert_array_almost_equal(actual.affine, expected)
Exemplo n.º 6
0
def test_transform_centers_of_mass_3d():
    np.random.seed(1246592)
    shape = (64, 64, 64)
    rm = 8
    sp = vf.create_sphere(shape[0] // 2, shape[1] // 2, shape[2] // 2, rm)
    moving = np.zeros(shape)
    # The center of mass will be (16, 16, 16), in image coordinates
    moving[:shape[0] // 2, :shape[1] // 2, :shape[2] // 2] = sp[...]

    rs = 16
    # The center of mass will be (32, 32, 32), in image coordinates
    static = vf.create_sphere(shape[0], shape[1], shape[2], rs)

    # Create arbitrary image-to-space transforms
    axis = np.array([.5, 2.0, 1.5])
    t = 0.15  # translation factor
    trans = np.array([[1, 0, 0, -t * shape[0]],
                      [0, 1, 0, -t * shape[1]],
                      [0, 0, 1, -t * shape[2]],
                      [0, 0, 0, 1]])
    trans_inv = npl.inv(trans)

    for rotation_angle in [-1 * np.pi / 6.0, 0.0, np.pi / 5.0]:
        for scale_factor in [0.83, 1.3, 2.07]:  # scale
            rot = np.zeros(shape=(4, 4))
            rot[:3, :3] = geometry.rodrigues_axis_rotation(axis,
                                                           rotation_angle)
            rot[3, 3] = 1.0
            scale = np.array([[1 * scale_factor, 0, 0, 0],
                              [0, 1 * scale_factor, 0, 0],
                              [0, 0, 1 * scale_factor, 0],
                              [0, 0, 0, 1]])

            static_grid2world = trans_inv.dot(scale.dot(rot.dot(trans)))
            moving_grid2world = npl.inv(static_grid2world)

            # Expected translation
            c_static = static_grid2world.dot((32, 32, 32, 1))[:3]
            c_moving = moving_grid2world.dot((16, 16, 16, 1))[:3]
            expected = np.eye(4)
            expected[:3, 3] = c_moving - c_static

            # Implementation under test
            actual = imaffine.transform_centers_of_mass(static,
                                                        static_grid2world,
                                                        moving,
                                                        moving_grid2world)
            assert_array_almost_equal(actual.affine, expected)
Exemplo n.º 7
0
def test_transform_geometric_centers_3d():
    # Create arbitrary image-to-space transforms
    axis = np.array([.5, 2.0, 1.5])
    t = 0.15  # translation factor

    for theta in [-1 * np.pi / 6.0, 0.0, np.pi / 5.0]:  # rotation angle
        for s in [0.83, 1.3, 2.07]:  # scale
            m_shapes = [(256, 256, 128), (255, 255, 127), (64, 127, 142)]
            for shape_moving in m_shapes:
                s_shapes = [(256, 256, 128), (255, 255, 127), (64, 127, 142)]
                for shape_static in s_shapes:
                    moving = np.ndarray(shape=shape_moving)
                    static = np.ndarray(shape=shape_static)
                    trans = np.array([[1, 0, 0, -t * shape_static[0]],
                                      [0, 1, 0, -t * shape_static[1]],
                                      [0, 0, 1, -t * shape_static[2]],
                                      [0, 0, 0, 1]])
                    trans_inv = npl.inv(trans)
                    rot = np.zeros(shape=(4, 4))
                    rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
                    rot[3, 3] = 1.0
                    scale = np.array([[1 * s, 0, 0, 0],
                                      [0, 1 * s, 0, 0],
                                      [0, 0, 1 * s, 0],
                                      [0, 0, 0, 1]])

                    static_grid2world = trans_inv.dot(
                        scale.dot(rot.dot(trans)))
                    moving_grid2world = npl.inv(static_grid2world)

                    # Expected translation
                    c_static = np.array(shape_static, dtype=np.float64) * 0.5
                    c_static = tuple(c_static)
                    c_static = static_grid2world.dot(c_static + (1,))[:3]
                    c_moving = np.array(shape_moving, dtype=np.float64) * 0.5
                    c_moving = tuple(c_moving)
                    c_moving = moving_grid2world.dot(c_moving + (1,))[:3]
                    expected = np.eye(4)
                    expected[:3, 3] = c_moving - c_static

                    # Implementation under test
                    actual = imaffine.transform_geometric_centers(
                        static, static_grid2world, moving, moving_grid2world)
                    assert_array_almost_equal(actual.affine, expected)
Exemplo n.º 8
0
def test_transform_geometric_centers_3d():
    # Create arbitrary image-to-space transforms
    axis = np.array([.5, 2.0, 1.5])
    t = 0.15  # translation factor

    for theta in [-1 * np.pi / 6.0, 0.0, np.pi / 5.0]:  # rotation angle
        for s in [0.83, 1.3, 2.07]:  # scale
            m_shapes = [(256, 256, 128), (255, 255, 127), (64, 127, 142)]
            for shape_moving in m_shapes:
                s_shapes = [(256, 256, 128), (255, 255, 127), (64, 127, 142)]
                for shape_static in s_shapes:
                    moving = np.ndarray(shape=shape_moving)
                    static = np.ndarray(shape=shape_static)
                    trans = np.array([[1, 0, 0, -t * shape_static[0]],
                                      [0, 1, 0, -t * shape_static[1]],
                                      [0, 0, 1, -t * shape_static[2]],
                                      [0, 0, 0, 1]])
                    trans_inv = npl.inv(trans)
                    rot = np.zeros(shape=(4, 4))
                    rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
                    rot[3, 3] = 1.0
                    scale = np.array([[1 * s, 0, 0, 0],
                                      [0, 1 * s, 0, 0],
                                      [0, 0, 1 * s, 0],
                                      [0, 0, 0, 1]])

                    static_grid2world = trans_inv.dot(
                        scale.dot(rot.dot(trans)))
                    moving_grid2world = npl.inv(static_grid2world)

                    # Expected translation
                    c_static = np.array(shape_static, dtype=np.float64) * 0.5
                    c_static = tuple(c_static)
                    c_static = static_grid2world.dot(c_static + (1,))[:3]
                    c_moving = np.array(shape_moving, dtype=np.float64) * 0.5
                    c_moving = tuple(c_moving)
                    c_moving = moving_grid2world.dot(c_moving + (1,))[:3]
                    expected = np.eye(4)
                    expected[:3, 3] = c_moving - c_static

                    # Implementation under test
                    actual = imaffine.transform_geometric_centers(
                        static, static_grid2world, moving, moving_grid2world)
                    assert_array_almost_equal(actual.affine, expected)
Exemplo n.º 9
0
def test_metric_minimum_average_direct_flip():
    feature = dipymetric.IdentityFeature()

    class MinimumAverageDirectFlipMetric(dipymetric.Metric):
        def __init__(self, feature):
            super(MinimumAverageDirectFlipMetric, self).__init__(feature=feature)

        @property
        def is_order_invariant(self):
            return True  # Ordering is handled in the distance computation

        def are_compatible(self, shape1, shape2):
            return shape1[0] == shape2[0]

        def dist(self, v1, v2):
            average_euclidean = lambda x, y: np.mean(norm(x-y, axis=1))
            dist_direct = average_euclidean(v1, v2)
            dist_flipped = average_euclidean(v1, v2[::-1])
            return min(dist_direct, dist_flipped)

    for metric in [MinimumAverageDirectFlipMetric(feature),
                   dipymetric.MinimumAverageDirectFlipMetric(feature)]:

        # Test special cases of the MDF distance.
        assert_equal(metric.dist(s, s), 0.)
        assert_equal(metric.dist(s, s[::-1]), 0.)

        # Translation
        offset = np.array([0.8, 1.3, 5], dtype=dtype)
        assert_almost_equal(metric.dist(s, s+offset), norm(offset), 5)

        # Scaling
        M_scaling = np.diag([1.2, 2.8, 3]).astype(dtype)
        s_mean = np.mean(s, axis=0)
        s_zero_mean = s - s_mean
        s_scaled = np.dot(M_scaling, s_zero_mean.T).T + s_mean
        d = np.mean(norm((np.diag(M_scaling)-1)*s_zero_mean, axis=1))
        assert_almost_equal(metric.dist(s, s_scaled), d, 5)

        # Rotation
        from dipy.core.geometry import rodrigues_axis_rotation
        rot_axis = np.array([1, 2, 3], dtype=dtype)
        M_rotation = rodrigues_axis_rotation(rot_axis, 60.).astype(dtype)
        s_mean = np.mean(s, axis=0)
        s_zero_mean = s - s_mean
        s_rotated = np.dot(M_rotation, s_zero_mean.T).T + s_mean

        opposite = norm(np.cross(rot_axis, s_zero_mean), axis=1) / norm(rot_axis)
        distances = np.sqrt(2*opposite**2 * (1 - np.cos(60.*np.pi/180.))).astype(dtype)
        d = np.mean(distances)
        assert_almost_equal(metric.dist(s, s_rotated), d, 5)

        for s1, s2 in itertools.product(*[streamlines]*2):  # All possible pairs
            # Extract features since metric doesn't work directly on streamlines
            f1 = metric.feature.extract(s1)
            f2 = metric.feature.extract(s2)

            # Test method are_compatible
            same_nb_points = f1.shape[0] == f2.shape[0]
            assert_equal(metric.are_compatible(f1.shape, f2.shape), same_nb_points)

            # Test method dist if features are compatible
            if metric.are_compatible(f1.shape, f2.shape):
                distance = metric.dist(f1, f2)
                if np.all(f1 == f2):
                    assert_equal(distance, 0.)

                assert_almost_equal(distance, dipymetric.dist(metric, s1, s2))
                assert_almost_equal(distance, dipymetric.mdf(s1, s2))
                assert_true(distance >= 0.)

        # This metric type is order invariant
        assert_true(metric.is_order_invariant)
        for s1, s2 in itertools.product(*[streamlines]*2):  # All possible pairs
            f1 = metric.feature.extract(s1)
            f2 = metric.feature.extract(s2)

            if not metric.are_compatible(f1.shape, f2.shape):
                continue

            f1_flip = metric.feature.extract(s1[::-1])
            f2_flip = metric.feature.extract(s2[::-1])

            distance = metric.dist(f1, f2)
            assert_almost_equal(metric.dist(f1_flip, f2_flip), distance)

            if not np.all(f1_flip == f2_flip):
                assert_true(np.allclose(metric.dist(f1, f2_flip), distance))
                assert_true(np.allclose(metric.dist(f1_flip, f2), distance))
Exemplo n.º 10
0
def test_metric_minimum_average_direct_flip():
    feature = dipymetric.IdentityFeature()

    class MinimumAverageDirectFlipMetric(dipymetric.Metric):
        def __init__(self, feature):
            super(MinimumAverageDirectFlipMetric,
                  self).__init__(feature=feature)

        @property
        def is_order_invariant(self):
            return True  # Ordering is handled in the distance computation

        def are_compatible(self, shape1, shape2):
            return shape1[0] == shape2[0]

        def dist(self, v1, v2):
            def average_euclidean(x, y):
                return np.mean(norm(x - y, axis=1))

            dist_direct = average_euclidean(v1, v2)
            dist_flipped = average_euclidean(v1, v2[::-1])
            return min(dist_direct, dist_flipped)

    for metric in [
            MinimumAverageDirectFlipMetric(feature),
            dipymetric.MinimumAverageDirectFlipMetric(feature)
    ]:

        # Test special cases of the MDF distance.
        assert_equal(metric.dist(s, s), 0.)
        assert_equal(metric.dist(s, s[::-1]), 0.)

        # Translation
        offset = np.array([0.8, 1.3, 5], dtype=dtype)
        assert_almost_equal(metric.dist(s, s + offset), norm(offset), 5)

        # Scaling
        M_scaling = np.diag([1.2, 2.8, 3]).astype(dtype)
        s_mean = np.mean(s, axis=0)
        s_zero_mean = s - s_mean
        s_scaled = np.dot(M_scaling, s_zero_mean.T).T + s_mean
        d = np.mean(norm((np.diag(M_scaling) - 1) * s_zero_mean, axis=1))
        assert_almost_equal(metric.dist(s, s_scaled), d, 5)

        # Rotation
        from dipy.core.geometry import rodrigues_axis_rotation
        rot_axis = np.array([1, 2, 3], dtype=dtype)
        M_rotation = rodrigues_axis_rotation(rot_axis, 60.).astype(dtype)
        s_mean = np.mean(s, axis=0)
        s_zero_mean = s - s_mean
        s_rotated = np.dot(M_rotation, s_zero_mean.T).T + s_mean

        opposite = norm(np.cross(rot_axis, s_zero_mean),
                        axis=1) / norm(rot_axis)
        distances = np.sqrt(2 * opposite**2 *
                            (1 - np.cos(60. * np.pi / 180.))).astype(dtype)
        d = np.mean(distances)
        assert_almost_equal(metric.dist(s, s_rotated), d, 5)

        # All possible pairs
        for s1, s2 in itertools.product(*[streamlines] * 2):
            # Extract features since metric doesn't work
            # directly on streamlines
            f1 = metric.feature.extract(s1)
            f2 = metric.feature.extract(s2)

            # Test method are_compatible
            same_nb_points = f1.shape[0] == f2.shape[0]
            assert_equal(metric.are_compatible(f1.shape, f2.shape),
                         same_nb_points)

            # Test method dist if features are compatible
            if metric.are_compatible(f1.shape, f2.shape):
                distance = metric.dist(f1, f2)
                if np.all(f1 == f2):
                    assert_equal(distance, 0.)

                assert_almost_equal(distance, dipymetric.dist(metric, s1, s2))
                assert_almost_equal(distance, dipymetric.mdf(s1, s2))
                assert_true(distance >= 0.)

        # This metric type is order invariant
        assert_true(metric.is_order_invariant)
        # All possible pairs
        for s1, s2 in itertools.product(*[streamlines] * 2):
            f1 = metric.feature.extract(s1)
            f2 = metric.feature.extract(s2)

            if not metric.are_compatible(f1.shape, f2.shape):
                continue

            f1_flip = metric.feature.extract(s1[::-1])
            f2_flip = metric.feature.extract(s2[::-1])

            distance = metric.dist(f1, f2)
            assert_almost_equal(metric.dist(f1_flip, f2_flip), distance)

            if not np.all(f1_flip == f2_flip):
                assert_true(np.allclose(metric.dist(f1, f2_flip), distance))
                assert_true(np.allclose(metric.dist(f1_flip, f2), distance))
Exemplo n.º 11
0
X[2, ...] = x_2[None, None, :] * O
X[3, ...] = 1

# Select an arbitrary rotation axis
axis = np.array([.5, 2.0, 1.5])
# Select an arbitrary translation matrix
t = 0.1
trans = np.array([[1, 0, 0, -t * ns], [0, 1, 0, -t * nr], [0, 0, 1, -t * nc],
                  [0, 0, 0, 1]])
trans_inv = np.linalg.inv(trans)

# Select arbitrary rotation and scaling matrices
theta = np.pi / 5.0  # rotation angle
s = 1.1  # scale
rot = np.zeros(shape=(4, 4))
rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
rot[3, 3] = 1.0

scale = np.array([[1 * s, 0, 0, 0], [0, 1 * s, 0, 0], [0, 0, 1 * s, 0],
                  [0, 0, 0, 1]])

aff = trans_inv.dot(scale.dot(rot.dot(trans)))

# Select arbitrary (but different) grid-to-space transforms
sampling_grid2world = scale
field_grid2world = aff
field_world2grid = np.linalg.inv(field_grid2world)
image_grid2world = aff.dot(scale)
image_world2grid = np.linalg.inv(image_grid2world)

A = field_world2grid.dot(sampling_grid2world)
Exemplo n.º 12
0
def test_invert_vector_field(shape):
    r"""
    Inverts a synthetic, analytically invertible, displacement field
    """
    ndim = len(shape)
    if ndim == 3:
        ns = shape[0]
        nr = shape[1]
        nc = shape[2]

        # Create an arbitrary image-to-space transform

        # Select an arbitrary rotation axis
        axis = np.array([2.0, 0.5, 1.0])
        t = 2.5  # translation factor

        trans = np.array([
            [1, 0, 0, -t * ns],
            [0, 1, 0, -t * nr],
            [0, 0, 1, -t * nc],
            [0, 0, 0, 1],
        ])
        dipy_create_func = vfu.create_harmonic_fields_3d
        dipy_reorient_func = vfu.reorient_vector_field_3d
        dipy_invert_func = vfu.invert_vector_field_fixed_point_3d
    elif ndim == 2:
        nr = shape[0]
        nc = shape[1]
        # Create an arbitrary image-to-space transform
        t = 2.5  # translation factor

        trans = np.array([[1, 0, -t * nr], [0, 1, -t * nc], [0, 0, 1]])
        dipy_create_func = vfu.create_harmonic_fields_2d
        dipy_reorient_func = vfu.reorient_vector_field_2d
        dipy_invert_func = vfu.invert_vector_field_fixed_point_2d

    trans_inv = np.linalg.inv(trans)

    d, _ = dipy_create_func(*shape, 0.2, 8)
    d = np.asarray(d).astype(floating)

    for theta in [-1 * np.pi / 5.0, 0.0, np.pi / 5.0]:  # rotation angle
        for s in [0.5, 1.0, 2.0]:  # scale
            if ndim == 3:
                rot = np.zeros(shape=(4, 4))
                rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
                rot[3, 3] = 1.0
                scale = np.array([
                    [1 * s, 0, 0, 0],
                    [0, 1 * s, 0, 0],
                    [0, 0, 1 * s, 0],
                    [0, 0, 0, 1],
                ])
            elif ndim == 2:
                ct = np.cos(theta)
                st = np.sin(theta)

                rot = np.array([[ct, -st, 0], [st, ct, 0], [0, 0, 1]])

                scale = np.array([[1 * s, 0, 0], [0, 1 * s, 0], [0, 0, 1]])

            gt_affine = trans_inv.dot(scale.dot(rot.dot(trans)))
            gt_affine_inv = np.linalg.inv(gt_affine)
            dcopy = np.copy(d)

            dcopyd = cupy.asarray(dcopy)
            gt_affined = cupy.asarray(gt_affine)
            gt_affine_invd = cupy.asarray(gt_affine_inv)

            # make sure the field remains invertible after the re-mapping
            dipy_reorient_func(dcopy, gt_affine)

            # TODO: can't do in-place computation unless out= is supplied and
            #       dcopy has the dimensions axis first instead of last
            dcopyd = reorient_vector_field(dcopyd, gt_affined)
            cupy.testing.assert_array_almost_equal(dcopyd, dcopy, decimal=4)

            # Note: the spacings are used just to check convergence, so they
            # don't need to be very accurate. Here we are passing (0.5 * s) to
            # force the algorithm to make more iterations: in ANTS, there is a
            # hard-coded bound on the maximum residual, that's why we cannot
            # force more iteration by changing the parameters.
            # We will investigate this issue with more detail in the future.

            if False:
                from cupyx.time import repeat

                perf = repeat(
                    invert_vector_field_fixed_point,
                    (
                        dcopyd,
                        gt_affine_invd,
                        cupy.asarray([s, s, s]) * 0.5,
                        40,
                        1e-7,
                    ),
                    n_warmup=20,
                    n_repeat=80,
                )
                print(perf)
                perf = repeat(
                    dipy_invert_func,
                    (
                        dcopy,
                        gt_affine_inv,
                        np.asarray([s, s, s]) * 0.5,
                        40,
                        1e-7,
                    ),
                    n_warmup=0,
                    n_repeat=8,
                )
                print(perf)
            # if False:
            #     from pyvolplot import volshow
            #     from matplotlib import pyplot as plt
            #     inv_approx, q, norms, tmp1, tmp2, epsilon, maxlen = vfu.invert_vector_field_fixed_point_3d_debug(
            #         dcopy, gt_affine_inv, np.array([s, s, s]) * 0.5, max_iter=1, tol=1e-7
            #     )
            #     inv_approxd, qd, normsd, tmp1d, tmp2d, epsilond, maxlend = invert_vector_field_fixed_point(
            #         dcopyd, gt_affine_invd, cupy.asarray([s, s, s]) * 0.5, max_iter=1, tol=1e-7
            #     )
            inv_approxd = invert_vector_field_fixed_point(
                dcopyd, gt_affine_invd,
                cupy.asarray([s, s, s]) * 0.5, 40, 1e-7)

            if False:
                inv_approx = dipy_invert_func(dcopy, gt_affine_inv,
                                              np.array([s, s, s]) * 0.5, 40,
                                              1e-7)
                cupy.testing.assert_allclose(inv_approx,
                                             inv_approxd,
                                             rtol=1e-2,
                                             atol=1e-2)

            # TODO: use GPU-based imwarp here once implemented
            mapping = imwarp.DiffeomorphicMap(ndim, shape, gt_affine)
            mapping.forward = dcopy
            mapping.backward = inv_approxd.get()
            residual, stats = mapping.compute_inversion_error()
            assert_almost_equal(stats[1], 0, decimal=3)
            assert_almost_equal(stats[2], 0, decimal=3)
Exemplo n.º 13
0
def test_warp(shape):
    """Tests the cython implementation of the 3d warpings against scipy."""

    ndim = len(shape)
    radius = shape[0] / 3

    if ndim == 3:
        # Create an image of a sphere
        volume = vfu.create_sphere(*shape, radius)
        volume = np.array(volume, dtype=floating)

        # Create a displacement field for warping
        d, dinv = vfu.create_harmonic_fields_3d(*shape, 0.2, 8)
    else:
        # Create an image of a circle
        volume = vfu.create_circle(*shape, radius)
        volume = np.array(volume, dtype=floating)

        # Create a displacement field for warping
        d, dinv = vfu.create_harmonic_fields_2d(*shape, 0.2, 8)
    d = np.asarray(d).astype(floating)

    if ndim == 3:
        # Select an arbitrary rotation axis
        axis = np.array([0.5, 2.0, 1.5])
        # Select an arbitrary translation matrix
        t = 0.1
        trans = np.array([
            [1, 0, 0, -t * shape[0]],
            [0, 1, 0, -t * shape[1]],
            [0, 0, 1, -t * shape[2]],
            [0, 0, 0, 1],
        ])
        trans_inv = np.linalg.inv(trans)
        theta = np.pi / 5
        s = 1.1
        rot = np.zeros(shape=(4, 4))
        rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
        rot[3, 3] = 1.0

        scale = np.array([[1 * s, 0, 0, 0], [0, 1 * s, 0, 0], [0, 0, 1 * s, 0],
                          [0, 0, 0, 1]])
    elif ndim == 2:
        # Select an arbitrary translation matrix
        t = 0.1
        trans = np.array([[1, 0, -t * shape[0]], [0, 1, -t * shape[1]],
                          [0, 0, 1]])
        trans_inv = np.linalg.inv(trans)
        theta = -1 * np.pi / 6.0
        s = 0.42
        ct = np.cos(theta)
        st = np.sin(theta)

        rot = np.array([[ct, -st, 0], [st, ct, 0], [0, 0, 1]])

        scale = np.array([[1 * s, 0, 0], [0, 1 * s, 0], [0, 0, 1]])

    aff = trans_inv.dot(scale.dot(rot.dot(trans)))

    # Select arbitrary (but different) grid-to-space transforms
    sampling_grid2world = scale
    field_grid2world = aff
    field_world2grid = np.linalg.inv(field_grid2world)
    image_grid2world = aff.dot(scale)
    image_world2grid = np.linalg.inv(image_grid2world)

    A = field_world2grid.dot(sampling_grid2world)
    B = image_world2grid.dot(sampling_grid2world)
    C = image_world2grid

    # Reorient the displacement field according to its grid-to-space
    # transform
    dcopy = np.copy(d)
    if ndim == 3:
        vfu.reorient_vector_field_3d(dcopy, field_grid2world)
        expected = vfu.warp_3d(volume, dcopy, A, B, C,
                               np.array(shape, dtype=np.int32))
    elif ndim == 2:
        vfu.reorient_vector_field_2d(dcopy, field_grid2world)
        expected = vfu.warp_2d(volume, dcopy, A, B, C,
                               np.array(shape, dtype=np.int32))

    dcopyg = cupy.asarray(dcopy)
    volumeg = cupy.asarray(volume)
    Ag = cupy.asarray(A)
    Bg = cupy.asarray(B)
    Cg = cupy.asarray(C)

    warped = warp(volumeg, dcopyg, Ag, Bg, Cg, order=1, mode="constant")

    cupy.testing.assert_array_almost_equal(warped, expected, decimal=4)
Exemplo n.º 14
0
def test_transform_affine(d_shape, codomain_shape, order):

    ndim = len(d_shape)
    theta = -1 * np.pi / 5.0
    s = 0.5
    ct = np.cos(theta)
    st = np.sin(theta)

    if ndim == 2:
        # Create an image of a circle
        radius = d_shape[0] // 4
        volume = vfu.create_circle(*codomain_shape, radius)
        volume = np.array(volume, dtype=floating)

        # Generate affine transforms
        t = 0.3
        trans = np.array([[1, 0, -t * d_shape[0]], [0, 1, -t * d_shape[1]],
                          [0, 0, 1]])
        trans_inv = np.linalg.inv(trans)
        rot = np.array([[ct, -st, 0], [st, ct, 0], [0, 0, 1]])

        scale = np.array([[1 * s, 0, 0], [0, 1 * s, 0], [0, 0, 1]])
    elif ndim == 3:
        # Create an image of a sphere
        radius = d_shape[0] // 4
        volume = vfu.create_sphere(*codomain_shape, radius)
        volume = np.array(volume, dtype=floating)

        # Generate affine transforms
        # Select an arbitrary rotation axis
        axis = np.array([0.5, 2.0, 1.5])
        t = 0.3
        trans = np.array([
            [1, 0, 0, -t * d_shape[0]],
            [0, 1, 0, -t * d_shape[1]],
            [0, 0, 1, -t * d_shape[2]],
            [0, 0, 0, 1],
        ])
        trans_inv = np.linalg.inv(trans)

        rot = np.zeros(shape=(4, 4))
        rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, theta)
        rot[3, 3] = 1.0

        scale = np.array([[1 * s, 0, 0, 0], [0, 1 * s, 0, 0], [0, 0, 1 * s, 0],
                          [0, 0, 0, 1]])
    gt_affine = trans_inv.dot(scale.dot(rot.dot(trans)))

    # # Apply the affine transform to the grid coordinates
    # Y = np.apply_along_axis(gt_affine.dot, 0, X)[0:2, ...]

    # expected = map_coordinates(volume, Y, order=1)
    if order == 1:
        if ndim == 2:
            dipy_func = vfu.transform_2d_affine
        elif ndim == 3:
            dipy_func = vfu.transform_3d_affine
    elif order == 0:
        if ndim == 2:
            dipy_func = vfu.transform_2d_affine_nn
        elif ndim == 3:
            dipy_func = vfu.transform_3d_affine_nn
    expected = dipy_func(volume, np.array(d_shape, dtype=np.int32), gt_affine)

    volumed = cupy.asarray(volume)
    warped = transform_affine(volumed, d_shape, gt_affine, order=order)

    cupy.testing.assert_array_almost_equal(warped, expected)