Esempio n. 1
0
def test_S2FFT_NFFT():
    """
    Testing S2FFT NFFT
    """
    b = 8
    convention = 'Gauss-Legendre'
    #convention = 'Clenshaw-Curtis'
    x = S2.meshgrid(b=b, grid_type=convention)
    print(x[0].shape, x[1].shape)
    x = np.c_[x[0][..., None], x[1][..., None]]#.reshape(-1, 2)
    print(x.shape)
    x = x.reshape(-1, 2)
    w = S2.quadrature_weights(b=b, grid_type=convention).flatten()
    F = S2FFT_NFFT(L_max=b, x=x, w=w)

    for l in range(0, b):
        for m in range(-l, l + 1):
            #l = b; m = b
            f = sh(l, m, x[..., 0], x[..., 1], field='real', normalization='quantum', condon_shortley=True)
            #f2 = np.random.randn(*f.shape)
            print(f)

            f_hat = F.analyze(f)
            print(np.round(f_hat, 3))
            f_reconst = F.synthesize(f_hat)

            #print np.round(f, 3)
            print(np.round(f_reconst, 3))
            #print np.round(f/f_reconst, 3)
            print(np.abs(f-f_reconst).sum())
            assert np.isclose(np.abs(f-f_reconst).sum(), 0.)

            print(np.round(f_hat, 3))
            assert np.isclose(f_hat[l ** 2 + l + m], 1.)
            #assert False
Esempio n. 2
0
def make_sgrid(b):

    theta, phi = S2.meshgrid(b=b, grid_type='Driscoll-Healy')
    sgrid = S2.change_coordinates(np.c_[theta[..., None], phi[..., None]],
                                  p_from='S',
                                  p_to='C')
    sgrid = sgrid.reshape((-1, 3))

    return sgrid
Esempio n. 3
0
    def make_sgrid(b):
        from lie_learn.spaces import S2

        theta, phi = S2.meshgrid(b=b, grid_type='SOFT')
        sgrid = S2.change_coordinates(np.c_[theta[..., None], phi[..., None]],
                                      p_from='S',
                                      p_to='C')
        sgrid = sgrid.reshape((-1, 3))

        return (theta, phi), sgrid
Esempio n. 4
0
    def make_sgrid(b, alpha, beta, gamma, grid_type):
        theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
        sgrid = S2.change_coordinates(np.c_[theta[..., None], phi[..., None]],
                                      p_from='S',
                                      p_to='C')
        sgrid = sgrid.reshape((-1, 3))

        R = mesh_op.rotmat(alpha, beta, gamma, hom_coord=False)
        sgrid = np.einsum('ij,nj->ni', R, sgrid)

        return sgrid
Esempio n. 5
0
def make_sgrid(b, alpha, beta, gamma):
    from lie_learn.spaces import S2

    theta, phi = S2.meshgrid(b=b, grid_type='SOFT')
    sgrid = S2.change_coordinates(np.c_[theta[..., None], phi[..., None]], p_from='S', p_to='C')
    sgrid = sgrid.reshape((-1, 3))

    R = rotmat(alpha, beta, gamma, hom_coord=False)
    sgrid = np.einsum('ij,nj->ni', R, sgrid)

    return sgrid
Esempio n. 6
0
def get_projection_grid(b, grid_type="Driscoll-Healy"):
    """
    returns the spherical grid in euclidean
    coordinates, where the sphere's center is moved
    to (0, 0, 1)
    """
    theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
    grid = S2.change_coordinates(np.c_[theta[..., None], phi[..., None]],
                                 p_from='S',
                                 p_to='C')
    grid = grid.reshape((-1, 3)).astype(np.float32)
    return grid
def test_spherical_quadrature():
    """
    Testing spherical quadrature rule versus numerical integration.
    """

    b = 8  # 10

    # Create grids on the sphere
    x_gl = S2.meshgrid(b=b, grid_type='Gauss-Legendre')
    x_cc = S2.meshgrid(b=b, grid_type='Clenshaw-Curtis')
    x_soft = S2.meshgrid(b=b, grid_type='SOFT')
    x_gl = np.c_[x_gl[0][..., None], x_gl[1][..., None]]
    x_cc = np.c_[x_cc[0][..., None], x_cc[1][..., None]]
    x_soft = np.c_[x_soft[0][..., None], x_soft[1][..., None]]

    # Compute quadrature weights
    w_gl = S2.quadrature_weights(b=b, grid_type='Gauss-Legendre')
    w_cc = S2.quadrature_weights(b=b, grid_type='Clenshaw-Curtis')
    w_soft = S2.quadrature_weights(b=b, grid_type='SOFT')

    # Define a polynomial function, to be evaluated at one point or at an array of points
    def f1a(xs):
        xc = S2.change_coordinates(coords=xs, p_from='S', p_to='C')
        return xc[..., 0]**2 * xc[..., 1] - 1.4 * xc[..., 2] * xc[
            ..., 1]**3 + xc[..., 1] - xc[..., 2]**2 + 2.

    def f1(theta, phi):
        xs = np.array([theta, phi])
        return f1a(xs)

    # Obtain the "true" value of the integral of the function over the sphere, using scipy's numerical integration
    # routines
    i1 = S2.integrate(f1, normalize=False)

    # Compute the integral using the quadrature formulae
    # i1_gl_w = (w_gl * f1a(x_gl)).sum()
    i1_gl_w = S2.integrate_quad(f1a(x_gl),
                                grid_type='Gauss-Legendre',
                                normalize=False,
                                w=w_gl)
    print(i1_gl_w, i1, 'diff:', np.abs(i1_gl_w - i1))
    assert np.isclose(np.abs(i1_gl_w - i1), 0.0)

    # i1_cc_w = (w_cc * f1a(x_cc)).sum()
    i1_cc_w = S2.integrate_quad(f1a(x_cc),
                                grid_type='Clenshaw-Curtis',
                                normalize=False,
                                w=w_cc)
    print(i1_cc_w, i1, 'diff:', np.abs(i1_cc_w - i1))
    assert np.isclose(np.abs(i1_cc_w - i1), 0.0)

    i1_soft_w = (w_soft * f1a(x_soft)).sum()
    print(i1_soft_w, i1, 'diff:', np.abs(i1_soft_w - i1))
    print(i1_soft_w)
    print(i1)
Esempio n. 8
0
def get_projection_grid(b, grid_type="Driscoll-Healy"):
	theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
	x_ = np.sin(theta) * np.cos(phi)
	y_ = np.sin(theta) * np.sin(phi)
	z_ = np.cos(theta)
	#pdb.set_trace()
	return x_, y_, z_
Esempio n. 9
0
def naive_conv(l1=1, m1=1, l2=1, m2=1, g_parameterization='EA313'):
    f1 = lambda t, p: sh(l=l1,
                         m=m1,
                         theta=t,
                         phi=p,
                         field='real',
                         normalization='quantum',
                         condon_shortley=True)
    f2 = lambda t, p: sh(l=l2,
                         m=m2,
                         theta=t,
                         phi=p,
                         field='real',
                         normalization='quantum',
                         condon_shortley=True)

    theta, phi = S2.meshgrid(b=3, grid_type='Gauss-Legendre')
    f1_grid = f1(theta, phi)
    f2_grid = f2(theta, phi)

    alpha, beta, gamma = S3.meshgrid(b=3,
                                     grid_type='SOFT')  # TODO check convention

    f12_grid = np.zeros_like(alpha)
    for i in range(alpha.shape[0]):
        for j in range(alpha.shape[1]):
            for k in range(alpha.shape[2]):
                f12_grid[i, j, k] = naive_S2_conv_v2(f1, f2, alpha[i, j, k],
                                                     beta[i, j, k], gamma[i, j,
                                                                          k],
                                                     g_parameterization)
                print(i, j, k, f12_grid[i, j, k])

    return f1_grid, f2_grid, f12_grid
def get_grid(b, radius, grid_type="Driscoll-Healy"):
    """
    returns the spherical grid in euclidean coordinates, which, to be specify,
    for each image in range(train_size):
        for each point in range(num_points):
            generate the 2b * 2b S2 points , each is (x, y, z)
    therefore returns tensor (train_size * num_points, 2b * 2b, 3)
    :param b: the number of grids on the sphere
    :param radius: the radius of each sphere
    :param grid_type: "Driscoll-Healy"
    :return: tensor (batch_size, num_points, 4 * b * b, 3)
    """
    # theta in shape (2b, 2b), range [0, pi]; phi range [0, 2 * pi]
    theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
    theta = torch.from_numpy(theta).cuda()
    phi = torch.from_numpy(phi).cuda()

    x_ = radius * torch.sin(theta) * torch.cos(phi)
    """x will be reshaped to have one dimension of 1, then can broadcast
    look this link for more information: https://pytorch.org/docs/stable/notes/broadcasting.html
    """
    x = x_.reshape((1, 4 * b * b))  # tensor (1, 4 * b * b)

    # same for y and z
    y_ = radius * torch.sin(theta) * torch.sin(phi)
    y = y_.reshape((1, 4 * b * b))

    z_ = radius * torch.cos(theta)
    z = z_.reshape((1, 4 * b * b))

    grid = torch.cat((x, y, z), dim=0)  # (3, 4 * b * b)
    assert grid.shape == torch.Size([3, 4 * b * b])
    # grid = grid.reshape((1, 4 * b * b, 3))
    return grid
Esempio n. 11
0
def inverse_render_model(points: np.ndarray, sgrid: np.ndarray, lib):
    # wait for implementing
    #print("InverseRenderModel")
    try:
        x = points[:, 0]
    except IndexError:
        print(points.shape[0], points.shape[1])

    y = points[:, 1]
    z = points[:, 2]
    # Fistly, we get the centroid, then translate the points
    centroid_x = np.sum(x) / points.shape[0]
    centroid_y = np.sum(y) / points.shape[0]
    centroid_z = np.sum(z) / points.shape[0]
    centroid = np.array([centroid_x, centroid_y, centroid_z])
    points = points.astype(np.float)
    points -= centroid

    # After normalization, compute the distance between the sphere and points

    radius = np.sqrt(points[:, 0]**2 + points[:, 1]**2 + points[:, 2]**2)
    # dist = 1 - (1 / np.max(radius)) * radius

    # Projection
    from lie_learn.spaces import S2
    radius = np.repeat(radius, 3).reshape(-1, 3)
    points_on_sphere = points / radius
    # ssgrid = sgrid.reshape(-1, 3)
    # phi, theta = S2.change_coordinates(ssgrid, p_from='C', p_to='S')
    out = S2.change_coordinates(points_on_sphere, p_from='C', p_to='S')

    phi = out[..., 0]
    theta = out[..., 1]

    phi = phi
    theta = theta % (np.pi * 2)

    # Interpolate
    b = sgrid.shape[0] / 2  # bandwidth
    # By computing the m,n, we can find
    # the neighbours on the sphere
    m = np.trunc((phi - np.pi / (4 * b)) / (np.pi / (2 * b)))
    m = m.astype(int)
    n = np.trunc(theta / (np.pi / b))
    n = n.astype(int)

    dist_im, center_grid, east_grid, south_grid, southeast_grid = interpolate(
        m=m,
        n=n,
        sgrid=sgrid,
        points_on_sphere=points_on_sphere,
        radius=radius)
    dot_img, cross_img = angle(m=m, n=n, sgrid=sgrid, dist_im=dist_im, lib=lib)
    #dist_im=dist_im.reshape(-1,1)

    #wait for validation
    im = np.stack((dist_im, dot_img, cross_img), axis=0)

    return im
Esempio n. 12
0
def get_projection_grid(b, grid_type="Driscoll-Healy"):
    ''' returns the spherical grid in euclidean
    coordinates, where the sphere's center is moved
    to (0, 0, 1)'''
    theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
    x_ = np.sin(theta) * np.cos(phi)
    y_ = np.sin(theta) * np.sin(phi)
    z_ = np.cos(theta)
    return x_, y_, z_
Esempio n. 13
0
def make_sgrid_(b):
    theta = np.linspace(0, m.pi, num=b)
    phi = np.linspace(0, 2 * m.pi, num=b)
    theta_m, phi_m = np.meshgrid(theta, phi)
    sgrid = S2.change_coordinates(np.c_[theta_m[..., None], phi_m[..., None]],
                                  p_from='S',
                                  p_to='C')
    sgrid = sgrid.reshape((-1, 3))

    return sgrid
Esempio n. 14
0
    def __init__(self,
                 L_max,
                 grid_type='Gauss-Legendre',
                 field='real',
                 normalization='quantum',
                 condon_shortley='cs'):

        super().__init__()

        self.b = L_max + 1

        # Compute a grid of spatial sampling points and associated quadrature weights
        beta, alpha = S2.meshgrid(b=self.b, grid_type=grid_type)
        self.w = S2.quadrature_weights(b=self.b, grid_type=grid_type)
        self.spatial_grid_shape = beta.shape
        self.num_spatial_points = beta.size

        # Determine for which degree and order we want the spherical harmonics
        irreps = np.arange(
            self.b
        )  # TODO find out upper limit for exact integration for each grid type
        ls = [[ls] * (2 * ls + 1) for ls in irreps]
        ls = np.array([ll for sublist in ls
                       for ll in sublist])  # 0, 1, 1, 1, 2, 2, 2, 2, 2, ...
        ms = [list(range(-ls, ls + 1)) for ls in irreps]
        ms = np.array([mm for sublist in ms
                       for mm in sublist])  # 0, -1, 0, 1, -2, -1, 0, 1, 2, ...
        self.num_spectral_points = ms.size  # This equals sum_{l=0}^{b-1} 2l+1 = b^2

        # In one shot, sample the spherical harmonics at all spectral (l, m) and spatial (beta, alpha) coordinates
        self.Y = sh(ls[None, None, :],
                    ms[None, None, :],
                    beta[:, :, None],
                    alpha[:, :, None],
                    field=field,
                    normalization=normalization,
                    condon_shortley=condon_shortley == 'cs')

        # Convert to a matrix
        self.Ymat = self.Y.reshape(self.num_spatial_points,
                                   self.num_spectral_points)
Esempio n. 15
0
def test_S2_FT_Naive():

    L_max = 6

    for grid_type in ('Gauss-Legendre', 'Clenshaw-Curtis'):

        theta, phi = S2.meshgrid(b=L_max + 1, grid_type=grid_type)

        for field in ('real', 'complex'):
            for normalization in (
                    'quantum', 'seismology'
            ):  # TODO Others should work but are not normalized
                for condon_shortley in ('cs', 'nocs'):

                    fft = S2_FT_Naive(L_max,
                                      grid_type=grid_type,
                                      field=field,
                                      normalization=normalization,
                                      condon_shortley=condon_shortley)

                    for l in range(L_max):
                        for m in range(-l, l + 1):

                            y_true = sh(
                                l,
                                m,
                                theta,
                                phi,
                                field=field,
                                normalization=normalization,
                                condon_shortley=condon_shortley == 'cs')

                            y_hat = fft.analyze(y_true)

                            # The flat index for (l, m) is l^2 + l + m
                            # Before the harmonics of degree l, there are this many harmonics:
                            # sum_{i=0}^{l-1} 2i+1 = l^2
                            # There are 2l+1 harmonics of degree l, with order m=0 at the center,
                            # so the m-th harmonic of degree is at l + m within the block of degree l.
                            y_hat_true = np.zeros_like(y_hat)
                            y_hat_true[l**2 + l + m] = 1

                            y = fft.synthesize(y_hat_true)

                            diff = np.sum(np.abs(y_hat - y_hat_true))
                            print(grid_type, field, normalization,
                                  condon_shortley, l, m, diff)
                            assert np.isclose(diff, 0.)

                            diff = np.sum(np.abs(y - y_true))
                            print(grid_type, field, normalization,
                                  condon_shortley, l, m, diff)
                            assert np.isclose(diff, 0.)
Esempio n. 16
0
def naive_S2_conv_v2(f1, f2, alpha, beta, gamma, g_parameterization='EA323'):
    """
    Compute int_S^2 f1(x) f2(g^{-1} x)* dx,
    where x = (theta, phi) is a point on the sphere S^2,
    and g = (alpha, beta, gamma) is a point in SO(3) in Euler angle parameterization

    :param f1, f2: functions to be convolved
    :param alpha, beta, gamma: the rotation at which to evaluate the result of convolution
    :return:
    """

    theta, phi = S2.meshgrid(b=3, grid_type='Gauss-Legendre')
    w = S2.quadrature_weights(b=3, grid_type='Gauss-Legendre')

    print(theta.shape, phi.shape)
    s2_coords = np.c_[theta[..., None], phi[..., None]]
    print(s2_coords.shape)
    r3_coords = np.c_[theta[..., None], phi[..., None],
                      np.ones_like(theta)[..., None]]

    # g_inv = SO3.invert((alpha, beta, gamma), parameterization=g_parameterization)
    # g_inv = (-gamma, -beta, -alpha)
    g_inv = (alpha, beta, gamma)  # wrong

    ginvx = SO3.transform_r3(g=g_inv,
                             x=r3_coords,
                             g_parameterization=g_parameterization,
                             x_parameterization='S')
    print(ginvx.shape)
    g_inv_theta = ginvx[..., 0]
    g_inv_phi = ginvx[..., 1]
    g_inv_r = ginvx[..., 2]

    print(g_inv_theta, g_inv_phi, g_inv_r)

    f1_grid = f1(theta, phi)
    f2_grid = f2(g_inv_theta, g_inv_phi)

    print(f1_grid.shape, f2_grid.shape, w.shape)
    return np.sum(f1_grid * f2_grid * w)
Esempio n. 17
0
def get_grids(b,
              num_grids,
              base_radius=1,
              center=[0, 0, 0],
              grid_type="Driscoll-Healy"):
    """
    :param b: the number of grids on the sphere
    :param base_radius: the radius of each sphere
    :param grid_type: "Driscoll-Healy"
    :param num_grids: number of grids
    :return: [(radius, tensor([2b, 2b, 3])) * num_grids]
    """

    grids = list()
    radiuses = [
        round(i, 2)
        for i in list(np.linspace(0, base_radius, num_grids + 1))[1:]
    ]

    # Each grid has differet radius, the radiuses are distributed uniformly based on number
    for radius in radiuses:

        # theta in shape (2b, 2b), range [0, pi]; phi range [0, 2 * pi]
        theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
        theta = torch.from_numpy(theta)
        phi = torch.from_numpy(phi)

        # x will be reshaped to have one dimension of 1, then can broadcast
        # look this link for more information: https://pytorch.org/docs/stable/notes/broadcasting.html
        x_ = radius * torch.sin(theta) * torch.cos(phi)
        x = x_.reshape((1, 4 * b * b))  # tensor -> [1, 4 * b * b]
        x = x + center[0]

        y_ = radius * torch.sin(theta) * torch.sin(phi)
        y = y_.reshape((1, 4 * b * b))
        y = y + center[1]

        z_ = radius * torch.cos(theta)
        z = z_.reshape((1, 4 * b * b))
        z = z + center[2]

        grid = torch.cat((x, y, z), dim=0)  # -> [3, 4b^2]
        grid = grid.transpose(0, 1)  # -> [4b^2, 3]

        grid = grid.view(2 * b, 2 * b, 3)  # -> [2b, 2b, 3]
        grid = grid.float().cuda()

        grids.append((radius, grid))

    assert len(grids) == num_grids
    return grids
Esempio n. 18
0
def setup_legendre_transform(b):
    """
    Compute a set of matrices containing coefficients to be used in a discrete Legendre transform.
    
    The discrete Legendre transform of a data vector s[k] (k=0, ..., 2b-1) is defined as

    s_hat(l, m) = sum_{k=0}^{2b-1} P_l^m(cos(beta_k)) s[k]
    for l = 0, ..., b-1 and -l <= m <= l,
    where P_l^m is the associated Legendre function of degree l and order m,
    beta_k = ...

    Computing Fourier Transforms and Convolutions on the 2-Sphere
    J.R. Driscoll, D.M. Healy

    FFTs for the 2-Sphere–Improvements and Variations
    D.M. Healy, Jr., D.N. Rockmore, P.J. Kostelec, and S. Moore

    :param b: bandwidth of the transform
    :return: lt, an array of shape (N, 2b), containing samples of the Legendre functions,
     where N is the number of spectral points for a signal of bandwidth b.
    """
    dim = np.sum(np.arange(b) * 2 + 1)
    lt = np.empty((2 * b, dim))

    beta, _ = S2.linspace(b, grid_type='Driscoll-Healy')
    sample_points = np.cos(beta)

    # TODO move quadrature weight computation to S2.py
    weights = [(1. / b) * np.sin(np.pi * j * 0.5 / b) * np.sum([
        1. / (2 * l + 1) * np.sin((2 * l + 1) * np.pi * j * 0.5 / b)
        for l in range(b)
    ]) for j in range(2 * b)]
    weights = np.array(weights)

    zeros = np.zeros_like(sample_points)
    i = 0
    for l in range(b):
        for m in range(-l, l + 1):
            # Z = np.sqrt(((2 * l + 1) * factorial(l - m)) / float(4 * np.pi * factorial(l + m))) * np.pi / 2
            # lt[i, :] = lpmv(m, l, sample_points) * weights * Z

            # The spherical harmonics code appears to be more stable than the (unnormalized) associated Legendre
            # function code.
            # (Note: the spherical harmonics evaluated at alpha=0 is the associated Legendre function))
            lt[:,
               i] = csh(l, m, beta, zeros,
                        normalization='seismology').real * weights * np.pi / 2

            i += 1

    return lt
def get_projection_grid(b, images, radius, grid_type="Driscoll-Healy"):
    """
    returns the spherical grid in euclidean coordinates, which, to be specify,
    for each image in range(train_size):
        for each point in range(num_points):
            generate the 2b * 2b S2 points , each is (x, y, z)
    therefore returns tensor (train_size * num_points, 2b * 2b, 3)
    :param b: the number of grids on the sphere
    :param images: tensor (batch_size, num_points, 3)
    :param radius: the radius of each sphere
    :param grid_type: "Driscoll-Healy"
    :return: tensor (batch_size, num_points, 4 * b * b, 3)
    """
    assert type(images) == torch.Tensor
    assert len(images.shape) == 3
    assert images.shape[-1] == 3
    batch_size = images.shape[0]
    num_points = images.shape[1]
    images = images.reshape((-1, 3))  # -> (B * 512, 3)

    # theta in shape (2b, 2b), range [0, pi]; phi range [0, 2 * pi]
    theta, phi = S2.meshgrid(b=b, grid_type=grid_type)
    theta = torch.from_numpy(theta).cuda()
    phi = torch.from_numpy(phi).cuda()

    x_ = radius * torch.sin(theta) * torch.cos(phi)
    """x will be reshaped to have one dimension of 1, then can broadcast
    look this link for more information: https://pytorch.org/docs/stable/notes/broadcasting.html
    """
    x = x_.reshape((1, 4 * b * b))  # tensor (1, 4 * b * b)
    px = images[:, 0].reshape((-1, 1))  # tensor (batch_size * 512, 1)
    x = x + px  # (batch_size * num_points, 4 * b * b)

    # same for y and z
    y_ = radius * torch.sin(theta) * torch.sin(phi)
    y = y_.reshape((1, 4 * b * b))
    py = images[:, 1].reshape((-1, 1))
    y = y + py

    z_ = radius * torch.cos(theta)
    z = z_.reshape((1, 4 * b * b))
    pz = images[:, 2].reshape((-1, 1))
    z = z + pz

    # give x, y, z extra dimension, so that it can concat by that dimension
    x = torch.unsqueeze(x, 2)  # (B * 512, 4 * b * b, 1)
    y = torch.unsqueeze(y, 2)
    z = torch.unsqueeze(z, 2)
    grid = torch.cat((x, y, z), 2)  # (B * 512, 4 * b * b, 3)
    grid = grid.reshape((batch_size, num_points, 4 * b * b, 3))
    return grid
Esempio n. 20
0
def check_orthogonality(L_max=3,
                        grid_type='Gauss-Legendre',
                        field='real',
                        normalization='quantum',
                        condon_shortley=True):

    theta, phi = S2.meshgrid(b=L_max + 1, grid_type=grid_type)
    w = S2.quadrature_weights(b=L_max + 1, grid_type=grid_type)

    for l in range(L_max):
        for m in range(-l, l + 1):
            for l2 in range(L_max):
                for m2 in range(-l2, l2 + 1):
                    Ylm = sh(l, m, theta, phi, field, normalization,
                             condon_shortley)
                    Ylm2 = sh(l2, m2, theta, phi, field, normalization,
                              condon_shortley)

                    dot_numerical = S2.integrate_quad(Ylm * Ylm2.conj(),
                                                      grid_type=grid_type,
                                                      normalize=False,
                                                      w=w)

                    dot_numerical2 = S2.integrate(
                        lambda t, p: sh(l, m, t, p, field, normalization, condon_shortley) * \
                                     sh(l2, m2, t, p, field, normalization, condon_shortley).conj(), normalize=False)

                    sqnorm_analytical = sh_squared_norm(l,
                                                        normalization,
                                                        normalized_haar=False)
                    dot_analytical = sqnorm_analytical * (l == l2 and m == m2)

                    print(l, m, l2, m2, field, normalization, condon_shortley,
                          dot_analytical, dot_numerical, dot_numerical2)
                    assert np.isclose(dot_numerical, dot_analytical)
                    assert np.isclose(dot_numerical2, dot_analytical)
Esempio n. 21
0
def spherical_voxel_optimized(points: np.ndarray, size_bandwidth: int, size_radial_divisions: int,
                              radius_support: float, do_random_sampling: bool, num_random_points: int) \
        -> Tuple[np.ndarray, np.ndarray]:
    """Compute spherical voxel using the C++ code.

    Compute Spherical Voxel signal as defined in:
    Pointwise Rotation-Invariant Network withAdaptive Sampling and 3D Spherical Voxel Convolution.
    Yang You, Yujing Lou, Qi Liu, Yu-Wing Tai, Weiming Wang, Lizhuang Ma and Cewu Lu.
    AAAI 2020.

    :param points: the points to convert.
    :param size_bandwidth: alpha and beta bandwidth.
    :param size_radial_divisions: the number of bins along radial dimension.
    :param radius_support: the radius used to compute the points in the support.
    :param do_random_sampling: if true a subset of random points will be used to compute the spherical voxel.
    :param num_random_points: the number of points to keep if do_random_sampling is true.

    :return: A tuple containing:
        The spherical voxel, shape(size_radial_divisions, 2 * size_bandwidth, 2 * size_bandwidth).
        The points used to compute the signal normalized according the the farthest point.
    """
    if do_random_sampling:
        min_limit = 1 if points.shape[0] > 1 else 0
        indices_random = np.random.randint(min_limit, points.shape[0], num_random_points)
        points = points[indices_random]

    pts_norm = np.linalg.norm(points, axis=1)
    # Scale points to fit unit sphere
    pts_normed = points / pts_norm[:, None]
    pts_normed = np.clip(pts_normed, -1, 1)

    pts_s2_coord = S2.change_coordinates(pts_normed, p_from='C', p_to='S')
    # Convert to spherical voxel indices
    pts_s2_coord[:, 0] *= 2 * size_bandwidth / np.pi  # [0, pi]
    pts_s2_coord[:, 1] *= size_bandwidth / np.pi
    pts_s2_coord[:, 1][pts_s2_coord[:, 1] < 0] += 2 * size_bandwidth

    # Adaptive sampling factor
    daas_weights = np.sin(np.pi * (2 * np.arange(2 * size_bandwidth) + 1) / 4 / size_bandwidth).astype(np.float32)
    voxel = np.asarray(sv.compute(pts_on_s2=pts_s2_coord,
                                  pts_norm=pts_norm,
                                  size_bandwidth=size_bandwidth,
                                  size_radial_divisions=size_radial_divisions,
                                  radius_support=radius_support,
                                  daas_weights=daas_weights))
    pts_normed = points / np.max(pts_norm)
    return voxel.astype(np.float32), pts_normed.astype(np.float32)
Esempio n. 22
0
    def __getitem__(self, index):
        b = self.bw
        pts = np.array(self.pts[index])

        # randomly sample points
        sub_idx = np.random.randint(0, pts.shape[0], 2048)
        pts = pts[sub_idx]
        if self.aug:
            rot = rnd_rot()
            pts = np.einsum('ij,nj->ni', rot, pts)
            pts += np.random.rand(3)[None, :] * 0.05
            pts = np.einsum('ij,nj->ni', rot.T, pts)

        segs = np.array(self.segs[index])
        segs = segs[sub_idx]
        labels = self.labels[index]

        pts_norm = np.linalg.norm(pts, axis=1)
        pts_normed = pts / pts_norm[:, None]
        rand_rot = rnd_rot() if self.rand_rot else np.eye(3)
        rotated_pts_normed = np.clip(pts_normed @ rand_rot, -1, 1)

        pts_s2 = S2.change_coordinates(rotated_pts_normed,
                                       p_from='C',
                                       p_to='S')
        pts_s2[:, 0] *= 2 * b / np.pi  # [0, pi]
        pts_s2[:, 1] *= b / np.pi
        pts_s2[:, 1][pts_s2[:, 1] < 0] += 2 * b

        pts_s2_float = pts_s2

        # N * 3
        pts_so3 = np.stack([
            pts_norm * 2 - 1, pts_s2_float[:, 1] /
            (2 * b - 1) * 2 - 1, pts_s2_float[:, 0] / (2 * b - 1) * 2 - 1
        ],
                           axis=1)
        pts_so3 = np.clip(pts_so3, -1, 1)

        features = np.asarray(
            compute(pts_s2_float, np.linalg.norm(pts, axis=1), 2 * b, b,
                    np.sin(np.pi * (2 * np.arange(2 * b) + 1) / 4 / b)))
        features = np.moveaxis(features, [0, 1, 2], [2, 0, 1])[None]

        return features.astype(np.float32), pts_so3.astype(
            np.float32), segs.astype(np.int64), pts @ rand_rot, labels.astype(
                np.int64)
Esempio n. 23
0
    def __getitem__(self, index):
        b = hyper.BANDWIDTH_IN
        pts = np.array(self.pts[index])

        # randomly sample points
        sub_idx = np.random.randint(0, pts.shape[0],  hyper.N_PTCLOUD)
        pts = pts[sub_idx]
        if self.aug:
            rot = rnd_rot()
            pts = np.einsum('ij,nj->ni', rot, pts)
            pts += np.random.rand(3)[None, :] * 0.05
            pts = np.einsum('ij,nj->ni', rot.T, pts)
        segs = np.array(self.segs[index])
        segs = segs[sub_idx]
        labels = self.labels[index]

        pts_norm = np.linalg.norm(pts, axis=1)
        pts_normed = pts / pts_norm[:, None]
        rand_rot = rnd_rot() if self.rand_rot else np.eye(3)
        rotated_pts_normed = np.clip(pts_normed @ rand_rot, -1, 1)

        pts_s2 = S2.change_coordinates(rotated_pts_normed, p_from='C', p_to='S')
        pts_s2[:, 0] *= 2 * b / np.pi  # [0, pi]
        pts_s2[:, 1] *= b / np.pi
        pts_s2[:, 1][pts_s2[:, 1] < 0] += 2 * b

        pts_s2_float = pts_s2

        # N * 3
        pts_so3 = np.stack([pts_norm * 2 - 1, pts_s2_float[:, 1] / (2 * b - 1) * 2 - 1, pts_s2_float[:, 0] / (2 * b - 1) * 2 - 1], axis=1)
        pts_so3 = np.clip(pts_so3, -1, 1)

        # one hundred times speed up !
        features = np.asarray(compute(pts_s2_float, np.linalg.norm(pts, axis=1), hyper.R_IN, b, np.sin(np.pi * (2 * np.arange(2 * b) + 1) / 4 / b)))
    
        print('SSS', type(pts), pts.shape, pts_so3.shape, features.shape) # 2048 x 3, 2048 x 3, 64 x 64 x 64
        print('Mins/maxs/avg pts', pts.min(0), pts.max(0), pts.mean(0))
        print('Mins/maxs p so3ts', pts_so3.min(0), pts_so3.max(0))

        return features.astype(np.float32), pts_so3.astype(np.float32), segs.astype(np.int64), pts @ rand_rot, labels.astype(np.int64)
Esempio n. 24
0
def compare_naive_and_spectral_conv():

    f1 = lambda t, p: sh(l=2,
                         m=1,
                         theta=t,
                         phi=p,
                         field='real',
                         normalization='quantum',
                         condon_shortley=True)
    f2 = lambda t, p: sh(l=2,
                         m=1,
                         theta=t,
                         phi=p,
                         field='real',
                         normalization='quantum',
                         condon_shortley=True)

    theta, phi = S2.meshgrid(b=4, grid_type='Gauss-Legendre')
    f1_grid = f1(theta, phi)
    f2_grid = f2(theta, phi)

    alpha, beta, gamma = S3.meshgrid(b=4,
                                     grid_type='SOFT')  # TODO check convention

    f12_grid_spectral = spectral_S2_conv(f1_grid,
                                         f2_grid,
                                         s2_fft=None,
                                         so3_fft=None)

    f12_grid = np.zeros_like(alpha)
    for i in range(alpha.shape[0]):
        for j in range(alpha.shape[1]):
            for k in range(alpha.shape[2]):
                f12_grid[i, j, k] = naive_S2_conv(f1, f2, alpha[i, j, k],
                                                  beta[i, j, k], gamma[i, j,
                                                                       k])
                print(i, j, k, f12_grid[i, j, k])

    return f1_grid, f2_grid, f12_grid, f12_grid_spectral
Esempio n. 25
0
def naive_S2_conv(f1, f2, alpha, beta, gamma, g_parameterization='EA323'):
    """
    Compute int_S^2 f1(x) f2(g^{-1} x)* dx,
    where x = (theta, phi) is a point on the sphere S^2,
    and g = (alpha, beta, gamma) is a point in SO(3) in Euler angle parameterization

    :param f1, f2: functions to be convolved
    :param alpha, beta, gamma: the rotation at which to evaluate the result of convolution
    :return:
    """

    # This fails
    def integrand(theta, phi):
        g_inv = SO3.invert((alpha, beta, gamma),
                           parameterization=g_parameterization)
        g_inv_theta, g_inv_phi, _ = SO3.transform_r3(
            g=g_inv,
            x=(theta, phi, 1.),
            g_parameterization=g_parameterization,
            x_parameterization='S')
        return f1(theta, phi) * f2(g_inv_theta, g_inv_phi).conj()

    return S2.integrate(f=integrand, normalize=True)
Esempio n. 26
0
def linspace(b, grid_type='SOFT'):
    """
    Compute a linspace on the 3-sphere.

    Since S3 is ismorphic to SO(3), we use the grid grid_type from:
    FFTs on the Rotation Group
    Peter J. Kostelec and Daniel N. Rockmore
    http://www.cs.dartmouth.edu/~geelong/soft/03-11-060.pdf
    :param b:
    :return:
    """
    # alpha = 2 * np.pi * np.arange(2 * b) / (2. * b)
    # beta = np.pi * (2 * np.arange(2 * b) + 1) / (4. * b)
    # gamma = 2 * np.pi * np.arange(2 * b) / (2. * b)

    beta, alpha = S2.linspace(b, grid_type)

    # According to this paper:
    # "Sampling sets and quadrature formulae on the rotation group"
    # We can just tack a sampling grid for S^1 to a sampling grid for S^2 to get a sampling grid for SO(3).
    gamma = 2 * np.pi * np.arange(2 * b) / (2. * b)

    return alpha, beta, gamma
Esempio n. 27
0
def test_S2FFT():

    L_max = 10
    beta, alpha = S2.meshgrid(b=L_max + 1, grid_type='Driscoll-Healy')
    lt = setup_legendre_transform(b=L_max + 1)
    lti = setup_legendre_transform_indices(b=L_max + 1)

    for l in range(L_max):
        for m in range(-l, l + 1):

            Y = sh(l,
                   m,
                   beta,
                   alpha,
                   field='complex',
                   normalization='seismology',
                   condon_shortley=True)

            y_hat = sphere_fft(Y, lt, lti)

            # The flat index for (l, m) is l^2 + l + m
            # Before the harmonics of degree l, there are this many harmonics: sum_{i=0}^{l-1} 2i+1 = l^2
            # There are 2l+1 harmonics of degree l, with order m=0 at the center,
            # so the m-th harmonic of degree is at l + m within the block of degree l.
            y_hat_true = np.zeros_like(y_hat)
            y_hat_true[l**2 + l + m] = 1

            diff = np.sum(np.abs(y_hat - y_hat_true))
            nz = 1. - np.isclose(y_hat, 0.)
            diff_nz = np.sum(np.abs(nz - y_hat_true))
            print(l, m, diff, diff_nz)
            print(np.round(y_hat, 4))
            print(y_hat_true)
            # assert np.isclose(diff, 0.)  # TODO make this work
            print(nz)
            assert np.isclose(diff_nz, 0.)
Esempio n. 28
0
    def __getitem__(self, index):
        b = hyper.BANDWIDTH_IN
        pts = np.array(self.pts[index])

        # randomly sample points
        sub_idx = np.random.randint(0, pts.shape[0], hyper.N_PTCLOUD)
        pts = pts[sub_idx]
        if self.aug:
            rot = rnd_rot()
            np.einsum('ij,nj->ni', rot, pts)
            pts += np.random.rand(3)[None, :] * 0.05
            np.einsum('ij,nj->ni', rot.T, pts)
        segs = np.array(self.segs[index])
        segs = segs[sub_idx]
        labels = self.labels[index]

        pts_norm = np.linalg.norm(pts, axis=1)
        pts_normed = pts / pts_norm[:, None]
        rand_rot = rnd_rot() if self.rand_rot else np.eye(3)
        rotated_pts_normed = np.clip(pts_normed @ rand_rot, -1, 1)

        pts_s2 = S2.change_coordinates(rotated_pts_normed,
                                       p_from='C',
                                       p_to='S')
        pts_s2[:, 0] *= 2 * b / np.pi  # [0, pi]
        pts_s2[:, 1] *= b / np.pi
        pts_s2[:, 1][pts_s2[:, 1] < 0] += 2 * b

        pts_s2_float = pts_s2
        pts_s2 = (pts_s2 + 0.5).astype(np.int)
        pts_s2[:, 0] = np.clip(pts_s2[:, 0], 0, 2 * b - 1)
        pts_s2[:, 1] = np.clip(pts_s2[:, 1], 0, 2 * b - 1)  # [0, 2pi]

        # N * 3
        pts_so3 = np.stack([
            pts_norm * 2 - 1, pts_s2_float[:, 1] /
            (2 * b - 1) * 2 - 1, pts_s2_float[:, 0] / (2 * b - 1) * 2 - 1
        ],
                           axis=1)
        pts_so3 = np.clip(pts_so3, -1, 1)

        # cache data
        try:
            if self.cache_dir is None:
                raise FileNotFoundError
            features = np.load(
                os.path.join(self.cache_dir, 'features%d.npy' % index))
        except (OSError, FileNotFoundError):
            features = []
            interval = 1. / hyper.R_IN

            dist = np.linalg.norm(pts, axis=1)

            # adaptive sampling
            wt = np.sin(np.pi * (2 * np.arange(2 * b) + 1) / 4 / b)

            # TODO: rewrite this in an efficient way
            for i in range(hyper.R_IN):
                idx = (dist < (i + 2) * interval) & (dist > i * interval)
                pts_idx = pts_s2[idx]
                pts_idx_float = pts_s2_float[idx]
                im = np.zeros([2 * b, 2 * b], np.float32)
                for beta in range(2 * b):
                    filt = (pts_idx[:, 0] == beta)
                    for alpha in range(2 * b):
                        filt_alpha = filt & (
                            pts_idx_float[:, 1] > alpha - 1. / 2 / wt[beta]
                        ) & (pts_idx_float[:, 1] < alpha + 1. / 2 / wt[beta])
                        if not np.any(filt_alpha):
                            continue
                        im[beta,
                           alpha] = (1 - np.abs(dist[idx][filt_alpha] -
                                                (i + 1) * interval) / interval
                                     ).sum() / np.count_nonzero(filt_alpha)
                features.append(im)
            features = np.stack(features, axis=0)
            if self.cache_dir is not None:
                np.save(os.path.join(self.cache_dir, 'features%d.npy' % index),
                        features)

        return features, pts_so3.astype(np.float32), segs.astype(
            np.int64), pts @ rand_rot, labels.astype(np.int64)
Esempio n. 29
0
def inverse_render_model(points: np.ndarray, sgrid: np.ndarray):
    # wait for implementing
    print("Aloha")

    x = points[:, 0]
    y = points[:, 1]
    z = points[:, 2]
    # Fistly, we get the centroid, then translate the points
    centroid_x = np.sum(x) / points.shape[0]
    centroid_y = np.sum(y) / points.shape[0]
    centroid_z = np.sum(z) / points.shape[0]
    centroid = np.array([centroid_x, centroid_y, centroid_z])
    points = points.astype(np.float)
    points -= centroid

    # After normalization, compute the distance between the sphere and points

    radius = np.sqrt(points[:, 0] ** 2 + points[:, 1] ** 2 + points[:, 2] ** 2)
    # dist = 1 - (1 / np.max(radius)) * radius

    # Projection
    from lie_learn.spaces import S2
    radius = np.repeat(radius, 3).reshape(-1, 3)
    points_on_sphere = points / radius
    # ssgrid = sgrid.reshape(-1, 3)
    # phi, theta = S2.change_coordinates(ssgrid, p_from='C', p_to='S')
    out = S2.change_coordinates(points_on_sphere, p_from='C', p_to='S')

    phi = out[..., 0]
    theta = out[..., 1]

    phi = phi
    theta = theta % (np.pi * 2)

    # Interpolate
    b = sgrid.shape[0] / 2  # bandwidth
    # By computing the m,n, we can find
    # the neighbours on the sphere
    m = np.trunc((phi - np.pi / (4 * b)) / (np.pi / (2 * b)))
    m = m.astype(int)
    n = np.trunc(theta / (np.pi / b))
    n = n.astype(int)

    dist_im, center_grid, east_grid, south_grid, southeast_grid = interpolate(m=m, n=n, sgrid=sgrid,
                                                                              points_on_sphere=points_on_sphere,
                                                                              radius=radius)
    coef, intercept,center_points =angle(m=m,n=n,sgrid=sgrid,dist_im=dist_im)
    # utilizing linear regression to create a plane

    # use a mask to avoid the index out of the boundary
    """
    mask_m = m - 1 >= 0
    mask = mask_m
    m = m[mask]
    n = n[mask]
    """

    # =======================================================================================
    fig = plt.figure()
    grid = make_sgrid(bandwidth, 0, 0, 0)
    grid = grid.reshape((-1, 3))

    xx = grid[:, 0]
    yy = grid[:, 1]
    zz = grid[:, 2]
    xx = xx.reshape(-1, 1)
    yy = yy.reshape(-1, 1)
    zz = zz.reshape(-1, 1)
    ax = Axes3D(fig)
    ax.scatter(0, 0, 0)

    ax.scatter(points[:, 0], points[:, 1], points[:, 2])
    ax.scatter(points_on_sphere[:, 0], points_on_sphere[:, 1], points_on_sphere[:, 2])

    ax.scatter(center_grid[:, 0], center_grid[:, 1], center_grid[:, 2])
    ax.scatter(east_grid[:, 0], east_grid[:, 1], east_grid[:, 2])
    ax.scatter(south_grid[:, 0], south_grid[:, 1], south_grid[:, 2])
    ax.scatter(southeast_grid[:, 0], southeast_grid[:, 1], southeast_grid[:, 2])
    # ax.scatter(xx, yy, zz)
    # plt.legend()

    # draw line
    ax = fig.gca(projection='3d')
    zero = np.zeros(points_on_sphere.shape[0])
    ray_x = np.stack((zero, points_on_sphere[:, 0]), axis=1).reshape(-1, 2)
    ray_y = np.stack((zero, points_on_sphere[:, 1]), axis=1).reshape(-1, 2)
    ray_z = np.stack((zero, points_on_sphere[:, 2]), axis=1).reshape(-1, 2)
    for index in range(points_on_sphere.shape[0]):
        ax.plot(ray_x[index], ray_y[index], ray_z[index])

    # draw plane
    for index in range(center_points.shape[0]):
        X = np.arange(center_points[index, 0] - 0.05, center_points[index, 0] + 0.05, 0.01)
        Y = np.arange(center_points[index, 1] - 0.05, center_points[index, 1] + 0.05, 0.01)
        X, Y = np.meshgrid(X, Y)
        a1 = coef[index, 0]
        a2 = coef[index, 1]
        b = intercept[index]
        Z = a1 * X + a2 * Y + b
        surf = ax.plot_surface(X, Y, Z)

    plt.show()
    im = dist_im
    return im
 def f1a(xs):
     xc = S2.change_coordinates(coords=xs, p_from='S', p_to='C')
     return xc[..., 0]**2 * xc[..., 1] - 1.4 * xc[..., 2] * xc[
         ..., 1]**3 + xc[..., 1] - xc[..., 2]**2 + 2.