def batchreconstructcompact(self, img): nim = img.shape[0] r = np.mod(nim, 6) if r > 0: # pad with empty frames so total number of frames is divisible by 6 img = np.concatenate((img, np.zeros((6 - r, self.N, self.N), np.single))) nim = nim + 6 - r nim3 = nim // 3 imf = fft.rfft2(img) * self._prefilter[:, 0:self.N // 2 + 1] img2 = np.zeros([nim, 2 * self.N, 2 * self.N], dtype=np.single) for i in range(0, nim, 3): self._carray1[:, 0:self.N // 2, 0:self.N // 2 + 1] = imf[i:i + 3, 0:self.N // 2, 0:self.N // 2 + 1] self._carray1[:, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[i:i + 3, self.N // 2:self.N, 0:self.N // 2 + 1] img2[i:i + 3, :, :] = fft.irfft2(self._carray1) * self._reconfactor res = np.zeros((nim3, 2 * self.N, 2 * self.N), dtype=np.single) imgf = fft.rfft(img2[:, :self.N, :self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, :self.N, :self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, :self.N, self.N:2 * self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, :self.N, self.N:2 * self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, self.N:2 * self.N, :self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, self.N:2 * self.N, :self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, self.N:2 * self.N, self.N:2 * self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, self.N:2 * self.N, self.N:2 * self.N] = fft.irfft(imgf, nim3, 0) res = fft.irfft2(fft.rfft2(res) * self._postfilter[:, :self.N + 1]) return res
def rfft2(self, field): """Convenience wrapper for real-valued 2D FFT.""" if PYFFTW_AVAILABLE: num_thread = min(field.shape[0], self.max_num_thread) return fft.rfft2(field, norm="ortho", threads=num_thread) else: return fft.rfft2(field, norm="ortho")
def main(blur_name, kernel_data_name, deconvolved_name): with h5py.File(kernel_data_name, 'r') as h5f: kernel = h5f['dataset_1'][:] # cut the low frequency components out, since we know they don't # contain any useful information. This has the side-effect of # significantly speeding up the deconvolution. # x, y, _ = kernel.shape # shift = np.fft.fftshift(kernel) # shift_clip = shift[floor(x/2 - 20):ceil(x/2 + 20), floor(y/2-20):ceil(y/2 + 20), :] # kernel_small = np.fft.fftshift(shift_clip) blur = plt.imread(blur_name)[:, :, :3] print("Kernel has size: " + str(kernel.shape[:2])) print("Blurred image has size: " + str(blur.shape[:2])) kernel, blur = resize_to_fit(kernel, blur) print("Cropped to size: " + str(blur.shape[:2])) # deconvolved = restoration.richardson_lucy(blur, kernel_small) blur_f = fft.rfft2(blur, axes=(0, 1), threads=16) kernel_f = fft.rfft2(kernel, axes=(0, 1), threads=16) deconvolved_f = blur_f / kernel_f deconvolved = np.nan_to_num(fft.irfft2(deconvolved_f, axes=(0, 1), threads=16)) imwrite(deconvolved_name, deconvolved)
def reconstructframe_rfftw(self, img, i): diff = img - self._imgstore[i, :, :] imf = fft.rfft2(diff) * self._prefilter[:, 0:self.N // 2 + 1] self._carray1[0, 0:self.N // 2, 0:self.N // 2 + 1] = imf[0:self.N // 2, 0:self.N // 2 + 1] self._carray1[0, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[self.N // 2:self.N, 0:self.N // 2 + 1] img2 = fft.irfft2(self._carray1[0, :, :]) * self._reconfactor[i, :, :] self._imgstore[i, :, :] = img self._bigimgstore = self._bigimgstore + fft.irfft2(fft.rfft2(img2) * self._postfilter[:, 0:self.N + 1]) return self._bigimgstore
def reconstruct_rfftw(self, img): imf = fft.rfft2(img) * self._prefilter[:, 0:self.N // 2 + 1] self._carray1[:, 0:self.N // 2, 0:self.N // 2 + 1] = imf[:, 0:self.N // 2, 0:self.N // 2 + 1] self._carray1[:, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[:, self.N // 2:self.N, 0:self.N // 2 + 1] img2 = np.sum(fft.irfft2(self._carray1) * self._reconfactor, 0) return fft.irfft2(fft.rfft2(img2) * self._postfilter[:, 0:self.N + 1])
def main(blur_name, orig_name, data_name, kernel_name): orig = plt.imread(orig_name)[:, :, :3] blur = plt.imread(blur_name)[:, :, :3] # blur = kernel * orig → kernel = blur/orig # kernel = restoration.richardson_lucy(blur, orig) orig_f = fft.rfft2(orig, axes=(0, 1), threads=16) blur_f = fft.rfft2(blur, axes=(0, 1), threads=16) kernel_f = blur_f / orig_f kernel = np.nan_to_num(fft.irfft2(kernel_f, axes=(0, 1), threads=16)) with h5py.File(data_name, 'w') as h5f: h5f.create_dataset('dataset_1', data=kernel) imwrite(kernel_name, np.fft.fftshift(kernel) / kernel.max())
def batchreconstruct(self, img, n_output_frames=None): nim = img.shape[0] r = np.mod(nim, 14) if r > 0: # pad with empty frames so total number of frames is divisible by 14 img = np.concatenate((img, np.zeros((14 - r, self.N, self.N), np.single))) nim = nim + 14 - r imf = fft.rfft2(img) * self._prefilter[:, 0:self.N // 2 + 1] img2 = np.zeros([nim, 2 * self.N, 2 * self.N], dtype=np.single) for i in range(0, nim, 7): self._carray1[:, 0:self.N // 2, 0:self.N // 2 + 1] = imf[i:i + 7, 0:self.N // 2, 0:self.N // 2 + 1] self._carray1[:, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[i:i + 7, self.N // 2:self.N, 0:self.N // 2 + 1] img2[i:i + 7, :, :] = fft.irfft2(self._carray1) * self._reconfactor nim7 = nim // 7 if n_output_frames is None: n_output_frames = nim7 img3 = fft.irfft(fft.rfft(img2, nim, 0)[0:nim7 // 2 + 1, :, :], n_output_frames, 0) res = fft.irfft2(fft.rfft2(img3) * self._postfilter[:, :self.N + 1]) return res
def tiehom2020(im, plan, nr_threads=2): """Process a tomographic projection image with the Generalized TIE-HOM (Paganin et al 2020) phase retrieval algorithm. Parameters ---------- im : array_like Flat corrected image data as numpy array. plan : structure Structure with pre-computed data (see tiehom_plan function). nr_threads : int Number of threads to be used in the computation of FFT by PyFFTW (default = 2). """ # Extract plan values: dim0_o = plan['dim0'] dim1_o = plan['dim1'] n_pad0 = plan['npad0'] n_pad1 = plan['npad1'] marg0 = (n_pad0 - dim0_o) / 2 marg1 = (n_pad1 - dim1_o) / 2 den = plan['den'] mu = plan['mu'] # Pad image (if required): im = padImage(im, n_pad0, n_pad1) # (Un)comment the following two lines to use PyFFTW: n_byte_align(im, simd_alignment) im = rfft2(im, threads=nr_threads) # (Un)comment the following line to use NumPy: #im = rfft2(im) # Apply Paganin's (pre-computed) formula: im = im / den # (Un)comment the following two lines to use PyFFTW: n_byte_align(im, simd_alignment) im = irfft2(im, threads=nr_threads) # (Un)comment the following line to use NumPy: #im = irfft2(im) im = im.astype(float32) im = -1 / mu * nplog(im) # Return cropped output: return im[marg0:dim0_o + marg0, marg1:dim1_o + marg1]
def tiehom(im, plan, nr_threads=2): """Process a tomographic projection image with the TIE-HOM (Paganin's) phase retrieval algorithm. Parameters ---------- im : array_like Flat corrected image data as numpy array. plan : structure Structure with pre-computed data (see tiehom_plan function). nr_threads : int Number of threads to be used in the computation of FFT by PyFFTW (default = 2). """ # Extract plan values: dim0_o = plan['dim0'] dim1_o = plan['dim1'] n_pad0 = plan['npad0'] n_pad1 = plan['npad1'] marg0 = (n_pad0 - dim0_o) / 2 marg1 = (n_pad1 - dim1_o) / 2 den = plan['den'] mu = plan['mu'] # Pad image (if required): im = padImage(im, n_pad0, n_pad1) # (Un)comment the following two lines to use PyFFTW: n_byte_align(im, simd_alignment) im = rfft2(im, threads=nr_threads) # (Un)comment the following line to use NumPy: #im = rfft2(im) # Apply Paganin's (pre-computed) formula: im = im / den # (Un)comment the following two lines to use PyFFTW: n_byte_align(im, simd_alignment) im = irfft2(im, threads=nr_threads) # (Un)comment the following line to use NumPy: #im = irfft2(im) im = im.astype(float32) im = -1 / mu * nplog(im) # Return cropped output: return im[marg0:dim0_o + marg0, marg1:dim1_o + marg1]
def _update_stationary(image, dm, dn, B, cov): """Accumulate the stationary image statistics""" M,N,K = image.shape If = fft.rfft2(image.transpose(2,0,1), (M+B,N+B)) Ic = If.conj() for k1 in range(K): for k2 in range(k1,K): # cross correlate corr = fft.irfft2(Ic[k1]*If[k2], (M+B,N+B)) # accumulate cov[dm,dn,k1,k2] += corr[dm,dn] if k1 != k2: cov[-dm,-dn,k2,k1] += corr[dm,dn]
def particle_xcorr(ptcl, refmap_ft): r = util.euler2rot(*np.deg2rad(ptcl[star.Relion.ANGLES])) proj = vop.interpolate_slice_numba(refmap_ft, r) c = ctf.eval_ctf(s / apix, a, def1[i], def2[i], angast[i], phase[i], kv[i], ac[i], cs[i], bf=0, lp=2 * apix) pshift = np.exp(-2 * np.pi * 1j * (-xshift[i] * sx + -yshift * sy)) proj_ctf = proj * pshift * c with mrc.ZSliceReader(ptcl[star.Relion.IMAGE_NAME]) as f: exp_image_fft = rfft2(fftshift(f.read(i))) xcor_fft = exp_image_fft * proj_ctf xcor = fftshift(irfft2(xcor_fft)) return xcor
def calc_rhs(q): q_tend = fft.rfft2(c0*np.tanh(fft.irfft2(q))) \ - c1*q \ - nu * (kx[np.newaxis,:]**2 + ky[:,np.newaxis]**2) * q return q_tend
a = fft.irfft2(afft) # normalize the variance to 1 a *= a_std/np.std(a) return a #h = generate_random_field(1.) + h0 q = generate_random_field(1.) nt = 24*1000 dt = 6*3600. t = 0. n_out = 16 # Set all variables in Fourier space. q = fft.rfft2(q) def pad(a): a_pad = np.zeros((3*ny//2, 3*nx//4+1), dtype=np.complex) a_pad[:ny//2,:nx//2+1] = a[:ny//2,:] a_pad[ny:3*ny//2,:nx//2+1] = a[ny//2:,:] return (9/4)*a_pad def unpad(a_pad): a = np.zeros((ny, nx//2+1), dtype=complex) a[:ny//2,:] = a_pad[:ny//2,:nx//2+1] a[ny//2:,:] = a_pad[ny:3*ny//2,:nx//2+1] return (4/9)*a def calc_prod(a, b): a_pad = pad(a)
def calc_rhs(q): q_tend = fft.rfft2(nd1*np.tanh(fft.irfft2(q))) \ - nd2*q \ - (kx[np.newaxis,:]**2 + ky[:,np.newaxis]**2) * q return q_tend
def calc_prod(a, b): return fft.rfft2( fft.irfft2(a) * fft.irfft2(b) )
def homomorphic(im, args): """Process the input image with an homomorphic filtering. Parameters ---------- im : array_like Image data as numpy array. d0 : float Cutoff in the range [0.01, 0.99] of the high pass Gaussian filter. Higher values means more high pass effect. [Suggested for default: 0.80]. alpha : float Offset to preserve the zero frequency where. Higher values means less high pass effect. [Suggested for default: 0.2] (Parameters d0 and alpha have to passed as a string separated by ;) Example (using tiffile.py) -------------------------- >>> im = imread('im_orig.tif') >>> im = homomorphic(im, '0.5;0.2') >>> imsave('im_flt.tif', im) References ---------- """ # Get args: param1, param2 = args.split(";") d0 = (1.0 - float(param1)) # Simpler for user alpha = float(param2) # Internal parameters for Gaussian low-pass filtering: d0 = d0 * (im.shape[1] / 2.0) # Take the log: im = nplog(1 + im) # Compute FFT: n_byte_align(im, simd_alignment) im = rfft2(im, threads=2) # Prepare the frequency coordinates: u = arange(0, im.shape[0], dtype=float32) v = arange(0, im.shape[1], dtype=float32) # Compute the indices for meshgrid: u[(u > im.shape[0] / 2.0)] = u[(u > im.shape[0] / 2.0)] - im.shape[0] v[(v > im.shape[1] / 2.0)] = v[(v > im.shape[1] / 2.0)] - im.shape[1] # Compute the meshgrid arrays: V, U = meshgrid(v, u) # Compute the distances D(U, V): D = sqrt(U**2 + V**2) # Prepare Guassian filter: H = npexp(-(D**2) / (2 * (d0**2))) H = (1 - H) + alpha # Do the filtering: im = H * im # Compute inverse FFT of the filtered data: n_byte_align(im, simd_alignment) #im = real(irfft2(im, threads=2)) im = irfft2(im, threads=2) # Take the exp: im = npexp(im) - 1 # Return image according to input type: return im.astype(float32)
a = fft.irfft2(afft) # normalize the variance to 1 a *= a_std/np.std(a) return a #h = generate_random_field(1.) + h0 q = generate_random_field(1.) nt = 172800 dt = 100. t = 0. # Set all variables in Fourier space. u = fft.rfft2(u) v = fft.rfft2(v) h = fft.rfft2(h) q = fft.rfft2(q) def pad(a): a_pad = np.zeros((3*ny//2, 3*nx//4+1), dtype=np.complex) a_pad[:ny//2,:nx//2+1] = a[:ny//2,:] a_pad[ny:3*ny//2,:nx//2+1] = a[ny//2:,:] return (9/4)*a_pad def unpad(a_pad): a = np.zeros((ny, nx//2+1), dtype=complex) a[:ny//2,:] = a_pad[:ny//2,:nx//2+1] a[ny//2:,:] = a_pad[ny:3*ny//2,:nx//2+1] return (4/9)*a
def integrate_dpc(xshift, yshift, padf=4, lP=0.5, hP=100, stepsize=0.2, iter_count=100): """ Integrate DPC shifts using Fourier transforms and preventing edge effects Parameters ---------- xshift: ndarray Beam shift in the X dimension yshift: ndarray Beam shift in the X dimensions padf: int, optional padding factor for accurate FFT, default is 4 lP: float, optional low pass filter, default is 0.5 hP: float, optional high pass filter, default is 100 stepsize: float, optional fraction of phase differnce to update every iteration. Default is 0.5. This is a dynamic factor, and is reduced if the error starts increasing iter_count: int, optional Number of iterations to run. Default is 100 Returns ------- phase_final: ndarray Phase of the matrix that leads to the displacement Notes ----- This is based on two ideas - iterative complex plane integration and antisymmetric mirror integration. First two antisymmetric matrices are generated for each of the x shift and y shifts. Then they are integrated in Fourier space as per the idea of complex integration. Finally, a sub-matrix is taken out from the antisymmetric integrand matrix to give the dpc integrand References ---------- .. [1] Ishizuka, Akimitsu, Masaaki Oka, Takehito Seki, Naoya Shibata, and Kazuo Ishizuka. "Boundary-artifact-free determination of potential distribution from differential phase contrast signals." Microscopy 66, no. 6 (2017): 397-405. :Authors: Debangshu Mukherjee <*****@*****.**> """ imshape = np.asarray(xshift.shape) padshape = (imshape * padf).astype(int) qx = np.fft.fftfreq(padshape[0]) qy = np.fft.rfftfreq(padshape[1]) qr2 = qx[:, None]**2 + qy[None, :]**2 denominator = qr2 + hP + ((qr2**2) * lP) _ = np.seterr(divide="ignore") denominator = 1.0 / denominator denominator[0, 0] = 0 _ = np.seterr(divide="warn") f = 1j * 0.25 * stepsize qxOperator = f * qx[:, None] * denominator qyOperator = f * qy[None, :] * denominator padded_phase = np.zeros(padshape) update = np.zeros_like(padded_phase) dx = np.zeros_like(padded_phase) dy = np.zeros_like(padded_phase) error = np.zeros(iter_count) mask = np.zeros_like(padded_phase, dtype=bool) mask[int(0.5 * (padshape[0] - imshape[0])):int(0.5 * (padshape[0] + imshape[0])), int(0.5 * (padshape[1] - imshape[1])):int(0.5 * (padshape[1] + imshape[1])), ] = True maskInv = mask == False for ii in range(iter_count): dx[mask] -= xshift.ravel() dy[mask] -= yshift.ravel() dx[maskInv] = 0 dy[maskInv] = 0 update = pfft.irfft2( pfft.rfft2(dx) * qxOperator + pfft.rfft2(dy) * qyOperator) padded_phase += scnd.gaussian_filter((stepsize * update), 1) dx = (np.roll(padded_phase, (-1, 0), axis=(0, 1)) - np.roll(padded_phase, (1, 0), axis=(0, 1))) / 2.0 dy = (np.roll(padded_phase, (0, -1), axis=(0, 1)) - np.roll(padded_phase, (0, 1), axis=(0, 1))) / 2.0 xDiff = dx[mask] - xshift.ravel() yDiff = dy[mask] - yshift.ravel() error[ii] = np.sqrt( np.mean((xDiff - np.mean(xDiff))**2 + (yDiff - np.mean(yDiff))**2)) if ii > 0: if error[ii] > error[ii - 1]: stepsize /= 2 phase_final = np.reshape(padded_phase[mask], imshape) return phase_final
def homomorphic(im, args): """Process the input image with an homomorphic filtering. Parameters ---------- im : array_like Image data as numpy array. d0 : float Cutoff in the range [0.01, 0.99] of the high pass Gaussian filter. Higher values means more high pass effect. [Suggested for default: 0.80]. alpha : float Offset to preserve the zero frequency where. Higher values means less high pass effect. [Suggested for default: 0.2] (Parameters d0 and alpha have to passed as a string separated by ;) Example (using tiffile.py) -------------------------- >>> im = imread('im_orig.tif') >>> im = homomorphic(im, '0.5;0.2') >>> imsave('im_flt.tif', im) References ---------- """ # Get args: param1, param2 = args.split(";") d0 = (1.0 - float(param1)) # Simpler for user alpha = float(param2) # Internal parameters for Gaussian low-pass filtering: d0 = d0 * (im.shape[1] / 2.0) # Take the log: im = nplog(1 + im) # Compute FFT: n_byte_align(im, simd_alignment) im = rfft2(im, threads=2) # Prepare the frequency coordinates: u = arange(0, im.shape[0], dtype=float32) v = arange(0, im.shape[1], dtype=float32) # Compute the indices for meshgrid: u[(u > im.shape[0] / 2.0)] = u[(u > im.shape[0] / 2.0)] - im.shape[0] v[(v > im.shape[1] / 2.0)] = v[(v > im.shape[1] / 2.0)] - im.shape[1] # Compute the meshgrid arrays: V, U = meshgrid(v, u) # Compute the distances D(U, V): D = sqrt(U ** 2 + V ** 2) # Prepare Guassian filter: H = npexp(-(D ** 2) / (2 * (d0 ** 2))) H = (1 - H) + alpha # Do the filtering: im = H * im # Compute inverse FFT of the filtered data: n_byte_align(im, simd_alignment) #im = real(irfft2(im, threads=2)) im = irfft2(im, threads=2) # Take the exp: im = npexp(im) - 1 # Return image according to input type: return im.astype(float32)
def calc_prod(a, b): a_pad = pad(a) b_pad = pad(b) ab_pad = fft.rfft2( fft.irfft2(a_pad) * fft.irfft2(b_pad) ) return unpad(ab_pad)
def raven(im, args): """Process a sinogram image with the Raven de-striping algorithm. Parameters ---------- im : array_like Image data as numpy array. n : int Size of the window (minimum n = 3) around the zero frequency where filtering is actually applied (v0 parameter in Raven's article). Higher values means more smoothing effect. [Suggested for default: 3] d0 : float Cutoff in the range [0.01, 0.99] of the low pass filter (a Gaussian filter is used instead of the originally proposed Butterworth filter in order to have only one tuning parameter). Higher values means more smoothing effect. [Suggested for default: 0.5]. (Parameters n and d0 have to passed as a string separated by ;) Example (using tiffile.py) -------------------------- >>> im = imread('sino_orig.tif') >>> im = raven(im, '3;0.50') >>> imsave('sino_flt.tif', im) References ---------- C. Raven, Numerical removal of ring artifacts in microtomography, Review of Scientific Instruments 69(8):2978-2980, 1998. """ # Disable a warning: simplefilter("ignore", ComplexWarning) # Get args: param1, param2 = args.split(";") n = int(param1) d0 = (1.0 - float(param2)) # Simpler for user # Internal parameters for Gaussian low-pass filtering: d0 = d0 * (im.shape[1] / 2.0) # Pad image: marg = im.shape im = pad(im, pad_width=((im.shape[0] / 2, im.shape[0] / 2), (0,0)), mode='reflect') # or 'constant' for zero padding im = pad(im, pad_width=((0,0) ,(im.shape[1] / 2, im.shape[1] / 2)), mode='edge') # or 'constant' for zero padding # Windowing: im = _windowing_lr(im, marg[1]) im = _windowing_lr(im.T, marg[0]).T # Compute FFT: n_byte_align(im, simd_alignment) im = rfft2(im, threads=2) # Prepare the frequency coordinates: u = arange(0, im.shape[0], dtype=float32) v = arange(0, im.shape[1], dtype=float32) # Compute the indices for meshgrid: u[(u > im.shape[0] / 2.0)] = u[(u > im.shape[0] / 2.0)] - im.shape[0] v[(v > im.shape[1] / 2.0)] = v[(v > im.shape[1] / 2.0)] - im.shape[1] # Compute the meshgrid arrays: V, U = meshgrid(v, u) # Compute the distances D(U, V): D = sqrt(U ** 2 + V ** 2) # Prepare Guassian filter limited to a window around zero-frequency: H = exp(-(D ** 2) / (2 * (d0 ** 2))) if (n % 2 == 1): H[n / 2:-(n / 2),:] = 1 else: H[n / 2:-(n / 2 - 1),:] = 1 # Do the filtering: im = H * im # Compute inverse FFT of the filtered data: n_byte_align(im, simd_alignment) #im = real(irfft2(im, threads=2)) im = irfft2(im, threads=2) # Crop image: im = im[im.shape[0] / 4:(im.shape[0] / 4 + marg[0]), im.shape[1] / 4:(im.shape[1] / 4 + marg[1])] # Return image: return im.astype(float32)