Ejemplo n.º 1
0
def get_synthetic_warped_circle(nslices):
    #get a subsampled circle
    fname_cicle = get_data('reg_o')
    circle = np.load(fname_cicle)[::4,::4].astype(floating)

    #create a synthetic invertible map and warp the circle
    d, dinv = vfu.create_harmonic_fields_2d(64, 64, 0.1, 4)
    d = np.asarray(d, dtype=floating)
    dinv = np.asarray(dinv, dtype=floating)
    mapping = DiffeomorphicMap(2, (64, 64))
    mapping.forward, mapping.backward = d, dinv
    wcircle = mapping.transform(circle)

    if(nslices == 1):
        return circle, wcircle

    #normalize and form the 3d by piling slices
    circle = (circle-circle.min())/(circle.max() - circle.min())
    circle_3d = np.ndarray(circle.shape + (nslices,), dtype=floating)
    circle_3d[...] = circle[...,None]
    circle_3d[...,0] = 0
    circle_3d[...,-1] = 0

    #do the same with the warped circle
    wcircle = (wcircle-wcircle.min())/(wcircle.max() - wcircle.min())
    wcircle_3d = np.ndarray(wcircle.shape + (nslices,), dtype=floating)
    wcircle_3d[...] = wcircle[...,None]
    wcircle_3d[...,0] = 0
    wcircle_3d[...,-1] = 0

    return circle_3d, wcircle_3d
Ejemplo n.º 2
0
def test_diffeomorphic_map_simplification_2d():
    r"""
    Create an invertible deformation field, and define a DiffeomorphicMap
    using different voxel-to-space transforms for domain, codomain, and
    reference discretizations, also use a non-identity pre-aligning matrix.
    Warp a circle using the diffeomorphic map to obtain the expected warped
    circle. Now simplify the DiffeomorphicMap and warp the same circle using
    this simplified map. Verify that the two warped circles are equal up to
    numerical precision.
    """
    #create a simple affine transformation
    dom_shape = (64, 64)
    cod_shape = (80, 80)
    nr = dom_shape[0]
    nc = dom_shape[1]
    s = 1.1
    t = 0.25
    trans = np.array([[1, 0, -t*nr],
                      [0, 1, -t*nc],
                      [0, 0, 1]])
    trans_inv = np.linalg.inv(trans)
    scale = np.array([[1*s, 0, 0],
                      [0, 1*s, 0],
                      [0, 0, 1]])
    gt_affine = trans_inv.dot(scale.dot(trans))
    # Create the invertible displacement fields and the circle
    radius = 16
    circle = vfu.create_circle(cod_shape[0], cod_shape[1], radius)
    d, dinv = vfu.create_harmonic_fields_2d(dom_shape[0], dom_shape[1], 0.3, 6)
    #Define different voxel-to-space transforms for domain, codomain and
    #reference grid, also, use a non-identity pre-align transform
    D = gt_affine
    C = imwarp.mult_aff(gt_affine, gt_affine)
    R = np.eye(3)
    P = gt_affine

    #Create the original diffeomorphic map
    diff_map = imwarp.DiffeomorphicMap(2, dom_shape, R,
                                          dom_shape, D,
                                          cod_shape, C,
                                          P)
    diff_map.forward = np.array(d, dtype = floating)
    diff_map.backward = np.array(dinv, dtype = floating)
    #Warp the circle to obtain the expected image
    expected = diff_map.transform(circle, 'linear')

    #Simplify
    simplified = diff_map.get_simplified_transform()
    #warp the circle
    warped = simplified.transform(circle, 'linear')
    #verify that the simplified map is equivalent to the
    #original one
    assert_array_almost_equal(warped, expected)
    #And of course, it must be simpler...
    assert_equal(simplified.domain_affine, None)
    assert_equal(simplified.codomain_affine, None)
    assert_equal(simplified.disp_affine, None)
    assert_equal(simplified.domain_affine_inv, None)
    assert_equal(simplified.codomain_affine_inv, None)
    assert_equal(simplified.disp_affine_inv, None)
Ejemplo n.º 3
0
def get_warped_stacked_image(image, nslices, b, m):
    r""" Creates a volume by stacking copies of a deformed image

    The image is deformed under an invertible field, and a 3D volume is
    generated as follows:
    the first and last `nslices`//3 slices are filled with zeros
    to simulate background. The remaining middle slices are filled with
    copies of the deformed `image` under the action of the invertible
    field.

    Parameters
    ----------
    image : 2d array shape(r, c)
        the image to be deformed
    nslices : int
        the number of slices in the final volume
    b, m : float
        parameters of the harmonic field (as in [1]).

    Returns
    -------
    vol : array shape(r, c) if `nslices`==1 else (r, c, `nslices`)
        the volumed generated using the undeformed image
    wvol : array shape(r, c) if `nslices`==1 else (r, c, `nslices`)
        the volumed generated using the warped image

    References
    ----------
    [1] Chen, M., Lu, W., Chen, Q., Ruchala, K. J., & Olivera, G. H. (2008).
        A simple fixed-point approach to invert a deformation field.
        Medical Physics, 35(1), 81. doi:10.1118/1.2816107
    """
    shape = image.shape
    # create a synthetic invertible map and warp the circle
    d, dinv = vfu.create_harmonic_fields_2d(shape[0], shape[1], b, m)
    d = np.asarray(d, dtype=floating)
    dinv = np.asarray(dinv, dtype=floating)
    mapping = DiffeomorphicMap(2, shape)
    mapping.forward, mapping.backward = d, dinv
    wimage = mapping.transform(image)

    if (nslices == 1):
        return image, wimage

    # normalize and form the 3d by piling slices
    image = image.astype(floating)
    image = (image - image.min()) / (image.max() - image.min())
    zero_slices = nslices // 3
    vol = np.zeros(shape=image.shape + (nslices, ))
    vol[..., zero_slices:(2 * zero_slices)] = image[..., None]
    wvol = np.zeros(shape=image.shape + (nslices, ))
    wvol[..., zero_slices:(2 * zero_slices)] = wimage[..., None]

    return vol, wvol
Ejemplo n.º 4
0
def get_warped_stacked_image(image, nslices, b, m):
    r""" Creates a volume by stacking copies of a deformed image

    The image is deformed under an invertible field, and a 3D volume is
    generated as follows:
    the first and last `nslices`//3 slices are filled with zeros
    to simulate background. The remaining middle slices are filled with
    copies of the deformed `image` under the action of the invertible
    field.

    Parameters
    ----------
    image : 2d array shape(r, c)
        the image to be deformed
    nslices : int
        the number of slices in the final volume
    b, m : float
        parameters of the harmonic field (as in [1]).

    Returns
    -------
    vol : array shape(r, c) if `nslices`==1 else (r, c, `nslices`)
        the volumed generated using the undeformed image
    wvol : array shape(r, c) if `nslices`==1 else (r, c, `nslices`)
        the volumed generated using the warped image

    References
    ----------
    [1] Chen, M., Lu, W., Chen, Q., Ruchala, K. J., & Olivera, G. H. (2008).
        A simple fixed-point approach to invert a deformation field.
        Medical Physics, 35(1), 81. doi:10.1118/1.2816107
    """
    shape = image.shape
    # create a synthetic invertible map and warp the circle
    d, dinv = vfu.create_harmonic_fields_2d(shape[0], shape[1], b, m)
    d = np.asarray(d, dtype=floating)
    dinv = np.asarray(dinv, dtype=floating)
    mapping = DiffeomorphicMap(2, shape)
    mapping.forward, mapping.backward = d, dinv
    wimage = mapping.transform(image)

    if(nslices == 1):
        return image, wimage

    # normalize and form the 3d by piling slices
    image = image.astype(floating)
    image = (image - image.min()) / (image.max() - image.min())
    zero_slices = nslices // 3
    vol = np.zeros(shape=image.shape + (nslices,))
    vol[..., zero_slices:(2 * zero_slices)] = image[..., None]
    wvol = np.zeros(shape=image.shape + (nslices,))
    wvol[..., zero_slices:(2 * zero_slices)] = wimage[..., None]

    return vol, wvol
Ejemplo n.º 5
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)