def im_backproject(im, rot_matrices): """ Backproject images along rotation :param im: An L-by-L-by-n array of images to backproject. :param rot_matrices: An 3-by-3-by-n array of rotation matrices corresponding to viewing directions. :return: An L-by-L-by-L volumes corresponding to the sum of the backprojected images. """ L, _, n = im.shape ensure(L == im.shape[1], "im must be LxLxK") ensure(n == rot_matrices.shape[2], "No. of rotation matrices must match the number of images") pts_rot = rotated_grids(L, rot_matrices) pts_rot = m_reshape(pts_rot, (3, -1)) im_f = centered_fft2(im) / (L**2) if L % 2 == 0: im_f[0, :, :] = 0 im_f[:, 0, :] = 0 im_f = m_flatten(im_f) plan = Plan(sz=(L, L, L), fourier_pts=pts_rot) vol = np.real(plan.adjoint(im_f)) / L return vol
def testTransform2(self): if not backend_available('pynfft'): raise SkipTest vol = np.load(os.path.join(DATA_DIR, 'nfft_volume.npy')) fourier_pts = np.array([ [ 0.88952655922411, 0.35922344760724, -0.17107966400962, -0.70138277562649], [ 1.87089316522016, 1.99362869011803, 2.11636421501590, 2.23909973991377], [-3.93035749861843, -3.36417300942290, -2.79798852022738, -2.23180403103185] ]) plan = Plan(vol.shape, fourier_pts, backend='pynfft') result = plan.transform(vol) self.assertTrue(np.allclose( result, [-0.05646675 + 1.503746j, 1.677600 + 0.6610926j, 0.9124417 - 0.7394574j, -0.9136836 - 0.5491410j] ))
def vol_project(vol, rot_matrices): L = vol.shape[0] n = rot_matrices.shape[-1] pts_rot = rotated_grids(L, rot_matrices) # TODO: rotated_grids might as well give us correctly shaped array in the first place pts_rot = m_reshape(pts_rot, (3, L**2 * n)) im_f = 1. / L * Plan(vol.shape, pts_rot).transform(vol) im_f = m_reshape(im_f, (L, L, -1)) if L % 2 == 0: im_f[0, :, :] = 0 im_f[:, 0, :] = 0 im = centered_ifft2(im_f) return np.real(im)
def vol2img(volume, rots, L=None, dtype=None): """ Generate 2D images from the input volume and rotation angles The function handles odd and even-sized arrays correctly. The center of an odd array is taken to be at (n+1)/2, and an even array is n/2+1. :param volume: A 3D volume objects. :param rots: A n-by-3-by-3 array of rotation angles. :param L: The output size of 2D images. :return: An array consists of 2D images. """ if L is None: L = np.size(volume, 0) if dtype is None: dtype = volume.dtype lv = np.size(volume, 0) if L > lv + 1: # For compatibility with gen_projections, allow one pixel aliasing. # More precisely, it should be N>nv, however, by using nv+1 the # results match those of gen_projections. if np.mod(L - lv, 2) == 1: raise RuntimeError( 'Upsampling from odd to even sizes or vice versa is ' 'currently not supported') dL = np.floor((L - lv) / 2) fv = centered_fft3(volume) padded_volume = np.zeros((L, L, L), dtype=dtype) padded_volume[dL + 1:dL + lv + 1, dL + 1:dL + lv + 1, dL + 1:dL + lv + 1] = fv volume = centered_ifft3(padded_volume) ensure( np.norm(np.imag(volume[:])) / np.norm(volume[:]) < 1.0e-5, "The image part of volume is related large (>1.0e-5).") # The new volume size lv = L grid2d = grid_2d(lv, shifted=True, normalized=False) num_pts = lv**2 num_rots = rots.shape[0] pts = np.pi * np.vstack([ grid2d['x'].flatten('F'), grid2d['y'].flatten('F'), np.zeros(num_pts) ]) pts_rot = np.zeros((3, num_pts, num_rots)) for i in range(num_rots): pts_rot[:, :, i] = rots[i, :, :].T @ pts pts_rot = m_reshape(pts_rot, (3, lv**2 * num_rots)) pts_rot = -2 * pts_rot / lv im_f = Plan(volume.shape, -pts_rot).transform(volume) im_f = m_reshape(im_f, (lv, lv, -1)) if lv % 2 == 0: pts_rot = m_reshape(pts_rot, (3, lv, lv, num_rots)) im_f = im_f * np.exp(1j * np.sum(pts_rot, 0) / 2) im_f = im_f * np.expand_dims( np.exp(2 * np.pi * 1j * (grid2d['x'] + grid2d['y'] - 1) / (2 * lv)), 2) im = centered_ifft2(im_f) if lv % 2 == 0: im = im * m_reshape( np.exp(2 * np.pi * 1j * (grid2d['x'] + grid2d['y']) / (2 * lv)), (lv, lv, 1)) return np.real(im)