def write_center(tomo, theta, dpath='tmp/center', cen_range=None, ind=None, mask=False, ratio=1., sinogram_order=False, algorithm='gridrec', filter_name='parzen'): """ Save images reconstructed with a range of rotation centers. Helps finding the rotation center manually by visual inspection of images reconstructed with a set of different centers.The output images are put into a specified folder and are named by the center position corresponding to the image. Parameters ---------- tomo : ndarray 3D tomographic data. theta : array Projection angles in radian. dpath : str, optional Folder name to save output images. cen_range : list, optional [start, end, step] Range of center values. ind : int, optional Index of the slice to be used for reconstruction. mask : bool, optional If ``True``, apply a circular mask to the reconstructed image to limit the analysis into a circular region. ratio : float, optional The ratio of the radius of the circular mask to the edge of the reconstructed image. sinogram_order: bool, optional Determins whether data is a stack of sinograms (True, y-axis first axis) or a stack of radiographs (False, theta first axis). algorithm : {str, function} One of the following string values. 'art' Algebraic reconstruction technique :cite:`Kak:98`. 'bart' Block algebraic reconstruction technique. 'fbp' Filtered back-projection algorithm. 'gridrec' Fourier grid reconstruction algorithm :cite:`Dowd:99`, :cite:`Rivers:06`. 'mlem' Maximum-likelihood expectation maximization algorithm :cite:`Dempster:77`. 'osem' Ordered-subset expectation maximization algorithm :cite:`Hudson:94`. 'ospml_hybrid' Ordered-subset penalized maximum likelihood algorithm with weighted linear and quadratic penalties. 'ospml_quad' Ordered-subset penalized maximum likelihood algorithm with quadratic penalties. 'pml_hybrid' Penalized maximum likelihood algorithm with weighted linear and quadratic penalties :cite:`Chang:04`. 'pml_quad' Penalized maximum likelihood algorithm with quadratic penalty. 'sirt' Simultaneous algebraic reconstruction technique. 'tv' Total Variation reconstruction technique :cite:`Chambolle:11`. 'grad' Gradient descent method with a constant step size filter_name : str, optional Name of the filter for analytic reconstruction. 'none' No filter. 'shepp' Shepp-Logan filter (default). 'cosine' Cosine filter. 'hann' Cosine filter. 'hamming' Hamming filter. 'ramlak' Ram-Lak filter. 'parzen' Parzen filter. 'butterworth' Butterworth filter. 'custom' A numpy array of size `next_power_of_2(num_detector_columns)/2` specifying a custom filter in Fourier domain. The first element of the filter should be the zero-frequency component. 'custom2d' A numpy array of size `num_projections*next_power_of_2(num_detector_columns)/2` specifying a custom angle-dependent filter in Fourier domain. The first element of each filter should be the zero-frequency component. """ tomo = dtype.as_float32(tomo) theta = dtype.as_float32(theta) if sinogram_order: dy, dt, dx = tomo.shape else: dt, dy, dx = tomo.shape if ind is None: ind = dy // 2 if cen_range is None: center = np.arange(dx / 2 - 5, dx / 2 + 5, 0.5) else: center = np.arange(*cen_range) stack = dtype.empty_shared_array((len(center), dt, dx)) for m in range(center.size): if sinogram_order: stack[m] = tomo[ind] else: stack[m] = tomo[:, ind, :] # Reconstruct the same slice with a range of centers. rec = recon(stack, theta, center=center, sinogram_order=True, algorithm=algorithm, filter_name=filter_name, nchunk=1) # Apply circular mask. if mask is True: rec = circ_mask(rec, axis=0) # Save images to a temporary folder. for m in range(len(center)): write_tiff(data=rec[m], fname=dpath, digit='{0:.2f}'.format(center[m]))
def align_seq( prj, ang, fdir='.', iters=10, pad=(0, 0), blur=True, center=None, algorithm='sirt', upsample_factor=10, rin=0.5, rout=0.8, save=False, debug=True): """ Aligns the projection image stack using the sequential re-projection algorithm :cite:`Gursoy:17`. Parameters ---------- prj : ndarray 3D stack of projection images. The first dimension is projection axis, second and third dimensions are the x- and y-axes of the projection image, respectively. ang : ndarray Projection angles in radians as an array. iters : scalar, optional Number of iterations of the algorithm. pad : list-like, optional Padding for projection images in x and y-axes. blur : bool, optional Blurs the edge of the image before registration. center: array, optional Location of rotation axis. algorithm : {str, function} One of the following string values. 'art' Algebraic reconstruction technique :cite:`Kak:98`. 'gridrec' Fourier grid reconstruction algorithm :cite:`Dowd:99`, :cite:`Rivers:06`. 'mlem' Maximum-likelihood expectation maximization algorithm :cite:`Dempster:77`. 'sirt' Simultaneous algebraic reconstruction technique. 'tv' Total Variation reconstruction technique :cite:`Chambolle:11`. 'grad' Gradient descent method with a constant step size upsample_factor : integer, optional The upsampling factor. Registration accuracy is inversely propotional to upsample_factor. rin : scalar, optional The inner radius of blur function. Pixels inside rin is set to one. rout : scalar, optional The outer radius of blur function. Pixels outside rout is set to zero. save : bool, optional Saves projections and corresponding reconstruction for each algorithm iteration. debug : book, optional Provides debugging info such as iterations and error. Returns ------- ndarray 3D stack of projection images with jitter. ndarray Error array for each iteration. """ # Needs scaling for skimage float operations. prj, scl = scale(prj) # Shift arrays sx = np.zeros((prj.shape[0])) sy = np.zeros((prj.shape[0])) conv = np.zeros((iters)) # Pad images. npad = ((0, 0), (pad[1], pad[1]), (pad[0], pad[0])) prj = np.pad(prj, npad, mode='constant', constant_values=0) # Register each image frame-by-frame. for n in range(iters): # Reconstruct image. rec = recon(prj, ang, center=center, algorithm=algorithm) # Re-project data and obtain simulated data. sim = project(rec, ang, center=center, pad=False) # Blur edges. if blur: _prj = blur_edges(prj, rin, rout) _sim = blur_edges(sim, rin, rout) else: _prj = prj _sim = sim # Initialize error matrix per iteration. err = np.zeros((prj.shape[0])) # For each projection for m in range(prj.shape[0]): # Register current projection in sub-pixel precision shift, error, diffphase = phase_cross_correlation( _prj[m], _sim[m], upsample_factor=upsample_factor) err[m] = np.sqrt(shift[0]*shift[0] + shift[1]*shift[1]) sx[m] += shift[0] sy[m] += shift[1] # Register current image with the simulated one tform = tf.SimilarityTransform(translation=(shift[1], shift[0])) prj[m] = tf.warp(prj[m], tform, order=5) if debug: print('iter=' + str(n) + ', err=' + str(np.linalg.norm(err))) conv[n] = np.linalg.norm(err) if save: write_tiff(prj, fdir + '/tmp/iters/prj', n) write_tiff(sim, fdir + '/tmp/iters/sim', n) write_tiff(rec, fdir + '/tmp/iters/rec', n) # Re-normalize data prj *= scl return prj, sx, sy, conv
def write_center( tomo, theta, dpath='tmp/center', cen_range=None, ind=None, mask=False, ratio=1., sinogram_order=False, algorithm='gridrec', filter_name='parzen'): """ Save images reconstructed with a range of rotation centers. Helps finding the rotation center manually by visual inspection of images reconstructed with a set of different centers.The output images are put into a specified folder and are named by the center position corresponding to the image. Parameters ---------- tomo : ndarray 3D tomographic data. theta : array Projection angles in radian. dpath : str, optional Folder name to save output images. cen_range : list, optional [start, end, step] Range of center values. ind : int, optional Index of the slice to be used for reconstruction. mask : bool, optional If ``True``, apply a circular mask to the reconstructed image to limit the analysis into a circular region. ratio : float, optional The ratio of the radius of the circular mask to the edge of the reconstructed image. sinogram_order: bool, optional Determins whether data is a stack of sinograms (True, y-axis first axis) or a stack of radiographs (False, theta first axis). algorithm : {str, function} One of the following string values. 'art' Algebraic reconstruction technique :cite:`Kak:98`. 'bart' Block algebraic reconstruction technique. 'fbp' Filtered back-projection algorithm. 'gridrec' Fourier grid reconstruction algorithm :cite:`Dowd:99`, :cite:`Rivers:06`. 'mlem' Maximum-likelihood expectation maximization algorithm :cite:`Dempster:77`. 'osem' Ordered-subset expectation maximization algorithm :cite:`Hudson:94`. 'ospml_hybrid' Ordered-subset penalized maximum likelihood algorithm with weighted linear and quadratic penalties. 'ospml_quad' Ordered-subset penalized maximum likelihood algorithm with quadratic penalties. 'pml_hybrid' Penalized maximum likelihood algorithm with weighted linear and quadratic penalties :cite:`Chang:04`. 'pml_quad' Penalized maximum likelihood algorithm with quadratic penalty. 'sirt' Simultaneous algebraic reconstruction technique. 'tv' Total Variation reconstruction technique :cite:`Chambolle:11`. 'grad' Gradient descent method with a constant step size filter_name : str, optional Name of the filter for analytic reconstruction. 'none' No filter. 'shepp' Shepp-Logan filter (default). 'cosine' Cosine filter. 'hann' Cosine filter. 'hamming' Hamming filter. 'ramlak' Ram-Lak filter. 'parzen' Parzen filter. 'butterworth' Butterworth filter. 'custom' A numpy array of size `next_power_of_2(num_detector_columns)/2` specifying a custom filter in Fourier domain. The first element of the filter should be the zero-frequency component. 'custom2d' A numpy array of size `num_projections*next_power_of_2(num_detector_columns)/2` specifying a custom angle-dependent filter in Fourier domain. The first element of each filter should be the zero-frequency component. """ tomo = dtype.as_float32(tomo) theta = dtype.as_float32(theta) if sinogram_order: dy, dt, dx = tomo.shape else: dt, dy, dx = tomo.shape if ind is None: ind = dy // 2 if cen_range is None: center = np.arange(dx / 2 - 5, dx / 2 + 5, 0.5) else: center = np.arange(*cen_range) stack = dtype.empty_shared_array((len(center), dt, dx)) for m in range(center.size): if sinogram_order: stack[m] = tomo[ind] else: stack[m] = tomo[:, ind, :] # Reconstruct the same slice with a range of centers. rec = recon(stack, theta, center=center, sinogram_order=True, algorithm=algorithm, filter_name=filter_name, nchunk=1) # Apply circular mask. if mask is True: rec = circ_mask(rec, axis=0) # Save images to a temporary folder. dpath = os.path.abspath(dpath) if not os.path.exists(dpath): os.makedirs(dpath) for m in range(len(center)): write_tiff(data=rec[m], fname=dpath, digit='{0:.2f}'.format(center[m]))