def covar_true(self): eigs_true, lamdbas_true = self.eigs() eigs_true = vol_to_vec(eigs_true) covar_true = eigs_true @ lamdbas_true @ eigs_true.T covar_true = vecmat_to_volmat(covar_true) return covar_true
def estimate(self, mean_vol, noise_variance): logger.info('Running Covariance Estimator') b_coeff = self.src_backward(mean_vol, noise_variance) est_coeff = self.conj_grad(b_coeff) covar_est = self.basis.mat_evaluate(est_coeff) covar_est = vecmat_to_volmat(make_symmat(volmat_to_vecmat(covar_est))) return covar_est
def src_backward(self, mean_vol, noise_variance, shrink_method=None): """ Apply adjoint mapping to source :return: The sum of the outer products of the mean-subtracted images in `src`, corrected by the expected noise contribution and expressed as coefficients of `basis`. """ covar_b = np.zeros((self.L, self.L, self.L, self.L, self.L, self.L), dtype=self.as_type) for i in range(0, self.n, self.batch_size): im = self.src.images(i, self.batch_size) batch_n = im.shape[-1] im_centered = im - self.src.vol_forward(mean_vol, i, self.batch_size) im_centered_b = np.zeros((self.L, self.L, self.L, batch_n), dtype=self.as_type) for j in range(batch_n): im_centered_b[:, :, :, j] = self.src.im_backward( im_centered[:, :, j], i + j) im_centered_b = vol_to_vec(im_centered_b) covar_b += vecmat_to_volmat( im_centered_b @ im_centered_b.T) / self.n covar_b_coeff = self.basis.mat_evaluate_t(covar_b) return self._shrink(covar_b_coeff, noise_variance, shrink_method)
def compute_kernel(self): # TODO: Most of this stuff is duplicated in MeanEstimator - move up the hierarchy? n = self.n L = self.L _2L = 2 * self.L kernel = np.zeros((_2L, _2L, _2L, _2L, _2L, _2L), dtype=self.as_type) filters_f = self.src.filters.evaluate_grid(L) sq_filters_f = np.array(filters_f**2, dtype=self.as_type) for i in tqdm(range(0, n, self.batch_size)): pts_rot = rotated_grids(L, self.src.rots[:, :, i:i + self.batch_size]) weights = sq_filters_f[:, :, self.src.filters.indices[i:i + self.batch_size]] weights *= self.src.amplitudes[i:i + self.batch_size]**2 if L % 2 == 0: weights[0, :, :] = 0 weights[:, 0, :] = 0 # TODO: This is where this differs from MeanEstimator pts_rot = m_reshape(pts_rot, (3, L**2, -1)) weights = m_reshape(weights, (L**2, -1)) batch_n = weights.shape[-1] factors = np.zeros((_2L, _2L, _2L, batch_n), dtype=self.as_type) # TODO: Numpy has got to have a functional shortcut to avoid looping like this! for j in range(batch_n): factors[:, :, :, j] = anufft3(weights[:, j], pts_rot[:, :, j], (_2L, _2L, _2L), real=True) factors = vol_to_vec(factors) kernel += vecmat_to_volmat(factors @ factors.T) / (n * L**8) # Ensure symmetric kernel kernel[0, :, :, :, :, :] = 0 kernel[:, 0, :, :, :, :] = 0 kernel[:, :, 0, :, :, :] = 0 kernel[:, :, :, 0, :, :] = 0 kernel[:, :, :, :, 0, :] = 0 kernel[:, :, :, :, :, 0] = 0 logger.info('Computing non-centered Fourier Transform') kernel = mdim_ifftshift(kernel, range(0, 6)) kernel_f = fftn(kernel) # Kernel is always symmetric in spatial domain and therefore real in Fourier kernel_f = np.real(kernel_f) return FourierKernel(kernel_f, centered=False)
def toeplitz(self, L=None): """ Compute the 3D Toeplitz matrix corresponding to this Fourier Kernel :param L: The size of the volumes to be convolved (default M/2, where the dimensions of this Fourier Kernel are MxMxM :return: An six-dimensional Toeplitz matrix of size L describing the convolution of a volume with this kernel """ if L is None: L = int(self.M / 2) A = np.eye(L**3, dtype=self.as_type) for i in range(L**3): A[:, i] = vol_to_vec(self.convolve_volume(vec_to_vol(A[:, i]))) A = vecmat_to_volmat(A) return A
def testVecmatToVolmat(self): m = np.empty((8, 27, 10)) m2 = vecmat_to_volmat(m) self.assertEqual(m2.shape, (2, 2, 2, 3, 3, 3, 10))