def curve_phantom(curve, direction, kappa, px=(20,20,20), vox_dim=(100,100,100), cyl_rad=0.2, max_l=6, dtype=np.float32): # Setup grid xyz = np.array(np.meshgrid( np.linspace(-(px[0]/2)*vox_dim[0], (px[0]/2)*vox_dim[0], px[0]), np.linspace(-(px[1]/2)*vox_dim[1], (px[1]/2)*vox_dim[1], px[1]), np.linspace(-(px[2]/2)*vox_dim[2], (px[2]/2)*vox_dim[2], px[2]))) xyz = np.moveaxis(xyz, [0, 1], [-1, 1]) # Calculate directions and kappas diff = xyz[:,:,:,None,:] - curve dist = np.linalg.norm(diff, axis=-1) min_dist = np.min(dist, axis=-1) # min dist between grid points and curve t_index = np.argmin(dist, axis=-1) min_dir = direction[t_index] # directions for closest point on curve min_k = kappa[t_index] # kappas # Calculate watson spang_shape = xyz.shape[0:-1] + (util.maxl2maxj(max_l),) spang1 = spang.Spang(np.zeros(spang_shape), vox_dim=vox_dim) dot = np.einsum('ijkl,ml->ijkm', min_dir, spang1.sphere.vertices) k = min_k[...,None] watson = np.exp(k*dot**2)/(4*np.pi*hyp1f1(0.5, 1.5, k)) watson_sh = np.einsum('ijkl,lm', watson, spang1.B) watson_sh = watson_sh/watson_sh[...,None,0] # Normalize # Cylinder mask mask = min_dist < cyl_rad spang1.f = np.einsum('ijkl,ijk->ijkl', watson_sh, mask).astype(dtype) return spang1
def visualize(self, filename, **kwargs): # Calculate arrow positions X = np.float(self.g.shape[0]) Y = np.float(self.g.shape[1]) Z = np.float(self.g.shape[2]) - kwargs['z_shift'] max_dim = np.max([X, Y, Z]) tips = np.array([[(X - max_dim) / 2, Y / 2, Z / 2], [X / 2, Y / 2, (Z + max_dim) / 2]]) rr = 10 # Visualize each volume for i in range(self.g.shape[4]): for j in range(self.g.shape[3]): o = np.array([X / 2, Y / 2, Z / 2]) pol = self.pols[i, j, :] rexc = tips[i, :] - o rdet = tips[(i + 1) % 2, :] - o tip = np.cross(rdet, pol) tip_n = tip * np.linalg.norm(rexc) / np.linalg.norm(tip) if np.dot(tip_n, rexc) < 0: tip_n *= -1 arrows = np.array([[tip_n + o, rr * pol], [tip_n + o, -rr * pol]]) sp = spang.Spang(f=np.zeros(self.g.shape[0:3] + (15, )), vox_dim=self.vox_dim) # For visuals only sp.f[..., 0] = self.g[..., j, i] sp.visualize(filename + 'v' + str(i) + 'p' + str(j), viz_type='Density', arrows=arrows, arrow_color=np.array([1, 0, 0]), **kwargs)
def all_directions(px=(15,15,1), vox_dim=(100,100,100)): dims = px + (3,) # f = np.zeros(dims) # tp = np.array(np.meshgrid(np.linspace(0, np.pi/2, px[0]), # np.linspace(0, np.pi, px[1]), # np.linspace(0, 0, px[2]))) # tp = np.moveaxis(tp, [0, 1], [-1, 1]) # xyz = np.apply_along_axis(util.tp2xyz, -1, tp) xyz = util.fibonacci_sphere(np.prod(np.array(px)), xyz=True).reshape(dims) f = np.apply_along_axis(util.xyz_sft, -1, xyz, max_l=4) return spang.Spang(f, vox_dim=vox_dim)
def three_helix(vox_dim=(130,130,130), px=(64,64,64), radius=600, scale=[1,1,1]): phant = spang.Spang(np.zeros(px + (15,), dtype=np.float32), vox_dim=vox_dim) s = 20 phant1 = helix_phantom(px=(s,s,s), radius=radius, pitch=1000, vox_dim=vox_dim, max_l=4, center=(0,0,0), normal=0, trange=(-2*np.pi, 2*np.pi)) phant2 = helix_phantom(px=(s,s,s), radius=radius, pitch=1000, vox_dim=vox_dim, max_l=4, center=(0,0,0), normal=1, trange=(-2*np.pi, 2*np.pi)) phant3 = helix_phantom(px=(s,s,s), radius=radius, pitch=1000, vox_dim=vox_dim, max_l=4, center=(0,0,0), normal=2, trange=(-2*np.pi, 2*np.pi)) phant.f[0:s,0:s,0:s] = phant1.f*scale[0] phant.f[s:2*s,s:2*s,s:2*s] = phant2.f*scale[1] phant.f[2*s:3*s,2*s:3*s,2*s:3*s] = phant3.f*scale[2] return phant
def bead(orientation=[1,0,0], kappa=None, px=(32,32,32), vox_dim=(100,100,100), sphere=None): # orientation sets the axis of rotational symmetry # kappa = None: all along single axis # kappa = 0: angularly uniform # kappa > 0: dumbbell # kappa < 0: pancake dims = px + (15,) f = np.zeros(dims, dtype=np.float32) spang1 = spang.Spang(f, vox_dim=vox_dim) dot = np.dot(orientation, spang1.sphere.vertices.T) if kappa is None: spang1.f[px[0]//2, px[1]//2, px[2]//2, :] = util.xyz_sft(orientation, max_l=4) else: watson = np.exp(kappa*dot**2)/(4*np.pi*hyp1f1(0.5, 1.5, kappa)) watson_sh = np.matmul(spang1.B.T, watson) spang1.f[px[0]//2, px[1]//2, px[2]//2, :] = watson_sh return spang1
os.makedirs(out_folder) # Read data and save mips vox_dim = (130, 130, 130) # nm data1 = data.Data(vox_dim=vox_dim, det_nas=[1.1, 0.71]) order = np.array([[2, 1, 0, 3], [2, 3, 0, 1]]) data1.read_tiff(in_folder, order=order) # Specify voxel dimensions in nm vox_dim_data = [130, 130, 130] vox_dim_A = [130, 130, 549] vox_dim_B = [227, 227, 835.8] # Model for uniform distributions # Build microscope model spang1 = spang.Spang(f=np.zeros(data1.g.shape[0:3] + (15, )), vox_dim=vox_dim) m = multi.MultiMicroscope(spang1, data1, n_samp=1.33, lamb=525, spang_coupling=True) ## NEW # Measured values from fluorescent lake # 561 calibration data. Values measured by hand from unifrom ROIs in # /Volumes/lacie-win/2018-07-30-pol-dipsim in P0-P4 order (no swaps) epi_cal = np.array([[8150, 8550, 8650, 8350], [16250, 16750, 17000, 16500]]) ls_cal = np.array([[6050, 5200, 4900, 5800], [9570, 7350, 6700, 8800]]) # Calculate expected values from fluorescent lake lake_response = m.lake_response(data1)
# Generate data using forward model # set "snr" to a positive number to simulate Poisson noise data1.g = m.fwd(phant.f, snr=10) # Save data data1.save_mips(folder + 'data.pdf') # try "diSPIM_format=False" for a 5D ImageJ hyperstack (pol = c, view = t) data1.save_tiff(folder + 'data/', diSPIM_format=True) # Calculate pseudoinverse solution # set "eta" to a positive number for Tikhonov regularization etas = 10**(np.linspace(-5, 0, 10)) errors = [] for i, eta in enumerate(etas): phant1 = spang.Spang(np.zeros(phant.f.shape)) phant1.f = m.pinv(data1.g, eta=eta) # Calculate reconstruction statistics and save phant1.calc_stats() mask = phant.density > 0.1 # phant.visualize(folder+'phantom-recon/', mask=mask, interact=False, video=True, # n_frames=15) phant1.save_stats(folder + 'phantom-recon-' + str(i) + '/') phant1.save_summary(folder + 'phantom-recon-' + str(i) + '.pdf', mask=mask) error = np.linalg.norm((phant1.f - phant.f).flatten()) print(error) errors.append(error)