Exemple #1
0
def remove_zinger(tomo, dif, size=3, ncore=None, nchunk=None):
    """
    Remove high intensity bright spots from 3D tomographic data.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    dif : float
        Expected difference value between outlier measurement and
        the median filtered raw measurement.
    size : int, optional
        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 = mp.distribute_jobs(tomo,
                             func=_remove_zinger,
                             args=(dif, size),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #2
0
def remove_stripe2(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 = mp.distribute_jobs(tomo,
                             func=_remove_stripe2,
                             args=(nblock, alpha),
                             axis=1,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #3
0
def median_filter(arr, size=3, axis=0, ncore=None, nchunk=None):
    """
    Apply median filter to 3D array along specified axis.

    Parameters
    ----------
    arr : ndarray
        Arbitrary 3D 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 = as_float32(arr)
    arr = mp.distribute_jobs(
        arr,
        func=_median_filter,
        args=(size, axis),
        axis=axis,
        ncore=ncore,
        nchunk=nchunk)
    return arr
Exemple #4
0
def correct_air(tomo, air=10, ncore=None, nchunk=None):
    """
    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 = as_float32(tomo)
    air = as_int32(air)

    arr = mp.distribute_jobs(tomo,
                             func=_correct_air,
                             args=(air, ),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #5
0
def retrieve_phase(
        tomo, psize=1e-4, dist=50, energy=20,
        alpha=1e-4, pad=True, ind=None):
    """
    Perform single-step phase retrieval from phase-contrast measurements
    :cite:`Paganin:02`.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    psize : 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.
    ind : array of int, optional
        Projection indices at which the phase retrieval is applied.

    Returns
    -------
    ndarray
        Approximated 3D tomographic phase data.
    """
    if type(tomo) == str and tomo == 'SHARED':
        tomo = mp.shared_data
    else:
        arr = mp.distribute_jobs(
            tomo, func=retrieve_phase,
            args=(psize, dist, energy, alpha, pad), axis=0)
        return arr

    dx, dy, dz = tomo.shape
    if ind is None:
        ind = np.arange(0, dx)

    # Compute the filter.
    H, xshift, yshift, prj = _paganin_filter(
        tomo, psize, dist, energy, alpha, pad)

    for m in ind:
        proj = tomo[m, :, :]
        if pad:
            prj[xshift:dy + xshift, yshift:dz + yshift] = proj
            fproj = np.fft.fft2(prj)
            filtproj = np.multiply(H, fproj)
            tmp = np.real(np.fft.ifft2(filtproj)) / np.max(H)
            proj = tmp[xshift:dy + xshift, yshift:dz + yshift]
        elif not pad:
            fproj = np.fft.fft2(proj)
            filtproj = np.multiply(H, fproj)
            proj = np.real(np.fft.ifft2(filtproj)) / np.max(H)
        tomo[m, :, :] = proj
Exemple #6
0
def median_filter(tomo, size=3, axis=0, ind=None):
    """
    Apply median filter to a 3D array along a specified axis.

    Parameters
    ----------
    tomo : ndarray
        Arbitrary 3D array.
    size : int, optional
        The size of the filter.
    axis : int, optional
        Axis along which median filtering is performed.
    ind : array of int, optional
        Indices at which the filtering is applied.

    Returns
    -------
    ndarray
        Median filtered 3D array.
    """
    if type(tomo) == str and tomo == 'SHARED':
        tomo = mp.shared_data
    else:
        arr = mp.distribute_jobs(
            tomo, func=median_filter, axis=axis,
            args=(size, axis))
        return arr

    dx, dy, dz = tomo.shape
    if ind is None:
        if axis == 0:
            ind = np.arange(0, dx)
        elif axis == 1:
            ind = np.arange(0, dy)
        elif axis == 2:
            ind = np.arange(0, dz)

    if axis == 0:
        for m in ind:
            tomo[m, :, :] = filters.median_filter(
                tomo[m, :, :], (size, size))
    elif axis == 1:
        for m in ind:
            tomo[:, m, :] = filters.median_filter(
                tomo[:, m, :], (size, size))
    elif axis == 2:
        for m in ind:
            tomo[:, :, m] = filters.median_filter(
                tomo[:, :, m], (size, size))
Exemple #7
0
def normalize(tomo, flat, dark, cutoff=None, ind=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.
    ind : array of int, optional
        Projection indices at which the normalization is applied.

    Returns
    -------
    ndarray
        Normalized 3D tomographic data.
    """
    if type(tomo) == str and tomo == 'SHARED':
        tomo = mp.shared_data
    else:
        arr = mp.distribute_jobs(
            tomo, func=normalize, axis=0,
            args=(flat, dark, cutoff))
        return arr

    dx, dy, dz = tomo.shape
    if ind is None:
        ind = np.arange(0, dx)

    # Calculate average flat and dark fields for normalization.
    flat = flat.mean(axis=0)
    dark = dark.mean(axis=0)

    # Avoid zero division in normalization
    denom = flat - dark
    denom[denom == 0] = 1e-6

    for m in ind:
        proj = tomo[m, :, :]
        proj = np.divide(proj - dark, denom)
        if cutoff is not None:
            proj[proj > cutoff] = cutoff
        tomo[m, :, :] = proj
Exemple #8
0
def retrieve_phase(tomo,
                   psize=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.
    psize : 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.
    """
    # Compute the filter.
    H, xshift, yshift, prj = _paganin_filter(tomo, psize, dist, energy, alpha,
                                             pad)

    arr = mp.distribute_jobs(tomo,
                             func=_retrieve_phase,
                             args=(H, xshift, yshift, prj, pad),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #9
0
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 = as_float32(obj)

    # Estimate data dimensions.
    ox, oy, oz = obj.shape
    dx = len(theta)
    dy = ox
    dz = np.ceil(np.sqrt(oy * oy + oz * oz)).astype('int')
    tomo = np.zeros((dx, dy, dz), dtype='float32')
    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center

    theta = as_float32(theta)
    center = as_float32(center)

    _init_shared(obj)
    arr = mp.distribute_jobs(tomo,
                             func=_project,
                             args=(theta, center),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #10
0
def remove_stripe1(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)))

    arr = mp.distribute_jobs(tomo,
                             func=_remove_stripe1,
                             args=(level, wname, sigma, pad),
                             axis=1,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #11
0
def gaussian_filter(arr, sigma, order=0, axis=0, ncore=None, nchunk=None):
    """
    Apply Gaussian filter to 3D array along specified axis.

    Parameters
    ----------
    arr : ndarray
        Arbitrary 3D 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 = as_float32(arr)
    arr = mp.distribute_jobs(
        arr,
        func=_gaussian_filter,
        args=(sigma, order, axis),
        axis=axis,
        ncore=ncore,
        nchunk=nchunk)
    return arr
Exemple #12
0
def remove_zinger(tomo, dif=1000, size=3, ind=None):
    """
    Remove high intensity bright spots from tomographic data.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    dif : float, optional
        Expected difference value between outlier measurements and
        the median filtered raw measurements.
    size : int, optional
        Size of the median filter.
    ind : array of int, optional
        Projection indices at which the zinger removal is applied.

    Returns
    -------
    ndarray
        Corrected 3D tomographic data.
    """
    if type(tomo) == str and tomo == 'SHARED':
        tomo = mp.shared_data
    else:
        arr = mp.distribute_jobs(
            tomo, func=remove_zinger, axis=0,
            args=(dif, size))
        return arr

    dx, dy, dz = tomo.shape

    if ind is None:
        ind = np.arange(0, dx)

    mask = np.zeros((1, dy, dz))
    for m in ind:
        tmp = filters.median_filter(tomo[m, :, :], (size, size))
        mask = ((tomo[m, :, :] - tmp) >= dif).astype(int)
        tomo[m, :, :] = tmp * mask + tomo[m, :, :] * (1 - mask)
Exemple #13
0
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 = as_float32(tomo)
    flat = as_float32(flat)
    dark = as_float32(dark)

    # Calculate average flat and dark fields for normalization.
    flat = flat.mean(axis=0)
    dark = dark.mean(axis=0)

    arr = mp.distribute_jobs(tomo,
                             func=_normalize,
                             args=(flat, dark, cutoff),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #14
0
def pml_hybrid(tomo,
               theta,
               center=None,
               emission=True,
               recon=None,
               num_gridx=None,
               num_gridy=None,
               num_iter=1,
               reg_par=None,
               ncore=None,
               nchunk=None):
    """
    Reconstruct object from projection data using penalized maximum
    likelihood algorithm with weighted linear and quadratic penalties
    :cite:`Chang:04`.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    theta : array
        Projection angles in radian.
    center: array, optional
        Location of rotation axis.
    emission : bool, optional
        Determines whether data is emission or transmission type.
    recon : ndarray, optional
        Initial values of the reconstruction object.
    num_gridx, num_gridy : int, optional
        Number of pixels along x- and y-axes in the reconstruction grid.
    num_iter : int, optional
        Number of algorithm iterations performed.
    reg_par : list, optional
        Regularization hyperparameters as an array, (beta, delta).
    num_block : int, optional
        Number of data blocks for intermediate updating the object.
    ind_block : array of int, optional
        Order of projections to be used for updating.
    ncore : int, optional
        Number of cores that will be assigned to jobs.
    nchunk : int, optional
        Chunk size for each core.

    Returns
    -------
    ndarray
        Reconstructed 3D object.
    """
    tomo = as_float32(tomo)
    theta = as_float32(theta)

    dx, dy, dz = tomo.shape
    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center
    if num_gridx is None:
        num_gridx = dz
    if num_gridy is None:
        num_gridy = dz
    if emission is False:
        tomo = -np.log(tomo)
    if recon is None:
        recon = 1e-6 * np.ones((dy, num_gridx, num_gridy), dtype='float32')
    if reg_par is None:
        reg_par = np.ones(10, dtype="float32")

    center = as_float32(center)
    recon = as_float32(recon)
    num_gridx = as_int32(num_gridx)
    num_gridy = as_int32(num_gridy)
    num_iter = as_int32(num_iter)
    reg_par = as_float32(reg_par)

    _init_shared(tomo)
    arr = mp.distribute_jobs(recon,
                             func=_pml_hybrid,
                             args=(theta, center, num_gridx, num_gridy,
                                   num_iter, reg_par),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #15
0
def art(tomo,
        theta,
        center=None,
        emission=True,
        recon=None,
        num_gridx=None,
        num_gridy=None,
        num_iter=1,
        ncore=None,
        nchunk=None):
    """
    Reconstruct object from projection data using algebraic reconstruction
    technique (ART) :cite:`Kak:98`.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    theta : array
        Projection angles in radian.
    center: array, optional
        Location of rotation axis.
    emission : bool, optional
        Determines whether data is emission or transmission type.
    recon : ndarray, optional
        Initial values of the reconstruction object.
    num_gridx, num_gridy : int, optional
        Number of pixels along x- and y-axes in the reconstruction grid.
    num_iter : int, optional
        Number of algorithm iterations performed.
    ncore : int, optional
        Number of cores that will be assigned to jobs.
    nchunk : int, optional
        Chunk size for each core.

    Returns
    -------
    ndarray
        Reconstructed 3D object.
    """
    tomo = as_float32(tomo)
    theta = as_float32(theta)

    dx, dy, dz = tomo.shape
    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center
    if num_gridx is None:
        num_gridx = dz
    if num_gridy is None:
        num_gridy = dz
    if emission is False:
        tomo = -np.log(tomo)
    if recon is None:
        recon = 1e-6 * np.ones((dy, num_gridx, num_gridy), dtype='float32')

    center = as_float32(center)
    recon = as_float32(recon)
    num_gridx = as_int32(num_gridx)
    num_gridy = as_int32(num_gridy)
    num_iter = as_int32(num_iter)

    _init_shared(tomo)
    arr = mp.distribute_jobs(recon,
                             func=_art,
                             args=(theta, center, num_gridx, num_gridy,
                                   num_iter),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #16
0
def osem(tomo,
         theta,
         center=None,
         emission=True,
         recon=None,
         num_gridx=None,
         num_gridy=None,
         num_iter=1,
         num_block=1,
         ind_block=None,
         ncore=None,
         nchunk=None):
    """
    Reconstruct object from projection data using ordered-subset
    expectation-maximization (OS-EM) :cite:`Hudson:94`.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    theta : array
        Projection angles in radian.
    center: array, optional
        Location of rotation axis.
    emission : bool, optional
        Determines whether data is emission or transmission type.
    recon : ndarray, optional
        Initial values of the reconstruction object.
    num_gridx, num_gridy : int, optional
        Number of pixels along x- and y-axes in the reconstruction grid.
    num_iter : int, optional
        Number of algorithm iterations performed.
    num_block : int, optional
        Number of data blocks for intermediate updating the object.
    ind_block : array of int, optional
        Order of projections to be used for updating.
    ncore : int, optional
        Number of cores that will be assigned to jobs.
    nchunk : int, optional
        Chunk size for each core.

    Returns
    -------
    ndarray
        Reconstructed 3D object.
    """
    tomo = as_float32(tomo)
    theta = as_float32(theta)

    dx, dy, dz = tomo.shape
    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center
    if num_gridx is None:
        num_gridx = dz
    if num_gridy is None:
        num_gridy = dz
    if emission is False:
        tomo = -np.log(tomo)
    if recon is None:
        recon = 1e-6 * np.ones((dy, num_gridx, num_gridy), dtype='float32')
    if ind_block is None:
        ind_block = np.arange(0, dx).astype("float32")

    center = as_float32(center)
    recon = as_float32(recon)
    num_gridx = as_int32(num_gridx)
    num_gridy = as_int32(num_gridy)
    num_iter = as_int32(num_iter)
    num_block = as_int32(num_block)
    ind_block = as_float32(ind_block)

    _init_shared(tomo)
    arr = mp.distribute_jobs(recon,
                             func=_osem,
                             args=(theta, center, num_gridx, num_gridy,
                                   num_iter, num_block, ind_block),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #17
0
def gridrec(tomo,
            theta,
            center=None,
            emission=True,
            num_gridx=None,
            num_gridy=None,
            filter_name='shepp',
            ncore=None,
            nchunk=None):
    """
    Reconstruct object from projection data using gridrec algorithm
    :cite:`Dowd:99`.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    theta : array
        Projection angles in radian.
    center: array, optional
        Location of rotation axis.
    emission : bool, optional
        Determines whether data is emission or transmission type.
    num_gridx, num_gridy : int, optional
        Number of pixels along x- and y-axes in the reconstruction grid.
    filter_name : str, optional
        Filter name for weighting. 'shepp', 'hann', 'hamming', 'ramlak',
        'cosine' or 'none'.
    ncore : int, optional
        Number of cores that will be assigned to jobs.
    nchunk : int, optional
        Chunk size for each core.

    Returns
    -------
    ndarray
        Reconstructed 3D object.
    """
    tomo = as_float32(tomo)
    theta = as_float32(theta)

    dx, dy, dz = tomo.shape

    # Gridrec accepts even number of slices.
    is_odd = False
    if tomo.shape[1] % 2 != 0:
        is_odd = True
        lasttomo = np.expand_dims(tomo[:, -1, :], 1)
        tomo = np.append(tomo, lasttomo, 1)
        dy += 1

    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center
    if num_gridx is None:
        num_gridx = dz
    if num_gridy is None:
        num_gridy = dz
    if emission is False:
        tomo = -np.log(tomo)
    recon = 1e-6 * np.ones((dy, num_gridx, num_gridy), dtype='float32')
    filter_name = np.array(filter_name, dtype=(str, 16))

    center = as_float32(center)
    num_gridx = as_int32(num_gridx)
    num_gridy = as_int32(num_gridy)

    # Chunk size can't be smaller than two for gridrec.
    if ncore is None:
        ncore = multiprocessing.cpu_count()
    if dx < ncore:
        ncore = dx
    if nchunk is None:
        nchunk = (dy - 1) // ncore + 1
    if nchunk < 2:
        nchunk = 2

    _init_shared(tomo)
    arr = mp.distribute_jobs(recon,
                             func=_gridrec,
                             args=(theta, center, num_gridx, num_gridy,
                                   filter_name),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)

    # Dump last slice if original number of sice was even.
    if is_odd:
        arr = arr[0:-1, :, :]
    return arr
Exemple #18
0
def fbp(tomo,
        theta,
        center=None,
        emission=True,
        num_gridx=None,
        num_gridy=None,
        filter_name='shepp',
        ncore=None,
        nchunk=None):
    """
    Reconstruct object from projection data using filtered back
    projection (FBP).

    Warning
    -------
    Filter not implemented yet.

    Parameters
    ----------
    tomo : ndarray
        3D tomographic data.
    theta : array
        Projection angles in radian.
    center: array, optional
        Location of rotation axis.
    emission : bool, optional
        Determines whether data is emission or transmission type.
    num_gridx, num_gridy : int, optional
        Number of pixels along x- and y-axes in the reconstruction grid.
    filter_name : str, optional
        Filter name for weighting. 'shepp', 'hann', 'hamming', 'ramlak',
    ncore : int, optional
        Number of cores that will be assigned to jobs.
    nchunk : int, optional
        Chunk size for each core.

    Returns
    -------
    ndarray
        Reconstructed 3D object.
    """
    tomo = as_float32(tomo)
    theta = as_float32(theta)

    dx, dy, dz = tomo.shape
    if center is None:
        center = np.ones(dy, dtype='float32') * dz / 2.
    elif np.array(center).size == 1:
        center = np.ones(dy, dtype='float32') * center
    if num_gridx is None:
        num_gridx = dz
    if num_gridy is None:
        num_gridy = dz
    if emission is False:
        tomo = -np.log(tomo)
    recon = 1e-6 * np.ones((dy, num_gridx, num_gridy), dtype='float32')
    filter_name = np.array(filter_name, dtype=(str, 16))

    center = as_float32(center)
    num_gridx = as_int32(num_gridx)
    num_gridy = as_int32(num_gridy)

    _init_shared(tomo)
    arr = mp.distribute_jobs(recon,
                             func=_fbp,
                             args=(theta, center, num_gridx, num_gridy,
                                   filter_name),
                             axis=0,
                             ncore=ncore,
                             nchunk=nchunk)
    return arr
Exemple #19
0
def remove_stripe(
        tomo, level=None, wname='db5',
        sigma=2, pad=True, ind=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.
    ind : array of int, optional
        Sinogram indices at which the stripe removal is applied.

    Returns
    -------
    ndarray
        Corrected 3D tomographic data.
    """
    if type(tomo) == str and tomo == 'SHARED':
        tomo = mp.shared_data
    else:
        arr = mp.distribute_jobs(
            tomo, func=remove_stripe, axis=1,
            args=(level, wname, sigma, pad))
        return arr

    dx, dy, dz = tomo.shape
    if ind is None:
        ind = np.arange(0, dy)
    if level is None:
        size = np.max(tomo.shape)
        level = int(np.ceil(np.log2(size)))

    # pad temp image.
    nx = dx
    if pad:
        nx = dx + dx / 8

    xshift = int((nx - dx) / 2.)
    sli = np.zeros((nx, dz), dtype='float32')

    for n in ind:
        sli[xshift:dx + xshift, :] = tomo[:, n, :]

        # Wavelet decomposition.
        cH = []
        cV = []
        cD = []
        for m in range(level):
            sli, (cHt, cVt, cDt) = pywt.dwt2(sli, wname)
            cH.append(cHt)
            cV.append(cVt)
            cD.append(cDt)

        # FFT transform of horizontal frequency bands.
        for m in range(level):
            # FFT
            fcV = np.fft.fftshift(np.fft.fft(cV[m], axis=0))
            my, mx = fcV.shape

            # Damping of ring artifact information.
            y_hat = (np.arange(-my, my, 2, dtype='float') + 1) / 2
            damp = 1 - np.exp(-np.power(y_hat, 2) / (2 * np.power(sigma, 2)))
            fcV = np.multiply(fcV, np.transpose(np.tile(damp, (mx, 1))))

            # Inverse FFT.
            cV[m] = np.real(np.fft.ifft(np.fft.ifftshift(fcV), axis=0))

        # Wavelet reconstruction.
        for m in range(level)[::-1]:
            sli = sli[0:cH[m].shape[0], 0:cH[m].shape[1]]
            sli = pywt.idwt2((sli, (cH[m], cV[m], cD[m])), wname)

        tomo[:, n, :] = sli[xshift:dx + xshift, 0:dz]