Beispiel #1
0
def correlation_func(cor_win_1,
                     cor_win_2,
                     window_size,
                     correlation_method='circular'):
    '''This function is doing the cross-correlation. Right now circular cross-correlation
    That means no zero-padding is done
    the .real is to cut off possible imaginary parts that remains due to finite numerical accuarcy
     '''
    if correlation_method == 'linear':
        cor_win_1 = cor_win_1 - cor_win_1.mean(axis=(1, 2)).reshape(
            cor_win_1.shape[0], 1, 1)
        cor_win_2 = cor_win_2 - cor_win_2.mean(axis=(1, 2)).reshape(
            cor_win_1.shape[0], 1, 1)
        cor_win_1[cor_win_1 < 0] = 0
        cor_win_2[cor_win_2 < 0] = 0

        corr = fftshift(irfft2(
            np.conj(rfft2(cor_win_1, s=(2 * window_size, 2 * window_size))) *
            rfft2(cor_win_2, s=(2 * window_size, 2 * window_size))).real,
                        axes=(1, 2))
        corr = corr[:, window_size // 2:3 * window_size // 2,
                    window_size // 2:3 * window_size // 2]

    else:
        corr = fftshift(irfft2(np.conj(rfft2(cor_win_1)) *
                               rfft2(cor_win_2)).real,
                        axes=(1, 2))
    return corr
Beispiel #2
0
def fft_correlate_images(image_a,
                         image_b,
                         correlation_method="circular",
                         normalized_correlation=True):
    """ FFT based cross correlation
    of two images with multiple views of np.stride_tricks()
    The 2D FFT should be applied to the last two axes (-2,-1) and the
    zero axis is the number of the interrogation window
    This should also work out of the box for rectangular windows.
    Parameters
    ----------
    image_a : 3d np.ndarray, first dimension is the number of windows,
        and two last dimensions are interrogation windows of the first image

    image_b : similar

    correlation_method : string
        one of the three methods implemented: 'circular' or 'linear'
        [default: 'circular].

    normalized_correlation : string
        decides wetehr normalized correlation is done or not: True or False
        [default: True].
    """

    if normalized_correlation:
        # remove the effect of stronger laser or
        # longer exposure for frame B
        # image_a = match_histograms(image_a, image_b)

        # remove mean background, normalize to 0..1 range
        image_a = normalize_intensity(image_a)
        image_b = normalize_intensity(image_b)

    s1 = np.array(image_a.shape[-2:])
    s2 = np.array(image_b.shape[-2:])

    if correlation_method == "linear":
        # have to be normalized, mainly because of zero padding
        size = s1 + s2 - 1
        fsize = 2**np.ceil(np.log2(size)).astype(int)
        fslice = (slice(0, image_a.shape[0]),
                  slice((fsize[0] - s1[0]) // 2, (fsize[0] + s1[0]) // 2),
                  slice((fsize[1] - s1[1]) // 2, (fsize[1] + s1[1]) // 2))
        f2a = rfft2(image_a, fsize, axes=(-2, -1)).conj()
        f2b = rfft2(image_b, fsize, axes=(-2, -1))
        corr = fftshift(irfft2(f2a * f2b).real, axes=(-2, -1))[fslice]
    elif correlation_method == "circular":
        corr = fftshift(irfft2(rfft2(image_a).conj() * rfft2(image_b)).real,
                        axes=(-2, -1))
    else:
        print("method is not implemented!")

    if normalized_correlation:
        corr = corr / (s2[0] * s2[1])  # for extended search area
        corr = np.clip(corr, 0, 1)
    return corr
Beispiel #3
0
def deconvolve_sinogram(sinogram, psf, l=20, mode='laplacian', clip=True):
    """
    Deconvolve a sinogram with given PSF.

    Parameters
    ----------
    sinogram : numpy.ndarray [TPY]
        The blurred sinogram.
    psf : numpy.ndarray [ZXY] or [XY]
        The PSF used to deconvolve.
    l : float, optional
        Strength of the regularization.
    clip : bool, optional
        Clip negative values to 0, default is True.

    Returns
    -------
    numpy.ndarray [TPY]
        The deconvolved sinogram.
    """

    fft_shape = [fft_size(s) for s in sinogram.shape[1:]]

    inverse = inverse_psf_rfft(psf, shape=fft_shape, l=l, mode=mode)

    s_fft = fft.rfft2(sinogram, s=fft_shape)
    i_fft = fft.irfft2(s_fft * inverse, s=fft_shape, overwrite_x=True)
    i_fft = i_fft[:, :sinogram.shape[1], :sinogram.shape[2]]
    if clip:
        np.clip(i_fft, 0, None, out=i_fft)

    return i_fft
Beispiel #4
0
def fft_correlate_strided_images(image_a, image_b):
    """FFT based cross correlation
    of two images with multiple views of np.stride_tricks()

    The 2D FFT should be applied to the last two axes (-2,-1) and the
    zero axis is the number of the interrogation window

    This should also work out of the box for rectangular windows.

    Parameters
    ----------
    image_a : 3d np.ndarray, first dimension is the number of windows,
        and two last dimensions are interrogation windows of the first image
    image_b : similar
    """
    s1 = np.array(image_a.shape[-2:])
    s2 = np.array(image_b.shape[-2:])
    size = s1 + s2 - 1
    fsize = 2**np.ceil(np.log2(size)).astype(int)
    fslice = tuple([slice(0, image_a.shape[0])] +
                   [slice(0, int(sz)) for sz in size])
    f2a = rfft2(image_a, fsize, axes=(-2, -1))
    f2b = rfft2(image_b[:, ::-1, ::-1], fsize, axes=(-2, -1))
    corr = irfft2(f2a * f2b, axes=(-2, -1)).real[fslice]
    return corr
Beispiel #5
0
 def get_cor(self, fname, fit_size=3):
     s = self.roi.size
     data = np.asarray(Image.open(fname))
     for a, b in zip(self.ref_rois, self.roi_iter(data, flip=True)):
         cor = fft.irfft2(a * b, (4 * s, 4 * s))[:-1, :-1]
         (yp, xp), q = subpixel_peak(cor, fit_size)
         xp = xp - 2 * s + 1
         yp = yp - 2 * s + 1
         yield cor, xp, yp, q
Beispiel #6
0
    def test_dirac(self):
        for psf in self.psfs:
            i_psf = fpsopt.inverse_psf_rfft(psf, l=0)
            psfft = fft.rfft2(psf.sum(0))
            dirac = fft.irfft2(psfft * i_psf, s=psf.shape[1:])

            ref = np.zeros_like(dirac)
            ref[(psf.shape[0] - 1) // 2, (psf.shape[0] - 1) // 2] = 1

            np.testing.assert_allclose(dirac, ref, atol=1e-12)
Beispiel #7
0
def makeFilter(shape: List[int], alpha: float, dtype=float) -> np.ndarray:
    assert 1 <= len(shape) <= 2, "shape must be one or two elements"
    if len(shape) == 1:
        shape = [shape[0], shape[0]]

    # Generate filter in the frequency domain
    fy = sf.fftfreq(shape[0])[:, np.newaxis].astype(dtype)
    fx = sf.rfftfreq(shape[1])[np.newaxis, :].astype(dtype)
    H2 = (fx**2 + fy**2)**(alpha / 2.0)

    return sf.fftshift(sf.irfft2(H2))
Beispiel #8
0
def texshadeFFT(x: np.ndarray, alpha: float) -> np.ndarray:
    """FFT-based texture shading elevation

  Given an array `x` of elevation data and an `alpha` > 0, apply the
  texture-shading algorithm using the full (real-only) FFT: the entire `x` array
  will be FFT'd.

  `alpha` is the shading detail factor, i.e., the power of the
  fractional-Laplacian operator. `alpha=0` means no detail (output is the
  input). `alpha=2.0` is the full (non-fractional) Laplacian operator and is
  probably too high. `alpha <= 1.0` seem aesthetically pleasing.

  Returns an array the same dimensions as `x` that contains the texture-shaded
  version of the input array.

  If `x` is memory-mapped and/or your system doesn't have 5x `x`'s memory
  available, consider using `texshade.texshadeSpatial`, which implements a
  low-memory version of the algorithm by approximating the frequency response of
  the fractional-Laplacian filter with a finite impulse response filter applied
  in the spatial-domain.

  Implementation note: this function uses Scipy's FFTPACK routines (in
  `scipy.fftpack`) instead of Numpy's FFT (`numpy.fft`) because the former can
  return single-precision float32. In newer versions of Numpy/Scipy, this
  advantage may have evaporated [1], [2].

  [1] https://github.com/numpy/numpy/issues/6012
  [2] https://github.com/scipy/scipy/issues/2487
  """
    Nyx = [nextprod([2, 3, 5, 7], x) for x in x.shape]

    # Generate filter in the frequency domain
    fy = sf.fftfreq(Nyx[0])[:, np.newaxis].astype(x.dtype)
    fx = sf.rfftfreq(Nyx[1])[np.newaxis, :].astype(x.dtype)
    H2 = (fx**2 + fy**2)**(alpha / 2.0)

    # Compute the FFT of the input and apply the filter
    xr = sf.rfft2(x, s=Nyx) * H2
    H2 = None  # potentially trigger GC here to reclaim H2's memory
    xr = sf.irfft2(xr)
    # Return the same size as input
    return xr[:x.shape[0], :x.shape[1]]
Beispiel #9
0
def fft_correlate_windows(window_a, window_b):
    """ FFT based cross correlation
    it is a so-called linear convolution based,
    since we increase the size of the FFT to
    reduce the edge effects.
    This should also work out of the box for rectangular windows.
    Parameters
    ----------
    window_a : 2d np.ndarray
        a two dimensions array for the first interrogation window,
    window_b : 2d np.ndarray
        a two dimensions array for the second interrogation window.
    # from Stackoverflow:
    from scipy import linalg
    import numpy as np
    # works for rectangular windows as well
    x = [[1 , 0 , 0 , 0] , [0 , -1 , 0 , 0] , [0 , 0 , 3 , 0] ,
        [0 , 0 , 0 , 1], [0 , 0 , 0 , 1]]
    x = np.array(x,dtype=np.float)
    y = [[4 , 5] , [3 , 4]]
    y = np.array(y)
    print ("conv:" ,  signal.convolve2d(x , y , 'full'))
    s1 = np.array(x.shape)
    s2 = np.array(y.shape)
    size = s1 + s2 - 1
    fsize = 2 ** np.ceil(np.log2(size)).astype(int)
    fslice = tuple([slice(0, int(sz)) for sz in size])
    new_x = np.fft.fft2(x , fsize)
    new_y = np.fft.fft2(y , fsize)
    result = np.fft.ifft2(new_x*new_y)[fslice].copy()
    print("fft for my method:" , np.array(result.real, np.int32))
    """
    s1 = np.array(window_a.shape)
    s2 = np.array(window_b.shape)
    size = s1 + s2 - 1
    fsize = 2 ** np.ceil(np.log2(size)).astype(int)
    fslice = tuple([slice(0, int(sz)) for sz in size])
    f2a = rfft2(window_a, fsize)
    f2b = rfft2(window_b[::-1, ::-1], fsize)
    corr = irfft2(f2a * f2b).real[fslice]
    return corr
Beispiel #10
0

if __name__ == '__main__':
    from cbi_toolbox.simu import optics, primitives, imaging
    import cbi_toolbox.splineradon as spl
    import napari

    TEST_SIZE = 64

    s_psf = optics.gaussian_psf(numerical_aperture=0.3,
                                npix_axial=TEST_SIZE + 1,
                                npix_lateral=TEST_SIZE + 1)

    i_psf = inverse_psf_rfft(s_psf, l=1e-15, mode='constant')
    psfft = fft.rfft2(s_psf.sum(0))
    dirac = fft.irfft2(psfft * i_psf, s=s_psf.shape[1:])

    sample = primitives.boccia(TEST_SIZE,
                               radius=(0.8 * TEST_SIZE) // 2,
                               n_stripes=4)
    s_theta = np.arange(90)

    s_radon = spl.radon(sample, theta=s_theta, circle=True)
    s_fpsopt = imaging.fps_opt(sample, s_psf, theta=s_theta)

    s_deconv = deconvolve_sinogram(s_fpsopt, s_psf, l=0)

    viewer = napari.view_image(s_radon)
    viewer.add_image(s_fpsopt)
    viewer.add_image(s_deconv)
Beispiel #11
0
 def test_irfft2(self):
     x = random((30, 20))
     assert_array_almost_equal(x, fft.irfft2(fft.rfft2(x)))
     assert_array_almost_equal(
         x, fft.irfft2(fft.rfft2(x, norm="ortho"), norm="ortho"))
Beispiel #12
0
 def test_irfft2(self):
     x = random((30, 20))
     assert_array_almost_equal(x, fft.irfft2(fft.rfft2(x)))
     for norm in ["backward", "ortho", "forward"]:
         assert_array_almost_equal(
             x, fft.irfft2(fft.rfft2(x, norm=norm), norm=norm))