Esempio n. 1
0
def generate_blob_mask(flat, size, snr):
    """
    Generate a binary mask of blobs from a flat-field image (Ref. [1]).

    Parameters
    ----------
    flat : array_like
        2D array. Flat-field image.
    size : float
        Estimated size of the largest blob.
    snr : float
        Ratio used to segment blobs.

    Returns
    -------
    array_like
        2D array. Binary mask.

    References
    ----------
    .. [1] https://doi.org/10.1364/OE.418448
    """
    mat = ndi.median_filter(flat, (2, 2))
    mask = np.zeros_like(mat)
    for i in range(mat.shape[0]):
        line = mat[i]
        line_fil = ndi.median_filter(line, size)
        line_fil[line_fil == 0.0] = np.mean(line_fil)
        line_norm = line / line_fil
        mask_1d = util.detect_stripe(line_norm, snr)
        mask_1d[0:2] = 0.0
        mask_1d[-2:] = 0.0
        mask[i] = np.float32(ndi.binary_dilation(mask_1d, iterations=1))
    return mask
Esempio n. 2
0
 def test_detect_stripe(self):
     np.random.seed(1)
     lis = np.random.rand(self.size)
     lis_off = np.linspace(0, 1, len(lis))
     lis = lis + lis_off
     lis[self.size // 2:self.size // 2 + 1] = 6.0
     lis_bin = util.detect_stripe(lis, 1.5)
     pos = np.where(lis_bin == 1.0)
     self.assertTrue((len(pos) > 0) and (pos[0] == self.size // 2))
Esempio n. 3
0
def remove_dead_stripe(sinogram,
                       snr=3.0,
                       size=51,
                       residual=True,
                       smooth_strength=10):
    """
    Remove unresponsive or fluctuating stripe artifacts in a sinogram,
    algorithm 6 in Ref. [1]_. Angular direction is along the axis 0.

    Parameters
    ----------
    sinogram : array_like
        2D array. Sinogram image.
    snr : float
        Ratio (>1.0) used to detect stripe locations. Greater is less sensitive.
    size : int
        Window size of the median filter.
    residual : bool, optional
        Removing residual stripes if True.
    smooth_strength : int, optional
        Window size of the uniform filter used to detect stripes.

    Returns
    -------
    ndarray
        2D array. Stripe-removed sinogram.

    References
    ----------
    .. [1] https://doi.org/10.1364/OE.26.028396
    """
    sinogram = np.copy(sinogram)
    (nrow, ncol) = sinogram.shape
    sino_smooth = np.apply_along_axis(ndi.uniform_filter1d, 0, sinogram,
                                      smooth_strength)
    list_diff = np.sum(np.abs(sinogram - sino_smooth), axis=0)
    list_diff_bck = ndi.median_filter(list_diff, size)
    nmean = np.mean(np.abs(list_diff_bck))
    list_diff_bck[list_diff_bck == 0.0] = nmean
    list_fact = list_diff / list_diff_bck
    list_mask = util.detect_stripe(list_fact, snr)
    list_mask = np.float32(ndi.binary_dilation(list_mask, iterations=1))
    list_mask[0:2] = 0.0
    list_mask[-2:] = 0.0
    xlist = np.where(list_mask < 1.0)[0]
    ylist = np.arange(nrow)
    mat = sinogram[:, xlist]
    finter = interpolate.interp2d(xlist, ylist, mat, kind='linear')
    xlist_miss = np.where(list_mask > 0.0)[0]
    if (ncol // 3) > len(xlist_miss) > 0:
        sinogram[:, xlist_miss] = finter(xlist_miss, ylist)
    if residual is True:
        sinogram = remove_large_stripe(sinogram, snr, size)
    return sinogram
Esempio n. 4
0
def remove_stripe_based_interpolation(sinogram,
                                      snr=3.0,
                                      size=51,
                                      drop_ratio=0.1,
                                      norm=True,
                                      kind="linear",
                                      **options):
    """
    Combination of algorithm 4, 5, and 6 in Ref. [1].
    Angular direction is along the axis 0.

    Parameters
    ----------
    sinogram : array_like
        2D array. Sinogram image
    snr : float
        Ratio (>1.0) used to detect stripe locations. Greater is less sensitive.
    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.
    kind : {'linear', 'cubic', 'quintic'}, optional
        The kind of spline interpolation to use. Default is 'linear'.
    options : dict, optional
        Use another smoothing filter rather than the median filter.
        E.g. options={"method": "gaussian_filter", "para1": (1,21))}

    Returns
    -------
    array_like
        2D array. Stripe-removed sinogram.

    References
    ----------
    .. [1] https://doi.org/10.1364/OE.26.028396
    """
    msg = "\n Please use the dictionary format: options={'method':" \
          " 'filter_name', 'para1': parameter_1, 'para2': parameter_2}"
    drop_ratio = np.clip(drop_ratio, 0.0, 0.8)
    sinogram = np.copy(sinogram)
    (nrow, ncol) = sinogram.shape
    ndrop = int(0.5 * drop_ratio * nrow)
    sino_sort = np.sort(sinogram, axis=0)
    if len(options) == 0:
        sino_smooth = ndi.median_filter(sino_sort, (1, size))
    else:
        if not isinstance(options, dict):
            raise ValueError(msg)
        sino_smooth = np.copy(sino_sort)
        for opt_name in options:
            opt = options[opt_name]
            method = tuple(opt.values())[0]
            para = tuple(opt.values())[1:]
            if method in dir(ndi):
                try:
                    sino_smooth = getattr(ndi, method)(sino_smooth, *para)
                except:
                    raise ValueError(msg)
            else:
                if method in dir(util):
                    try:
                        sino_smooth = getattr(util, method)(sino_smooth, *para)
                    except:
                        raise ValueError(msg)
                else:
                    raise ValueError("Can't find the method: '{}' in the"
                                     " namespace".format(method))
    list1 = np.mean(sino_sort[ndrop:nrow - ndrop], axis=0)
    list2 = np.mean(sino_smooth[ndrop:nrow - ndrop], axis=0)
    list_fact = np.divide(list1,
                          list2,
                          out=np.ones_like(list1),
                          where=list2 != 0)
    list_mask = util.detect_stripe(list_fact, snr)
    list_mask = np.float32(ndi.binary_dilation(list_mask, iterations=1))
    mat_fact = np.tile(list_fact, (nrow, 1))
    if norm is True:
        sinogram = sinogram / mat_fact
    list_mask[0:2] = 0.0
    list_mask[-2:] = 0.0
    xlist = np.where(list_mask < 1.0)[0]
    ylist = np.arange(nrow)
    zmat = sinogram[:, xlist]
    finter = interpolate.interp2d(xlist, ylist, zmat, kind=kind)
    xlist_miss = np.where(list_mask > 0.0)[0]
    if len(xlist_miss) > 0:
        sinogram[:, xlist_miss] = finter(xlist_miss, ylist)
    return sinogram
Esempio n. 5
0
def remove_large_stripe(sinogram,
                        snr=3.0,
                        size=51,
                        drop_ratio=0.1,
                        norm=True,
                        **options):
    """
    Remove large stripe artifacts in a sinogram, algorithm 5 in Ref. [1].
    Angular direction is along the axis 0.

    Parameters
    ----------
    sinogram : array_like
        2D array. Sinogram image
    snr : float
        Ratio (>1.0) used to detect stripe locations. 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 to reduce
        the possibility of the false detection of stripes.
    norm : bool, optional
        Apply normalization if True.
    options : dict, optional
        Use another smoothing filter rather than the median filter.
        E.g. options={"method": "gaussian_filter", "para1": (1,21))}.

    Returns
    -------
    array_like
        2D array. Stripe-removed sinogram.

    References
    ----------
    .. [1] https://doi.org/10.1364/OE.26.028396
    """
    msg = "\n Please use the dictionary format: options={'method':" \
          " 'filter_name', 'para1': parameter_1, 'para2': parameter_2}"
    sinogram = np.copy(np.float32(sinogram))
    drop_ratio = np.clip(drop_ratio, 0.0, 0.8)
    (nrow, ncol) = sinogram.shape
    ndrop = int(0.5 * drop_ratio * nrow)
    sino_sort, sino_index = util.sort_forward(sinogram, axis=0)
    if len(options) == 0:
        sino_smooth = ndi.median_filter(sino_sort, (1, size))
    else:
        if not isinstance(options, dict):
            raise ValueError(msg)
        sino_smooth = np.copy(sino_sort)
        for opt_name in options:
            opt = options[opt_name]
            method = tuple(opt.values())[0]
            if method in dir(ndi):
                para = tuple(opt.values())[1:]
                try:
                    sino_smooth = getattr(ndi, method)(sino_smooth, *para)
                except:
                    raise ValueError(msg)
            else:
                if method in dir(util):
                    try:
                        sino_smooth = getattr(util, method)(sino_smooth, *para)
                    except:
                        raise ValueError(msg)
                else:
                    raise ValueError("Can't find the method: '{}' in the"
                                     " namespace".format(method))
    list1 = np.mean(sino_sort[ndrop:nrow - ndrop], axis=0)
    list2 = np.mean(sino_smooth[ndrop:nrow - ndrop], axis=0)
    list_fact = np.divide(list1,
                          list2,
                          out=np.ones_like(list1),
                          where=list2 != 0)
    list_mask = util.detect_stripe(list_fact, snr)
    list_mask = np.float32(ndi.binary_dilation(list_mask, iterations=1))
    if norm is True:
        sinogram = sinogram / np.tile(list_fact, (nrow, 1))
    sino_corr = util.sort_backward(sino_smooth, sino_index, axis=0)
    xlist_miss = np.where(list_mask > 0.0)[0]
    sinogram[:, xlist_miss] = sino_corr[:, xlist_miss]
    return sinogram