def eval_vol(self, vol_true, vol_est): norm_true = anorm(vol_true) err = anorm(vol_true - vol_est) rel_err = err / norm_true corr = acorr(vol_true, vol_est) return {'err': err, 'rel_err': rel_err, 'corr': corr}
def testPhaseFlip(self): self.sim.phase_flip() imgs_pf = self.sim.images(start=0, num=self.n) # check energy conservation self.assertTrue( np.allclose( anorm(self.imgs_org.asnumpy(), axes=(1, 2)), anorm(imgs_pf.asnumpy(), axes=(1, 2)), ))
def eval_volmat(self, volmat_true, volmat_est): """ Evaluate volume matrix estimation accuracy :param volmat_true: The true volume matrices in the form of an L-by-L-by-L-by-L-by-L-by-L-by-K array. :param volmat_est: The estimated volume matrices in the same form. :return: """ norm_true = anorm(volmat_true) err = anorm(volmat_true - volmat_est) rel_err = err / norm_true corr = acorr(volmat_true, volmat_est) return {'err': err, 'rel_err': rel_err, 'corr': corr}
def testDownsample(self): # generate a 3D map with density decays as Gaussian function g3d = grid_3d(self.L, dtype=self.dtype) coords = np.array( [g3d["x"].flatten(), g3d["y"].flatten(), g3d["z"].flatten()]) sigma = 0.2 vol = np.exp(-0.5 * np.sum(np.abs(coords / sigma)**2, axis=0)).astype( self.dtype) vol = np.reshape(vol, g3d["x"].shape) vols = Volume(vol) # set noise to zero and CFT filters to unity for simulation object noise_var = 0 noise_filter = ScalarFilter(dim=2, value=noise_var) sim = Simulation( L=self.L, n=self.n, vols=vols, offsets=0.0, amplitudes=1.0, unique_filters=[ ScalarFilter(dim=2, value=1) for d in np.linspace(1.5e4, 2.5e4, 7) ], noise_filter=noise_filter, dtype=self.dtype, ) # get images before downsample imgs_org = sim.images(start=0, num=self.n) # get images after downsample max_resolution = 32 sim.downsample(max_resolution) imgs_ds = sim.images(start=0, num=self.n) # Check individual grid points self.assertTrue( np.allclose( imgs_org[:, 32, 32], imgs_ds[:, 16, 16], atol=utest_tolerance(self.dtype), )) # check resolution self.assertTrue(np.allclose(max_resolution, imgs_ds.shape[1])) # check energy conservation after downsample self.assertTrue( np.allclose( anorm(imgs_org.asnumpy(), axes=(1, 2)) / self.L, anorm(imgs_ds.asnumpy(), axes=(1, 2)) / max_resolution, atol=utest_tolerance(self.dtype), ))
def eval_eigs(self, eigs_est, lambdas_est): """ Evaluate covariance eigendecomposition accuracy :param eigs_est: The estimated volume eigenvectors in an L-by-L-by-L-by-K array. :param lambdas_est: The estimated eigenvalues in a K-by-K diagonal matrix (default `diag(ones(K, 1))`). :return: """ eigs_true, lambdas_true = self.eigs() B = vol_to_vec(eigs_est).T @ vol_to_vec(eigs_true) norm_true = anorm(lambdas_true) norm_est = anorm(lambdas_est) inner = ainner(B @ lambdas_true, lambdas_est @ B) err = np.sqrt(norm_true**2 + norm_est**2 - 2 * inner) rel_err = err / norm_true corr = inner / (norm_true * norm_est) # TODO: Determine Principal Angles and return as a dict value return {'err': err, 'rel_err': rel_err, 'corr': corr}
def setUp(self): L = 8 n = 32 C = 1 SNR = 1 pixel_size = 5 voltage = 200 defocus_min = 1.5e4 defocus_max = 2.5e4 defocus_ct = 7 Cs = 2.0 alpha = 0.1 filters = [ RadialCTFFilter(pixel_size, voltage, defocus=d, Cs=2.0, alpha=0.1) for d in np.linspace(defocus_min, defocus_max, defocus_ct) ] # Since FFBBasis2D doesn't yet implement dtype, we'll set this to double to match its built in types. sim = Simulation(n=n, C=C, filters=filters, dtype='double') vols = np.load(os.path.join(DATA_DIR, 'clean70SRibosome_vol.npy')) vols = vols[..., np.newaxis] vols = downsample(vols, (L * np.ones(3, dtype=int))) sim.vols = vols self.basis = FFBBasis2D((L, L)) # use new methods to generate random rotations and clean images sim.rots = qrand_rots(n, seed=0) self.imgs_clean = vol2img(vols[..., 0], sim.rots) self.h_idx = np.array([filters.index(f) for f in sim.filters]) self.filters = filters self.h_ctf_fb = [filt.fb_mat(self.basis) for filt in self.filters] self.imgs_ctf_clean = sim.eval_filters(self.imgs_clean) sim.cache(self.imgs_ctf_clean) power_clean = anorm(self.imgs_ctf_clean)**2 / np.size( self.imgs_ctf_clean) self.noise_var = power_clean / SNR self.imgs_ctf_noise = self.imgs_ctf_clean + np.sqrt( self.noise_var) * randn(L, L, n, seed=0) self.cov2d = RotCov2D(self.basis) self.coeff_clean = self.basis.evaluate_t(self.imgs_clean) self.coeff = self.basis.evaluate_t(self.imgs_ctf_noise)
def vol_coords(self, mean_vol=None, eig_vols=None): """ Coordinates of simulation volumes in a given basis :param mean_vol: A mean volume in the form of an L-by-L-by-L array (default `mean_true`). :param eig_vols: A set of eigenvolumes in an L-by-L-by-L-by-K array (default `eigs`). :return: """ if mean_vol is None: mean_vol = self.mean_true() if eig_vols is None: eig_vols = self.eigs()[0] vols = self.vols - np.expand_dims(mean_vol, 3) coords = vol_to_vec(eig_vols).T @ vol_to_vec(vols) res = vols - vec_to_vol(vol_to_vec(eig_vols) @ coords) res_norms = np.diag(anorm(res, (0, 1, 2))) res_inners = vol_to_vec(mean_vol).T @ vol_to_vec(res) return coords.squeeze(), res_norms, res_inners
def eval_coords(self, mean_vol, eig_vols, coords_est): """ Evaluate coordinate estimation :param mean_vol: A mean volume in the form of an L-by-L-by-L array. :param eig_vols: A set of eigenvolumes in an L-by-L-by-L-by-K array. :param coords_est: The estimated coordinates in the affine space defined centered at `mean_vol` and spanned by `eig_vols`. :return: """ coords_true, res_norms, res_inners = self.vol_coords( mean_vol, eig_vols) # 0-indexed states vector states = self.states - 1 coords_true = coords_true[states] res_norms = res_norms[states] res_inners = res_inners[states] mean_eigs_inners = np.asscalar( vol_to_vec(mean_vol).T @ vol_to_vec(eig_vols)) coords_err = coords_true - coords_est err = np.hypot(res_norms, coords_err) mean_vol_norm2 = anorm(mean_vol)**2 norm_true = np.sqrt(coords_true**2 + mean_vol_norm2 + 2 * res_inners + 2 * mean_eigs_inners * coords_true) norm_true = np.hypot(res_norms, norm_true) rel_err = err / norm_true inner = mean_vol_norm2 + mean_eigs_inners * ( coords_true + coords_est) + coords_true * coords_est + res_inners norm_est = np.sqrt(coords_est**2 + mean_vol_norm2 + 2 * mean_eigs_inners * coords_est) corr = inner / (norm_true * norm_est) return {'err': err, 'rel_err': rel_err, 'corr': corr}
logger.info( f'Finish normal FB expansion of original images in {dtime:.4f} seconds.') # Reconstruct images from the expansion coefficients based on FB basis fb_images = fb_basis.evaluate(fb_coeffs) logger.info( 'Finish reconstruction of images from normal FB expansion coefficients.') # Calculate the mean value of maximum differences between the FB estimated images and the original images fb_meanmax = np.mean(np.max(abs(fb_images - org_images), axis=2)) logger.info( f'Mean value of maximum differences between FB estimated images and original images: {fb_meanmax}' ) # Calculate the normalized RMSE of the FB estimated images nrmse_ims = anorm(fb_images - org_images) / anorm(org_images) logger.info(f'FB estimated images normalized RMSE: {nrmse_ims}') # plot the first images using the normal FB method plt.subplot(3, 4, 1) plt.imshow(np.real(org_images[..., 0]), cmap='gray') plt.title('Original') plt.subplot(3, 4, 5) plt.imshow(np.real(fb_images[..., 0]), cmap='gray') plt.title('FB Image') plt.subplot(3, 4, 9) plt.imshow(np.real(org_images[..., 0] - fb_images[..., 0]), cmap='gray') plt.title('Differences') # Specify the fast FB basis method for expanding the 2D images ffb_basis = FFBBasis2D((img_size, img_size))
h_idx = np.array([filters.index(f) for f in sim.filters]) # Evaluate CTF in the 8X8 FB basis h_ctf_fb = [filt.fb_mat(ffbbasis) for filt in filters] # Apply the CTF to the clean images. logger.info('Apply CTF filters to clean images.') imgs_ctf_clean = Image(sim.eval_filters(imgs_clean)) sim.cache(imgs_ctf_clean) # imgs_ctf_clean is an Image object. Convert to numpy array for subsequent statements imgs_ctf_clean = imgs_ctf_clean.asnumpy() # Apply the noise at the desired singal-noise ratio to the filtered clean images logger.info('Apply noise filters to clean images.') power_clean = anorm(imgs_ctf_clean)**2 / np.size(imgs_ctf_clean) noise_var = power_clean / sn_ratio imgs_noise = imgs_ctf_clean + np.sqrt(noise_var) * randn( img_size, img_size, num_imgs, seed=0) # Expand the images, both clean and noisy, in the Fourier-Bessel basis. This # can be done exactly (that is, up to numerical precision) using the # `basis.expand` function, but for our purposes, an approximation will do. # Since the basis is close to orthonormal, we may approximate the exact # expansion by applying the adjoint of the evaluation mapping using # `basis.evaluate_t`. logger.info('Get coefficients of clean and noisy images in FFB basis.') coeff_clean = ffbbasis.evaluate_t(imgs_clean) coeff_noise = ffbbasis.evaluate_t(imgs_noise) # Create the Cov2D object and calculate mean and covariance for clean images without CTF.
def norm(self): return anorm(self.data)