def downsample(self, ds_res): """ Downsample Image to a specific resolution. This method returns a new Image. :param ds_res: int - new resolution, should be <= the current resolution of this Image :return: The downsampled Image object. """ grid = grid_2d(self.res) grid_ds = grid_2d(ds_res) im_ds = np.zeros((ds_res, ds_res, self.n_images)).astype(self.dtype) # x, y values corresponding to 'grid'. This is what scipy interpolator needs to function. res_by_2 = self.res / 2 x = y = np.ceil(np.arange(-res_by_2, res_by_2)) / res_by_2 mask = (np.abs(grid['x']) < ds_res / self.res) & (np.abs(grid['y']) < ds_res / self.res) im = np.real( centered_ifft2(centered_fft2(self.data) * np.expand_dims(mask, 2))) for s in range(im_ds.shape[-1]): interpolator = RegularGridInterpolator((x, y), im[:, :, s], bounds_error=False, fill_value=0) im_ds[:, :, s] = interpolator(np.dstack([grid_ds['x'], grid_ds['y']])) return Image(im_ds)
def im_downsample(im, L_ds): """ Blur and downsample image :param im: Set of images to be downsampled in the form of an array L-by-L-by-K, where K is the number of images. :param L_ds: The desired resolution of the downsampled images. Must be smaller than L. :return: An array of the form L_ds-by-L_ds-by-K consisting of the blurred and downsampled images. """ N = im.shape[0] grid = grid_2d(N) grid_ds = grid_2d(L_ds) im_ds = np.zeros((L_ds, L_ds, im.shape[2])).astype(im.dtype) # x, y values corresponding to 'grid'. This is what scipy interpolator needs to function. x = y = np.ceil(np.arange(-N/2, N/2)) / (N/2) mask = (np.abs(grid['x']) < L_ds/N) & (np.abs(grid['y']) < L_ds/N) im = np.real(centered_ifft2(centered_fft2(im) * np.expand_dims(mask, 2))) for s in range(im_ds.shape[-1]): interpolator = RegularGridInterpolator( (x, y), im[:, :, s], bounds_error=False, fill_value=0 ) im_ds[:, :, s] = interpolator(np.dstack([grid_ds['x'], grid_ds['y']])) return im_ds
def im_filter(im, filt, *args, **kwargs): # TODO: Move inside appropriate object L = im.shape[0] im, sz_roll = unroll_dim(im, 3) filter_vals = filt.evaluate_grid(L, *args, **kwargs) im_f = centered_fft2(im) if im_f.ndim > filter_vals.ndim: im_f = np.expand_dims(filter_vals, 2) * im_f else: im_f = filter_vals * im_f im = centered_ifft2(im_f) im = np.real(im) im = roll_dim(im, sz_roll) return im
def filter(self, filter): """ Apply a `Filter` object to the Image. This method returns a new Image. :param filter: An object of type `Filter`. :return: A new filtered `Image` object. """ filter_values = filter.evaluate_grid(self.res) im_f = centered_fft2(self.data) if im_f.ndim > filter_values.ndim: im_f = np.expand_dims(filter_values, 2) * im_f else: im_f = filter_values * im_f im = centered_ifft2(im_f) im = np.real(im) return Image(im)
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 downsample(insamples, szout): """ Blur and downsample 1D to 3D objects such as, curves, images or volumes :param insamples: Set of objects to be downsampled in the form of an array, the last dimension is the number of objects. :param szout: The desired resolution of for output objects. :return: An array consists of the blurred and downsampled objects. """ ensure( insamples.ndim - 1 == szout.ndim, 'The number of downsampling dimensions is not the same as that of objects.' ) L_in = insamples.shape[0] L_out = szout.shape[0] ndata = insamples.shape(-1) outdims = szout outdims.push_back(ndata) outsamples = np.zeros((outdims)).astype(insamples.dtype) if insamples.ndim == 2: # one dimension object grid_in = grid_1d(L_in) grid_out = grid_1d(L_out) # x values corresponding to 'grid'. This is what scipy interpolator needs to function. x = np.ceil(np.arange(-L_in / 2, L_in / 2)) / (L_in / 2) mask = (np.abs(grid_in['x']) < L_out / L_in) insamples_fft = np.real( centered_ifft1(centered_fft1(insamples) * np.expand_dims(mask, 1))) for idata in range(ndata): interpolator = RegularGridInterpolator((x, ), insamples_fft[:, idata], bounds_error=False, fill_value=0) outsamples[:, :, idata] = interpolator(np.dstack([grid_out['x']])) elif insamples.ndim == 3: grid_in = grid_2d(L_in) grid_out = grid_2d(L_out) # x, y values corresponding to 'grid'. This is what scipy interpolator needs to function. x = y = np.ceil(np.arange(-L_in / 2, L_in / 2)) / (L_in / 2) mask = (np.abs(grid_in['x']) < L_out / L_in) & (np.abs(grid_in['y']) < L_out / L_in) insamples_fft = np.real( centered_ifft2(centered_fft2(insamples) * np.expand_dims(mask, 2))) for idata in range(ndata): interpolator = RegularGridInterpolator((x, y), insamples_fft[:, :, idata], bounds_error=False, fill_value=0) outsamples[:, :, idata] = interpolator( np.dstack([grid_out['x'], grid_out['y']])) elif insamples.ndim == 4: grid_in = grid_3d(L_in) grid_out = grid_3d(L_out) # x, y, z values corresponding to 'grid'. This is what scipy interpolator needs to function. x = y = z = np.ceil(np.arange(-L_in / 2, L_in / 2)) / (L_in / 2) mask = (np.abs(grid_in['x']) < L_out / L_in) & (np.abs( grid_in['y']) < L_out / L_in) & (np.abs(grid_in['z']) < L_out / L_in) insamples_fft = np.real( centered_ifft3(centered_fft3(insamples) * np.expand_dims(mask, 3))) for idata in range(ndata): interpolator = RegularGridInterpolator((x, y, z), insamples_fft[:, :, :, idata], bounds_error=False, fill_value=0) outsamples[:, :, :, idata] = interpolator( np.dstack([grid_out['x'], grid_out['y'], grid_out['z']])) return outsamples
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)