def normalize_bg(tomo, air=1, ncore=None, nchunk=None): """ Normalize 3D tomgraphy data based on background intensity. Weight sinogram such that the left and right image boundaries (i.e., typically the air region around the object) are set to one and all intermediate values are scaled linearly. Parameters ---------- tomo : ndarray 3D tomographic data. air : int, optional Number of pixels at each boundary to calculate the scaling factor. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ tomo = dtype.as_float32(tomo) air = dtype.as_int32(air) dx, dy, dz = tomo.shape arr = mproc.distribute_jobs(tomo, func=extern.c_normalize_bg, args=(dx, dy, dz, air), axis=0, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_based_fitting( tomo, order=3, sigma=(5, 20), ncore=None, nchunk=None): """ Remove horizontal stripes from sinogram using Nghia Vo's approach :cite:'Vo:18' Algorithm 1 in the paper. Remove stripes using the fitting technique. Parameters ---------- tomo : ndarray 3D tomographic data. order : int Polynomial fit order. sigma : tuple of 2 floats Sigmas of a 2D Gaussian window in x and y direction. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_based_fitting, args=(order, sigma), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_all_stripe(tomo, snr=3, la_size=61, sm_size=21, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` Combine algorithms 6,5,4,3 to remove all types of stripes. Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to locate large stripes. Greater is less sensitive. la_size : int Window size of the median filter to remove large stripes. sm_size : int Window size of the median filter to remove small-to-medium stripes. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_all_stripe, args=(snr, la_size, sm_size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_dead_stripe(tomo, snr=3, size=51, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` Algorithm 6 in the paper. Remove unresponsive and fluctuating stripes. Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to detect locations of large stripes. Greater is less sensitive. size : int Window size of the median filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_dead_stripe, args=(snr, size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_based_fitting( tomo, order=3, sigma=(5, 20), ncore=None, nchunk=None): """ Remove horizontal stripes from sinogram using Nghia Vo's approach :cite:`Vo:18` Algorithm 1 in the paper. Remove stripes using the fitting technique. Parameters ---------- tomo : ndarray 3D tomographic data. order : int Polynomial fit order. sigma : tuple of 2 floats Sigmas of a 2D Gaussian window in x and y direction. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_based_fitting, args=(order, sigma), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_based_filtering( tomo, sigma=3, size=None, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` Algorithm 2 in the paper. Remove stripes using the filtering technique. Parameters ---------- tomo : ndarray 3D tomographic data. sigma : float Sigma of the Gaussian window which is used to separate the low-pass and high-pass components of the intensity profiles of each column. size : int Window size of the median filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_based_filtering, args=(sigma, size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_based_filtering( tomo, sigma=3, size=None, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:'Vo:18' Algorithm 2 in the paper. Remove stripes using the filtering technique. Parameters ---------- tomo : ndarray 3D tomographic data. sigma : float Sigma of the Gaussian window which is used to separate the low-pass and high-pass components of the intensity profiles of each column. size : int Window size of the median filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_based_filtering, args=(sigma, size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_all_stripe(tomo, snr=3, la_size=61, sm_size=21, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:'Vo:18' Combine algorithms 6,5,4,3 to remove all types of stripes. Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to locate large stripes. Greater is less sensitive. la_size : int Window size of the median filter to remove large stripes. sm_size : int Window size of the median filter to remove small-to-medium stripes. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_all_stripe, args=(snr, la_size, sm_size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_sf(tomo, size=5, ncore=None, nchunk=None): """ Normalize raw projection data using a smoothing filter approach. Parameters ---------- tomo : ndarray 3D tomographic data. size : int, optional Size of the smoothing filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ tomo = dtype.as_float32(tomo) arr = mproc.distribute_jobs( tomo, func=extern.c_remove_stripe_sf, args=(size,), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_ti(tomo, nblock=0, alpha=1.5, ncore=None, nchunk=None): """ Remove horizontal stripes from sinogram using Titarenko's approach :cite:`Miqueles:14`. Parameters ---------- tomo : ndarray 3D tomographic data. nblock : int, optional Number of blocks. alpha : int, optional Damping factor. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_ti, args=(nblock, alpha), axis=1, ncore=ncore, nchunk=nchunk) return arr
def normalize_roi(arr, roi=[0, 0, 10, 10], ncore=None): """ Normalize raw projection data using an average of a selected window on projection images. Parameters ---------- arr : ndarray 3D tomographic data. roi: list of int, optional [top-left, top-right, bottom-left, bottom-right] pixel coordinates. ncore : int, optional Number of cores that will be assigned to jobs. Returns ------- ndarray Normalized 3D tomographic data. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs(arr, func=_normalize_roi, args=(roi, ), axis=0, ncore=ncore, nchunk=0) return arr
def remove_outlier(arr, dif, size=3, axis=0, ncore=None, nchunk=None): """ Remove high intensity bright spots from a 3D array along specified dimension. Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected array. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs(arr.swapaxes(0, axis), func=_remove_outlier, args=(dif, size), axis=0, ncore=ncore, nchunk=nchunk) return arr.swapaxes(0, axis)
def remove_stripe_based_sorting(tomo, size=None, dim=1, ncore=None, nchunk=None): """ Remove full and partial stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` (algorithm 3). Suitable for removing partial stripes. Parameters ---------- tomo : ndarray 3D tomographic data. size : int Window size of the median filter. dim : {1, 2}, optional Dimension of the window. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs(tomo, func=_remove_stripe_based_sorting, args=(size, dim), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_sf(tomo, size=5, ncore=None, nchunk=None): """ Normalize raw projection data using a smoothing filter approach. Parameters ---------- tomo : ndarray 3D tomographic data. size : int, optional Size of the smoothing filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ tomo = dtype.as_float32(tomo) dx, dy, dz = tomo.shape arr = mproc.distribute_jobs( tomo, func=extern.c_remove_stripe_sf, args=(dx, dy, dz, size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def _search_coarse(sino, smin, smax, ratio, drop, ncore=None): """ Coarse search for finding the rotation center. """ (nrow, ncol) = sino.shape cen_fliplr = (ncol - 1.0) / 2.0 smin = np.int16(np.clip(smin + cen_fliplr, 0, ncol - 1) - cen_fliplr) smax = np.int16(np.clip(smax + cen_fliplr, 0, ncol - 1) - cen_fliplr) start_cor = ncol // 2 + smin stop_cor = ncol // 2 + smax flip_sino = np.fliplr(sino) comp_sino = np.flipud(sino) # Used to avoid local minima list_cor = np.arange(start_cor, stop_cor + 0.5, 0.5) list_metric = np.zeros(len(list_cor), dtype=np.float32) mask = _create_mask(2 * nrow, ncol, 0.5 * ratio * ncol, drop) list_shift = 2.0 * (list_cor - cen_fliplr) list_metric = distribute_jobs(np.float32(list_shift), _calculate_metric, axis=0, args=(sino, flip_sino, comp_sino, mask), ncore=ncore, nchunk=1) minpos = np.argmin(list_metric) if minpos == 0: logger.debug('WARNING!!!Global minimum is out of searching range') logger.debug('Please extend smin: %i', smin) if minpos == len(list_metric) - 1: logger.debug('WARNING!!!Global minimum is out of searching range') logger.debug('Please extend smax: %i', smax) cor = list_cor[minpos] return cor
def remove_stripe_based_sorting(tomo, size=None, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` Algorithm 3 in the paper. Remove stripes using the sorting technique. Work particularly well for removing partial stripes. Parameters ---------- tomo : ndarray 3D tomographic data. size : int Window size of the median filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_stripe_based_sorting, args=(size,), axis=1, ncore=ncore, nchunk=nchunk) return arr
def distortion_correction_proj(tomo, xcenter, ycenter, list_fact, ncore=None, nchunk=None): """ Apply distortion correction to projections using the polynomial model. Coefficients are calculated using Vounwarp package :cite:`Vo:15`. Parameters ---------- tomo : ndarray 3D tomographic data. xcenter : float Center of distortion in x-direction. From the left of the image. ycenter : float Center of distortion in y-direction. From the top of the image. list_fact : list of floats Polynomial coefficients of the backward model. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_distortion_correction_proj, args=(xcenter, ycenter, list_fact), axis=0, ncore=ncore, nchunk=nchunk) return arr
def normalize_roi(tomo, roi=[0, 0, 10, 10], ncore=None, nchunk=None): """ Normalize raw projection data using an average of a selected window on projection images. Parameters ---------- tomo : ndarray 3D tomographic data. roi: list of int, optional [top-left, top-right, bottom-left, bottom-right] pixel coordinates. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Normalized 3D tomographic data. """ tomo = dtype.as_float32(tomo) arr = mproc.distribute_jobs( tomo, func=_normalize_roi, args=(roi, ), axis=0, ncore=ncore, nchunk=nchunk) return arr
def median_filter(arr, size=3, axis=0, ncore=None): """ Apply median filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. size : int, optional The size of the filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. Returns ------- ndarray Median filtered 3D array. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs( arr, func=filters.median_filter, args=((size, size),), axis=axis, ncore=ncore, nchunk=0) return arr
def normalize_bg(tomo, air=1, ncore=None, nchunk=None): """ Normalize 3D tomgraphy data based on background intensity. Weight sinogram such that the left and right image boundaries (i.e., typically the air region around the object) are set to one and all intermediate values are scaled linearly. Parameters ---------- tomo : ndarray 3D tomographic data. air : int, optional Number of pixels at each boundary to calculate the scaling factor. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ tomo = dtype.as_float32(tomo) air = dtype.as_int32(air) arr = mproc.distribute_jobs( tomo, func=extern.c_normalize_bg, args=(air,), axis=0, ncore=ncore, nchunk=nchunk) return arr
def sobel_filter(arr, axis=0, ncore=None): """ Apply Sobel filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. axis : int, optional Axis along which sobel filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. Returns ------- ndarray 3D array of same shape as input. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs( arr, func=filters.sobel, axis=axis, ncore=ncore, nchunk=0) return arr
def remove_outlier(arr, dif, size=3, axis=0, ncore=None): """ Remove high intensity bright spots from a 3D array along specified dimension. Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. Returns ------- ndarray Corrected array. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs( arr, func=_remove_outlier_from_img, args=(dif, size), axis=axis, ncore=ncore, nchunk=0) return arr
def remove_dead_stripe(tomo, snr=3, size=51, ncore=None, nchunk=None): """ Remove stripe artifacts from sinogram using Nghia Vo's approach :cite:'Vo:18' Algorithm 6 in the paper. Remove unresponsive and fluctuating stripes. Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to detect locations of large stripes. Greater is less sensitive. size : int Window size of the median filter. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs( tomo, func=_remove_dead_stripe, args=(snr, size), axis=1, ncore=ncore, nchunk=nchunk) return arr
def sobel_filter(arr, axis=0, ncore=None, nchunk=None): """ Apply Sobel filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. axis : int, optional Axis along which sobel filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D array of same shape as input. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs(arr.swapaxes(0, axis), func=_sobel_filter, axis=axis, ncore=ncore, nchunk=nchunk) return arr.swapaxes(0, axis)
def median_filter(arr, size=3, axis=0, ncore=None, nchunk=None): """ Apply median filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. size : int, optional The size of the filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Median filtered 3D array. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs(arr.swapaxes(0, axis), func=_median_filter, args=(size, ), axis=axis, ncore=ncore, nchunk=nchunk) return arr.swapaxes(0, axis)
def test_distribute_jobs(): assert_allclose( mproc.distribute_jobs( np.zeros((8, 8, 8)), func=_synthetic_func, args=(1.,), axis=0), np.ones((8, 8, 8)))
def _test_shape(self, a, expected_shape, axis=0, ncore=None, nchunk=None): ret = mproc.distribute_jobs(a, func=_test_shape, args=(expected_shape, ), axis=axis, ncore=ncore, nchunk=nchunk) assert_array_equal(a, ret)
def test_distribute_jobs(self): assert_allclose( mproc.distribute_jobs( np.zeros((8, 8, 8)), func=_synthetic_func, args=(1.,), axis=0), np.ones((8, 8, 8)))
def project(obj, theta, center=None, emission=True, sinogram_order=False, ncore=None, nchunk=None): """ Project x-rays through a given 3D object. Parameters ---------- obj : ndarray Voxelized 3D object. theta : array Projection angles in radian. center: array, optional Location of rotation axis. emission : bool, optional Determines whether output data is emission or transmission type. sinogram_order: bool, optional Determins whether output data is a stack of sinograms (True, y-axis first axis) or a stack of radiographs (False, theta first axis). ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D tomographic data. """ obj = dtype.as_float32(obj) theta = dtype.as_float32(theta) # Estimate data dimensions. oy, ox, oz = obj.shape dt = theta.size dy = oy dx = _round_to_even(np.sqrt(ox * ox + oz * oz) + 2) shape = dy, dt, dx tomo = dtype.empty_shared_array(shape) tomo[:] = 0.0 center = get_center(shape, center) tomo = mproc.distribute_jobs( (obj, center, tomo), func=extern.c_project, args=(theta,), axis=0, ncore=ncore, nchunk=nchunk) # NOTE: returns sinogram order with emmission=True if not emission: # convert data to be transmission type np.exp(-tomo, tomo) if not sinogram_order: # rotate to radiograph order tomo = np.swapaxes(tomo, 0, 1) #doesn't copy data # copy data to sharedmem tomo = dtype.as_sharedmem(tomo, copy=True) return tomo
def retrieve_phase(tomo, pixel_size=1e-4, dist=50, energy=20, alpha=1e-3, pad=True, ncore=None, nchunk=None): """ Perform single-step phase retrieval from phase-contrast measurements :cite:`Paganin:02`. Parameters ---------- tomo : ndarray 3D tomographic data. pixel_size : float, optional Detector pixel size in cm. dist : float, optional Propagation distance of the wavefront in cm. energy : float, optional Energy of incident wave in keV. alpha : float, optional Regularization parameter. pad : bool, optional If True, extend the size of the projections by padding with zeros. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Approximated 3D tomographic phase data. """ # New dimensions and pad value after padding. py, pz, val = _calc_pad(tomo, pixel_size, dist, energy, pad) # Compute the reciprocal grid. dx, dy, dz = tomo.shape w2 = _reciprocal_grid(pixel_size, dy + 2 * py, dz + 2 * pz) # Filter in Fourier space. phase_filter = np.fft.fftshift( _paganin_filter_factor(energy, dist, alpha, w2)) # Enable cache for FFTW. pyfftw.interfaces.cache.enable() prj = val * np.ones((dy + 2 * py, dz + 2 * pz), dtype='float32') arr = mproc.distribute_jobs(tomo, func=_retrieve_phase, args=(phase_filter, py, pz, prj, pad), axis=0, ncore=ncore, nchunk=nchunk) return arr
def _dist_recon(tomo, recon, algorithm, args, kwargs, ncore, nchunk): mproc.init_tomo(tomo) return mproc.distribute_jobs(recon, func=algorithm, args=args, kwargs=kwargs, axis=0, ncore=ncore, nchunk=nchunk)
def _test_shape(self, a, expected_shape, axis=0, ncore=None, nchunk=None): ret = mproc.distribute_jobs( a, func=_test_shape, args=(expected_shape,), axis=axis, ncore=ncore, nchunk=nchunk) assert_array_equal(a, ret)
def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): #assert tomo.flags.aligned return mproc.distribute_jobs((tomo, center, recon), func=algorithm, args=args, kwargs=kwargs, axis=0, ncore=ncore, nchunk=nchunk)
def remove_ring(rec, center_x=None, center_y=None, thresh=300.0, thresh_max=300.0, thresh_min=-100.0, theta_min=30, rwidth=30, ncore=None, nchunk=None): """ Remove ring artifacts from images in the reconstructed domain. Descriptions of parameters need to be more clear for sure. Parameters ---------- arr : ndarray Array of reconstruction data center_x : float, optional abscissa location of center of rotation center_y : float, optional ordinate location of center of rotation thresh : float, optional maximum value of an offset due to a ring artifact thresh_max : float, optional max value for portion of image to filter thresh_min : float, optional min value for portion of image to filer theta_min : int, optional minimum angle in degrees (int) to be considered ring artifact rwidth : int, optional Maximum width of the rings to be filtered in pixels ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected reconstruction data """ rec = dtype.as_float32(rec) dz, dy, dx = rec.shape if center_x is None: center_x = (dx - 1.0)/2.0 if center_y is None: center_y = (dy - 1.0)/2.0 args = (center_x, center_y, dx, dy, dz, thresh_max, thresh_min, thresh, theta_min, rwidth) rec = mproc.distribute_jobs( rec, func=extern.c_remove_ring, args=args, axis=0, ncore=ncore, nchunk=nchunk) return rec
def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): #assert tomo.flags.aligned return mproc.distribute_jobs( (tomo, center, recon), func=algorithm, args=args, kwargs=kwargs, axis=0, ncore=ncore, nchunk=nchunk)
def _dist_recon(tomo, recon, algorithm, args, kwargs, ncore, nchunk): mproc.init_tomo(tomo) return mproc.distribute_jobs( recon, func=algorithm, args=args, kwargs=kwargs, axis=0, ncore=ncore, nchunk=nchunk)
def retrieve_phase( tomo, pixel_size=1e-4, dist=50, energy=20, alpha=1e-3, pad=True, ncore=None, nchunk=None): """ Perform single-step phase retrieval from phase-contrast measurements :cite:`Paganin:02`. Parameters ---------- tomo : ndarray 3D tomographic data. pixel_size : float, optional Detector pixel size in cm. dist : float, optional Propagation distance of the wavefront in cm. energy : float, optional Energy of incident wave in keV. alpha : float, optional Regularization parameter. pad : bool, optional If True, extend the size of the projections by padding with zeros. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Approximated 3D tomographic phase data. """ # New dimensions and pad value after padding. py, pz, val = _calc_pad(tomo, pixel_size, dist, energy, pad) # Compute the reciprocal grid. dx, dy, dz = tomo.shape w2 = _reciprocal_grid(pixel_size, dy + 2 * py, dz + 2 * pz) # Filter in Fourier space. phase_filter = np.fft.fftshift( _paganin_filter_factor(energy, dist, alpha, w2)) # Enable cache for FFTW. pyfftw.interfaces.cache.enable() pyfftw.interfaces.cache.set_keepalive_time(5) prj = val * np.ones((dy + 2 * py, dz + 2 * pz), dtype='float32') arr = mproc.distribute_jobs( tomo, func=_retrieve_phase, args=(phase_filter, py, pz, prj, pad), axis=0, ncore=ncore, nchunk=nchunk) return arr
def fcorrect_as_pathlength_centerline(input_trans): """Corrects for the beam hardening, assuming we are in the ring plane. Input: transmission Output: sample pathlength in microns. """ data_dtype = input_trans.dtype return_data = mproc.distribute_jobs(input_trans, centerline_spline, args=(), axis=1) return return_data
def remove_stripe_fw(tomo, level=None, wname='db5', sigma=2, pad=True, ncore=None, nchunk=None): """ Remove horizontal stripes from sinogram using the Fourier-Wavelet (FW) based method :cite:`Munch:09`. Parameters ---------- tomo : ndarray 3D tomographic data. level : int, optional Number of discrete wavelet transform levels. wname : str, optional Type of the wavelet filter. 'haar', 'db5', sym5', etc. sigma : float, optional Damping parameter in Fourier space. pad : bool, optional If True, extend the size of the sinogram by padding with zeros. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ if level is None: size = np.max(tomo.shape) level = int(np.ceil(np.log2(size))) # Enable cache for FFTW. pyfftw.interfaces.cache.enable() arr = mproc.distribute_jobs(tomo, func=_remove_stripe_fw, args=(level, wname, sigma, pad), axis=1, ncore=ncore, nchunk=nchunk) return arr
def fcorrect_as_pathlength_centerline(self, input_trans): """Corrects for the beam hardening, assuming we are in the ring plane. Parameters ========== input_trans : np.ndarray transmission Returns ======= pathlength : np.ndarray sample pathlength in microns. """ data_dtype = input_trans.dtype pathlength = mproc.distribute_jobs(input_trans, self.centerline_spline, args=(), axis=1) return pathlength
def remove_stripe_fw( tomo, level=None, wname='db5', sigma=2, pad=True, ncore=None, nchunk=None): """ Remove horizontal stripes from sinogram using the Fourier-Wavelet (FW) based method :cite:`Munch:09`. Parameters ---------- tomo : ndarray 3D tomographic data. level : int, optional Number of discrete wavelet transform levels. wname : str, optional Type of the wavelet filter. 'haar', 'db5', sym5', etc. sigma : float, optional Damping parameter in Fourier space. pad : bool, optional If True, extend the size of the sinogram by padding with zeros. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ if level is None: size = np.max(tomo.shape) level = int(np.ceil(np.log2(size))) # Enable cache for FFTW. pyfftw.interfaces.cache.enable() arr = mproc.distribute_jobs( tomo, func=_remove_stripe_fw, args=(level, wname, sigma, pad), axis=1, ncore=ncore, nchunk=nchunk) return arr
def remove_stripe_based_interpolation(tomo, snr=3, size=31, drop_ratio=0.1, norm=True, ncore=None, nchunk=None): """ Remove most types of stripe artifacts from sinograms based on interpolation. Derived from algorithm 4, 5, and 6 in :cite:`Vo:18`. .. versionadded:: 1.9 Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to segment between useful information and noise. size : int Window size of the median filter used to detect stripes. drop_ratio : float, optional Ratio of pixels to be dropped, which is used to to reduce the possibility of the false detection of stripes. norm : bool, optional Apply normalization if True. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs(tomo, func=_remove_stripe_based_interpolation, args=(snr, size, drop_ratio, norm), axis=1, ncore=ncore, nchunk=nchunk) return arr
def project(obj, theta, center=None, ncore=None, nchunk=None): """ Project x-rays through a given 3D object. Parameters ---------- obj : ndarray Voxelized 3D object. theta : array Projection angles in radian. center: array, optional Location of rotation axis. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D tomographic data. """ obj = dtype.as_float32(obj) theta = dtype.as_float32(theta) # Estimate data dimensions. ox, oy, oz = obj.shape dx = theta.size dy = ox dz = np.ceil(np.sqrt(oy * oy + oz * oz)).astype('int') shape = dx, dy, dz tomo = np.zeros(shape, dtype='float32') center = get_center(shape, center) mproc.init_obj(obj) arr = mproc.distribute_jobs( tomo, func=extern.c_project, args=(ox, oy, oz, theta, center, dx, dy, dz), axis=0, ncore=ncore, nchunk=nchunk) return arr
def remove_large_stripe(tomo, snr=3, size=51, drop_ratio=0.1, norm=True, ncore=None, nchunk=None): """ Remove large stripe artifacts from sinogram using Nghia Vo's approach :cite:`Vo:18` (algorithm 5). Parameters ---------- tomo : ndarray 3D tomographic data. snr : float Ratio used to locate of large stripes. Greater is less sensitive. size : int Window size of the median filter. drop_ratio : float, optional Ratio of pixels to be dropped, which is used to reduce the false detection of stripes. norm : bool, optional Apply normalization if True. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Corrected 3D tomographic data. """ arr = mproc.distribute_jobs(tomo, func=_remove_large_stripe, args=(snr, size, drop_ratio, norm), axis=1, ncore=ncore, nchunk=nchunk) return arr
def project(obj, theta, center=None, ncore=None, nchunk=None): """ Project x-rays through a given 3D object. Parameters ---------- obj : ndarray Voxelized 3D object. theta : array Projection angles in radian. center: array, optional Location of rotation axis. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D tomographic data. """ obj = dtype.as_float32(obj) theta = dtype.as_float32(theta) # Estimate data dimensions. ox, oy, oz = obj.shape dx = theta.size dy = ox dz = np.ceil(np.sqrt(oy * oy + oz * oz)).astype('int') shape = dx, dy, dz tomo = np.zeros(shape, dtype='float32') center = get_center(shape, center) mproc.init_obj(obj) arr = mproc.distribute_jobs(tomo, func=extern.c_project, args=(ox, oy, oz, theta, center, dx, dy, dz), axis=0, ncore=ncore, nchunk=nchunk) return arr
def normalize(arr, flat, dark, cutoff=None, ncore=None, out=None): """ Normalize raw projection data using the flat and dark field projections. Parameters ---------- arr : ndarray 3D stack of projections. flat : ndarray 3D flat field data. dark : ndarray 3D dark field data. cutoff : float, optional Permitted maximum vaue for the normalized data. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Normalized 3D tomographic data. """ arr = dtype.as_float32(arr) flat = dtype.as_float32(flat) dark = dtype.as_float32(dark) flat = flat.mean(axis=0) dark = dark.mean(axis=0) arr = mproc.distribute_jobs( arr, func=_normalize, args=(flat, dark, cutoff), axis=0, ncore=ncore, nchunk=0, out=out) return arr
def gaussian_filter(arr, sigma=3, order=0, axis=0, ncore=None, nchunk=None): """ Apply Gaussian filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. sigma : scalar or sequence of scalars Standard deviation for Gaussian kernel. The standard deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes. order : {0, 1, 2, 3} or sequence from same set, optional Order of the filter along each axis is given as a sequence of integers, or as a single number. An order of 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order derivatives are not implemented axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D array of same shape as input. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs( arr.swapaxes(0, axis), func=_gaussian_filter, args=(sigma, order), axis=axis, ncore=ncore, nchunk=nchunk) return arr.swapaxes(0, axis)
def _search_fine(sino, srad, step, init_cen, ratio, drop, ncore=None): """ Fine search for finding the rotation center. """ (nrow, ncol) = sino.shape cen_fliplr = (ncol - 1.0) / 2.0 srad = np.clip(np.abs(srad), 1.0, ncol / 4.0) step = np.clip(np.abs(step), 0.1, srad) init_cen = np.clip(init_cen, srad, ncol - srad - 1) list_cor = init_cen + np.arange(-srad, srad + step, step) flip_sino = np.fliplr(sino) comp_sino = np.flipud(sino) mask = _create_mask(2 * nrow, ncol, 0.5 * ratio * ncol, drop) list_shift = 2.0 * (list_cor - cen_fliplr) list_metric = distribute_jobs(np.float32(list_shift), _calculate_metric, axis=0, args=(sino, flip_sino, comp_sino, mask), ncore=ncore, nchunk=1) cor = list_cor[np.argmin(list_metric)] return cor
def normalize(tomo, flat, dark, cutoff=None, ncore=None, nchunk=None): """ Normalize raw projection data using the flat and dark field projections. Parameters ---------- tomo : ndarray 3D tomographic data. flat : ndarray 3D flat field data. dark : ndarray 3D dark field data. cutoff : float, optional Permitted maximum vaue for the normalized data. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Normalized 3D tomographic data. """ tomo = dtype.as_float32(tomo) flat = dtype.as_float32(flat) dark = dtype.as_float32(dark) flat = flat.mean(axis=0) dark = dark.mean(axis=0) arr = mproc.distribute_jobs( tomo, func=_normalize, args=(flat, dark, cutoff), axis=0, ncore=ncore, nchunk=nchunk) return arr
def normalize(arr, flat, dark, cutoff=None, ncore=None, out=None): """ Normalize raw projection data using the flat and dark field projections. Parameters ---------- arr : ndarray 3D stack of projections. flat : ndarray 3D flat field data. dark : ndarray 3D dark field data. cutoff : float, optional Permitted maximum vaue for the normalized data. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Normalized 3D tomographic data. """ arr = dtype.as_float32(arr) flat = dtype.as_float32(flat) dark = dtype.as_float32(dark) flat = flat.mean(axis=0) dark = dark.mean(axis=0) arr = mproc.distribute_jobs(arr, func=_normalize, args=(flat, dark, cutoff), axis=0, ncore=ncore, nchunk=0, out=out) return arr
def gaussian_filter(arr, sigma=3, order=0, axis=0, ncore=None, nchunk=None): """ Apply Gaussian filter to 3D array along specified axis. Parameters ---------- arr : ndarray Input array. sigma : scalar or sequence of scalars Standard deviation for Gaussian kernel. The standard deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes. order : {0, 1, 2, 3} or sequence from same set, optional Order of the filter along each axis is given as a sequence of integers, or as a single number. An order of 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order derivatives are not implemented axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray 3D array of same shape as input. """ arr = dtype.as_float32(arr) arr = mproc.distribute_jobs(arr.swapaxes(0, axis), func=_gaussian_filter, args=(sigma, order), axis=axis, ncore=ncore, nchunk=nchunk) return arr.swapaxes(0, axis)
def normalize(tomo, flat, dark, cutoff=None, ncore=None, nchunk=None): """ Normalize raw projection data using the flat and dark field projections. Parameters ---------- tomo : ndarray 3D tomographic data. flat : ndarray 3D flat field data. dark : ndarray 3D dark field data. cutoff : float, optional Permitted maximum vaue for the normalized data. ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Normalized 3D tomographic data. """ tomo = dtype.as_float32(tomo) flat = dtype.as_float32(flat) dark = dtype.as_float32(dark) flat = flat.mean(axis=0) dark = dark.mean(axis=0) arr = mproc.distribute_jobs(tomo, func=_normalize, args=(flat, dark, cutoff), axis=0, ncore=ncore, nchunk=nchunk) return arr
def normalize_nf(tomo, flats, dark, flat_loc, cutoff=None, ncore=None, nchunk=None): """ Normalize raw 3D projection data with flats taken more than once during tomography. Normalization for each projection is done with the mean of the nearest set of flat fields (nearest flat fields). Parameters ---------- tomo : ndarray 3D tomographic data. flats : ndarray 3D flat field data. dark : ndarray 3D dark field data. flat_loc : list of int Indices of flat field data within tomography ncore : int, optional Number of cores that will be assigned to jobs. nchunk : int, optional Chunk size for each core. Returns ------- ndarray Normalized 3D tomographic data. """ tomo = dtype.as_float32(tomo) flats = dtype.as_float32(flats) dark = dtype.as_float32(dark) arr = np.zeros_like(tomo) dark = np.median(dark, axis=0) num_flats = len(flat_loc) total_flats = flats.shape[0] total_tomo = tomo.shape[0] num_per_flat = total_flats//num_flats tend = 0 for m, loc in enumerate(flat_loc): fstart = m*num_per_flat fend = (m + 1)*num_per_flat flat = np.median(flats[fstart:fend], axis=0) # Normalization can be parallelized much more efficiently outside this # foor loop accounting for the nested parallelism arising from # chunking the total normalization and each chunked normalization tstart = 0 if m == 0 else tend tend = total_tomo if m >= num_flats-1 else (flat_loc[m+1]-loc)//2 + loc _arr = mproc.distribute_jobs(tomo[tstart:tend], func=_normalize, args=(flat, dark, cutoff), axis=0, ncore=ncore, nchunk=nchunk) arr[tstart:tend] = _arr return arr