예제 #1
0
    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}
예제 #2
0
    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)),
            ))
예제 #3
0
    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}
예제 #4
0
    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),
            ))
예제 #5
0
    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}
예제 #6
0
    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)
예제 #7
0
    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
예제 #8
0
    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}
예제 #9
0
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))
예제 #10
0
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.
예제 #11
0
 def norm(self):
     return anorm(self.data)