class SphericalHarmonic: def __init__(self, input_, copy_=True, max_l=None, norm=4): """ Projects `input_` to its spherical harmonics basis up to degree `max_l`. norm = 4 means orthonormal harmonics. For more details, please see https://shtools.oca.eu/shtools/pyshexpanddh.html """ if copy_: self.spatial = input_.copy() else: self.spatial = input_ if not isinstance(self.spatial, EnvironmentMap): self.spatial = EnvironmentMap(self.spatial, 'LatLong') if self.spatial.format_ != "latlong": self.spatial = self.spatial.convertTo("latlong") self.norm = norm self.coeffs = [] for i in range(self.spatial.data.shape[2]): self.coeffs.append( SHExpandDH(self.spatial.data[:, :, i], norm=norm, sampling=2, lmax_calc=max_l)) def reconstruct(self, height=None, max_l=None, clamp_negative=True): """ :height: height of the reconstructed image :clamp_negative: Remove reconstructed values under 0 """ retval = [] for i in range(len(self.coeffs)): retval.append( MakeGridDH(self.coeffs[i], norm=self.norm, sampling=2, lmax=height, lmax_calc=max_l)) retval = np.asarray(retval).transpose((1, 2, 0)) if clamp_negative: retval = np.maximum(retval, 0) return retval
class SphericalHarmonic: def __init__(self, input_, copy_=True, max_l=None, norm=4): """ Projects `input_` to its spherical harmonics basis up to degree `max_l`. norm = 4 means orthonormal harmonics. For more details, please see https://shtools.oca.eu/shtools/pyshexpanddh.html """ if copy_: self.spatial = input_.copy() else: self.spatial = input_ if not isinstance(self.spatial, EnvironmentMap): self.spatial = EnvironmentMap(self.spatial, 'LatLong') if self.spatial.format_ != "latlong": self.spatial = self.spatial.convertTo("latlong") self.norm = norm #from cffi import FFI #ffi = FFI() #ffi.cdef(""" # void generateAssociatedLegendreFactors(const float N, float *data_out, const float * nodes, const unsigned int num_nodes); #""") #if os.name == 'nt': # C = ffi.dlopen(os.path.join(os.path.dirname(os.path.realpath(__file__)), "spharm_tools.dll")) #else: # C = ffi.dlopen(os.path.join(os.path.dirname(os.path.realpath(__file__)), "spharm_tools.so")) self.coeffs = [] for i in range(self.spatial.data.shape[2]): self.coeffs.append( SHExpandDH(self.spatial.data[:, :, i], norm=norm, sampling=2, lmax_calc=max_l)) def reconstruct(self, height=None, max_l=None, clamp_negative=True): """ :height: height of the reconstructed image :clamp_negative: Remove reconstructed values under 0 """ retval = [] for i in range(len(self.coeffs)): retval.append( MakeGridDH(self.coeffs[i], norm=self.norm, sampling=2, lmax=height, lmax_calc=max_l)) retval = np.asarray(retval).transpose((1, 2, 0)) if clamp_negative: retval = np.maximum(retval, 0) #original fork return here ! #return retval # nodes = [] # weights = [] # for d in range(1, degrees + 2): # x, y = np.polynomial.legendre.leggauss(d) # nodes.extend(x) # weights.extend(y) retval = np.zeros((int((2 * (degrees + 1) + 1)**2 / 8), ch), dtype=np.complex128) P, nodes = _getP(envmap, degrees) print(degrees, P.shape) # Gauss-Legendre / Gauss-Chebyshev quadrature to speed up? # Perform in C # for j in range(envmap.data.shape[1]): # for k in range(ch): # #fmi = np.interp(nodes, np.linspace(-np.pi/2, np.pi/2, fm.shape[0]), np.squeeze(fm[:,j,k])) # i = 0 # for l in range(degrees + 1): # for m in range(0, l + 1): # retval[l,m,k] += fm * P[l,m] # i += 1 import operator i = 0 for l in tqdm(range(degrees + 1)): for m in range(0, l + 1): #coef = np.sqrt(( (2.*l+1.) / (4.*np.pi) ) * ( 1. / (functools.reduce(operator.mul, range(l-m+1, l+m+1), 1)) ) ) for c in range(ch): #retval[i,c] = np.nansum(coef*P[:,i]*np.squeeze(fm[:,m,c])) retval[i, c] = np.nansum(P[:, i] * np.squeeze(fm[:, m, c])) #import pdb; pdb.set_trace() #retval[i,c] = np.nansum(coef*P[:,i]*np.exp(1j*m*theta.ravel())*envmap.data.reshape([-1,ch])[:,c]) #retval[i,c] = np.nansum(coef*ref[:,i]*np.exp(-1j*m*(theta).ravel())*f[:,c]) #print("2: ", coef*P[:,i]*np.exp(1j*m*theta.ravel())*f[:,c]) i += 1 #import pdb; pdb.set_trace() from matplotlib import pyplot as plt #plt.scatter(nodes_cos, ref); plt.show() return retval
elif reduction_type == 'right': retval[_triangleRightSide(degrees)] = coeffs for i in set(range( (degrees + 1)**2)) - set(_triangleRightSide(degrees)): l = np.sqrt(i).astype('int') m = abs((l) - (i - l**2)) retval[i] = (-1)**m * np.conj(retval[l**2 + l + m]) return retval if __name__ == '__main__': from matplotlib import pyplot as plt e = EnvironmentMap('envmap.exr', 'angular') e.resize((64, 64)) e.convertTo('latlong') se = SphericalHarmonic(e) err = [] from tqdm import tqdm for i in tqdm(range(32)): recons = se.reconstruct(max_l=i) err.append(np.sum((recons - e.data)**2)) plt.plot(err) plt.figure() plt.imshow(recons) plt.show()