示例#1
0
def fft2D():
    from scipy.fft import ifftn
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    N = 100
    f, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2,
                                                         3,
                                                         sharex='col',
                                                         sharey='row')
    xf = np.zeros((N, N))
    xf[0, 5] = 1
    xf[0, N - 5] = 1
    Z = ifftn(xf)
    ax1.imshow(xf, cmap=cm.Reds)
    ax4.imshow(np.real(Z), cmap=cm.gray)
    xf = np.zeros((N, N))
    xf[5, 0] = 1
    xf[N - 5, 0] = 1
    Z = ifftn(xf)
    ax2.imshow(xf, cmap=cm.Reds)
    ax5.imshow(np.real(Z), cmap=cm.gray)
    xf = np.zeros((N, N))
    xf[5, 10] = 1
    xf[N - 5, N - 10] = 1
    Z = ifftn(xf)
    ax3.imshow(xf, cmap=cm.Reds)
    ax6.imshow(np.real(Z), cmap=cm.gray)
    plt.show()
def fft(x, direction='C2C', inverse=False):
    """
        Interface with torch FFT routines for 2D signals.

        Example
        -------
        x = torch.randn(128, 32, 32, 2)
        x_fft = fft(x, inverse=True)

        Parameters
        ----------
        input : tensor
            complex input for the FFT
        direction : string
            'C2R' for complex to real, 'C2C' for complex to complex
        inverse : bool
            True for computing the inverse FFT.
            NB : if direction is equal to 'C2R', then an error is raised.

    """
    if direction == 'C2R':
        if not inverse:
            raise RuntimeError(
                'C2R mode can only be done with an inverse FFT.')

    if direction == 'C2R':
        output = np.real(ifftn(x, axes=(-3, -2, -1)))
    elif direction == 'C2C':
        if inverse:
            output = ifftn(x, axes=(-3, -2, -1))
        else:
            output = fftn(x, axes=(-3, -2, -1))

    return output
示例#3
0
 def test_ifftn(self):
     x = random((30, 20, 10)) + 1j*random((30, 20, 10))
     assert_array_almost_equal(
         fft.ifft(fft.ifft(fft.ifft(x, axis=2), axis=1), axis=0),
         fft.ifftn(x))
     assert_array_almost_equal(fft.ifftn(x) * np.sqrt(30 * 20 * 10),
                               fft.ifftn(x, norm="ortho"))
示例#4
0
def fft_allwfc_G2R(wfc, gkspace, nr1, nr2, nr3, omega):
  igwx = gkspace['igwx']
  gamma_only = gkspace['gamma_only']
  mill = gkspace['mill']
  try: 
    nox = wfc.shape[0]
    nwx = wfc.shape[1]
    wfcg = np.zeros((nwx,nr1,nr2,nr3), dtype=complex)
  except:
    nox = 0
    wfcg = np.zeros((nr1,nr2,nr3), dtype=complex)
  if nox == 0:
    for ig in range(igwx):
      wfcg[:,mill[0,ig],mill[1,ig],mill[2,ig]] = wfc[:,ig]
      if gamma_only:
        wfcg[:,-mill[0,ig],-mill[1,ig],-mill[2,ig]] = np.conj(wfc[:,ig])
    wfcr = FFT.ifftn(wfcg) * nr1 * nr2 * nr3 / np.sqrt(omega)
  else:
    wfcr = np.zeros((nox,nr1,nr2,nr3), dtype=complex)
    for no in range(nox):
      for ig in range(igwx):
        wfcg[no,mill[0,ig],mill[1,ig],mill[2,ig]] = wfc[no,ig]
        if gamma_only:
          wfcg[no,-mill[0,ig],-mill[1,ig],-mill[2,ig]] = np.conj(wfc[no,ig])
      wfcr[no] = FFT.ifftn(wfcg[no]) * nr1 * nr2 * nr3 / np.sqrt(omega)
  return wfcr
示例#5
0
def adjoint(y, ss, idx):
    Y = np.zeros(ss, dtype=complex)
    Y = Y.reshape((-1, 1))
    Y[idx] = y
    Y = Y.reshape(ss)
    Y = ifftn(Y, ss)
    return Y.reshape((-1, 1))
def convolution_square_root(PSI,
                            pre_expansion=0,
                            post_contraction=0,
                            positive_real_branch_cut=np.pi,
                            negative_real_branch_cut=0.0):
    # Input PSI and output Z are BoxFunction convolution kernels
    # Z is the convolution kernel for the square root of the operator that does convolution with PSI
    initial_width = PSI.width
    s = pre_expansion
    PSI = PSI.restrict_to_new_box(PSI.min - s * PSI.width, PSI.max +
                                  s * PSI.width)  # expand PSI box by zero

    PSI_shifted_array = np.roll(PSI.array,
                                -PSI.zeropoint_index,
                                axis=np.arange(PSI.ndim))

    fft_PSI = fft.fftn(PSI_shifted_array)
    sqrt_fft_PSI = np.zeros(fft_PSI.shape, dtype=complex)
    sqrt_fft_PSI[fft_PSI.real >= 0] = square_root(fft_PSI[fft_PSI.real >= 0],
                                                  positive_real_branch_cut)
    sqrt_fft_PSI[fft_PSI.real < 0] = square_root(fft_PSI[fft_PSI.real < 0],
                                                 negative_real_branch_cut)

    Z_shifted_array = fft.ifftn(sqrt_fft_PSI)

    Z_array = np.roll(Z_shifted_array,
                      PSI.zeropoint_index,
                      axis=np.arange(PSI.ndim)) / np.sqrt(PSI.dV)

    Z = BoxFunction(PSI.min, PSI.max, Z_array)

    t = post_contraction
    Z = Z.restrict_to_new_box(Z.min + t * initial_width,
                              Z.max - t * initial_width)  # contract Z box
    return Z
示例#7
0
def uifftn(inarray, dim=None):
    """N-dimensional unitary inverse Fourier transform.

    Parameters
    ----------
    inarray : ndarray
        The array to transform.
    dim : int, optional
        The last axis along which to compute the transform. All
        axes by default.

    Returns
    -------
    outarray : ndarray (same shape than inarray)
        The unitary inverse N-D Fourier transform of ``inarray``.

    Examples
    --------
    >>> input = np.ones((3, 3, 3))
    >>> output = uifftn(input)
    >>> np.allclose(np.sum(input) / np.sqrt(input.size), output[0, 0, 0])
    True
    >>> output.shape
    (3, 3, 3)
    """
    if dim is None:
        dim = inarray.ndim
    outarray = fft.ifftn(inarray, axes=range(-dim, 0), norm='ortho')
    return outarray
示例#8
0
def _elser_particle_old(resolution):
    """This is the original function from Veit Elser without the
    tunable feature size."""
    x_coordinates = _numpy.arange(resolution +
                                  2) - (resolution + 2) / 2.0 + 0.5
    y_coordinates = _numpy.arange(resolution +
                                  2) - (resolution + 2) / 2.0 + 0.5
    z_coordinates = _numpy.arange(resolution +
                                  2) - (resolution + 2) / 2.0 + 0.5
    radius = _numpy.sqrt(x_coordinates[_numpy.newaxis, _numpy.newaxis, :]**2 +
                         y_coordinates[_numpy.newaxis, :, _numpy.newaxis]**2 +
                         z_coordinates[:, _numpy.newaxis, _numpy.newaxis]**2)
    particle_mask = radius > resolution / 2.
    lp_mask = _fft.fftshift(radius > resolution / 4.)

    particle = _numpy.random.random(
        (resolution + 2, resolution + 2, resolution + 2))

    for _ in range(4):
        particle[particle_mask] = 0.0
        particle_ft = _fft.fftn(particle)
        particle_ft[lp_mask] = 0.0
        particle[:, :] = abs(_fft.ifftn(particle))
        particle_average = _numpy.average(particle.flatten())
        particle[particle > 0.5 * particle_average] = 1.0
        particle[particle <= 0.5 * particle_average] = 0.0

    particle[particle_mask] = 0.0
    return particle
示例#9
0
def spacecharge_meshes(rho_mesh, deltas, gamma=1, offset=(0,0,0), components=['Ex', 'Ey', 'Ez']):
    """
    Computes several components at once using an explicit FFT convolution.
    
    This is the preferred routine.
    
    """
    
    # FFT Configuration
    fft  = lambda x: sp_fft.fftn(x,  overwrite_x=True)
    ifft = lambda x: sp_fft.ifftn(x, overwrite_x=True)
    
    # Make double sized array
    nx, ny, nz = rho_mesh.shape
    crho = np.zeros( (2*nx, 2*ny, 2*nz))
    crho[0:nx,0:ny,0:nz] = rho_mesh[0:nx,0:ny,0:nz]
    # FFT
    crho = fft(crho)
    
    # Factor to convert to V/m
    factor = 1/(4*np.pi*scipy.constants.epsilon_0)
 
    field = {'deltas':deltas}
    for component in components:
        # Green gunction
        green_mesh = igf_mesh3(rho_mesh.shape, deltas, gamma=gamma, offset=offset, component=component)

        # Convolution of double-sized arrays
        field_mesh = ifft(crho*fft(green_mesh))
        # The result is in a shifted location in the output array
        field[component] = factor*np.real(field_mesh[nx-1:2*nx-1,ny-1:2*ny-1,nx-1:2*nz-1])
        
    return field
示例#10
0
 def test_ihfftn(self):
     x = random((30, 20, 10))
     expect = fft.ifftn(x)[:, :, :6]
     assert_array_almost_equal(expect, fft.ihfftn(x))
     assert_array_almost_equal(expect, fft.ihfftn(x, norm="backward"))
     assert_array_almost_equal(expect * np.sqrt(30 * 20 * 10),
                               fft.ihfftn(x, norm="ortho"))
     assert_array_almost_equal(expect * (30 * 20 * 10),
                               fft.ihfftn(x, norm="forward"))
示例#11
0
def fft_wfc_G2R_old(wfc, igwx, gamma_only, mill, nr1, nr2, nr3, omega):
  wfcg = np.zeros((nr1,nr2,nr3), dtype=complex)
  
  for ig in range(igwx):
    wfcg[mill[0,ig],mill[1,ig],mill[2,ig]] = wfc[ig]
    if gamma_only:
      wfcg[-mill[0,ig],-mill[1,ig],-mill[2,ig]] = np.conj(wfc[ig])
      
  wfcr = FFT.ifftn(wfcg) * nr1 * nr2 * nr3 / np.sqrt(omega)
  return wfcr
def test_real_input(dtype):
    reference_image = camera().astype(dtype, copy=False)
    subpixel_shift = (-2.4, 1.32)
    shifted_image = fourier_shift(fft.fftn(reference_image), subpixel_shift)
    shifted_image = fft.ifftn(shifted_image).real.astype(dtype, copy=False)

    # subpixel precision
    result, error, diffphase = phase_cross_correlation(reference_image,
                                                       shifted_image,
                                                       upsample_factor=100)
    assert result.dtype == _supported_float_type(dtype)
    assert_allclose(result[:2], -np.array(subpixel_shift), atol=0.05)
示例#13
0
    def __call__(self, data):
        """Apply the filter to the given data.

        Parameters
        ----------
        data : (M,N) ndarray

        """
        check_nD(data, 2, 'data')
        F, G = self._prepare(data)
        out = fft.ifftn(F * G)
        out = np.abs(_centre(out, data.shape))
        return out
示例#14
0
def fft_wfc_G2R(wfc, gkspace, nr1, nr2, nr3, omega):
  igwx = gkspace['igwx']
  gamma_only = gkspace['gamma_only']
  mill = gkspace['mill']
  wfcg = np.zeros((nr1,nr2,nr3), dtype=complex)
  
  for ig in range(igwx):
    wfcg[mill[0,ig],mill[1,ig],mill[2,ig]] = wfc[ig]
    if gamma_only:
      wfcg[-mill[0,ig],-mill[1,ig],-mill[2,ig]] = np.conj(wfc[ig])
      
  wfcr = FFT.ifftn(wfcg) * nr1 * nr2 * nr3 / np.sqrt(omega)
  return wfcr
示例#15
0
def scale_image_2d(image, factor):
    """Scales up the image by the scaling factor. No cropping is done.
    Input:
    image
    factor"""
    size_x = image.shape[0]
    size_y = image.shape[1]
    center_x = size_x // 2
    center_y = size_y // 2
    window_x = int(size_x // factor)
    window_y = int(size_y // factor)
    image_ft = _fft.fft2(
        image[center_x - window_x // 2:center_x + window_x // 2,
              center_y - window_y // 2:center_y + window_y // 2])
    image_scaled = abs(_fft.ifftn(_fft.fftshift(image_ft), [size_x, size_y]))
    return image_scaled
示例#16
0
def elser_particle_nd(array_shape,
                      feature_size,
                      mask=None,
                      return_blured=True):
    """Return a binary contrast particle of arbitrary dimensionality and shape.
    Feature size is given in pixels. If no mask is provided the paritlce will
    be spherical."""
    radius = tools.radial_distance(array_shape)
    if mask is None:
        particle_size = min(array_shape) - 2
        mask = radius < particle_size / 2.
    elif mask.shape != array_shape:
        raise ValueError("array_shape and mask.shape are different "
                         f"({array_shape} != {mask.shape})")
    coordinates = [
        _numpy.arange(this_shape) - this_shape / 2 + 0.5
        for this_shape in array_shape
    ]
    scaling = float(feature_size)**2 / float(len(coordinates[0]))**2
    component_exp = [
        _numpy.exp(-this_coordinate**2 * scaling)
        for this_coordinate in coordinates
    ]
    lp_kernel = _numpy.ones(array_shape)
    for index, this_exp in enumerate(component_exp):
        this_slice = [_numpy.newaxis] * len(array_shape)
        this_slice[index] = slice(None)
        this_slice = tuple(this_slice)
        lp_kernel *= this_exp[this_slice]
    lp_kernel = _fft.fftshift(lp_kernel)

    particle = _numpy.random.random(array_shape)
    for _ in range(4):
        particle_average = _numpy.median(particle[mask])
        particle[particle > particle_average] = 1.
        particle[particle <= particle_average] = 0.
        particle[~mask] = 0.
        particle_ft = _fft.fftn(particle)
        particle_ft *= lp_kernel
        particle[:] = abs(_fft.ifftn(particle_ft))

    if not return_blured:
        particle_average = _numpy.median(particle[mask])
        particle[particle > particle_average] = 1.
        particle[particle <= particle_average] = 0.
    return particle
示例#17
0
def random_channel(n, rand, fpower=2.0):
    freq = fftn(rand.rand(n, n))

    fx = fftfreq(n)[:, None]
    fy = fftfreq(n)[None, :]

    # combine as l2 norm of freq
    f = (fx**2 + fy**2)**0.5

    i = f > 0
    freq[i] /= f[i]**fpower
    freq[0, 0] = 0.0

    data = np.real(ifftn(freq))
    data -= data.min()
    data /= data.max()
    return data
示例#18
0
def fftconvolve3(rho, *greens):
    """
    Efficiently perform a 3D convolution of a charge density rho and multiple Green functions. 
    
    Parameters
    ----------
    
    rho : np.array (3D)
        Charge mesh
        
    *greens : np.arrays (3D)
        Charge meshes for the Green functions, which should be twice the size of rho    
        
        
    Returns
    -------
    
    fields : tuple of np.arrays with the same shape as rho. 
    
    """

    # FFT Configuration
    fft = lambda x: sp_fft.fftn(x, overwrite_x=True)
    ifft = lambda x: sp_fft.ifftn(x, overwrite_x=True)

    # Place rho in double-sized array. Should match the shape of green
    nx, ny, nz = rho.shape
    crho = np.zeros((2 * nx, 2 * ny, 2 * nz))
    crho[0:nx, 0:ny, 0:nz] = rho[0:nx, 0:ny, 0:nz]

    # FFT
    crho = fft(crho)

    results = []
    for green in greens:
        assert crho.shape == green.shape, f'Green array shape {green.shape} should be twice rho shape {rho.shape}'
        result = ifft(crho * fft(green))
        # Extract the result
        result = np.real(result[nx - 1:2 * nx - 1, ny - 1:2 * ny - 1,
                                nz - 1:2 * nz - 1])
        results.append(result)

    return tuple(results)
示例#19
0
def gaussian_blur_nonperiodic(array, sigma):
    """Only 1d at this point"""
    small_size = len(array)
    pad_size = int(sigma * 10)
    large_size = small_size + 2 * pad_size
    large_array = _numpy.zeros(large_size)
    large_array[pad_size:(small_size + pad_size)] = array
    large_array[:pad_size] = array[0]
    large_array[(small_size + pad_size):] = array[-1]

    x_array = _numpy.arange(-large_size // 2, large_size // 2)

    kernel_ft = _numpy.exp(-2. * sigma**2 * _numpy.pi**2 *
                           (x_array / large_size)**2)
    kernel_ft = ((large_size / _numpy.sqrt(2. * _numpy.pi) / sigma) *
                 _fft.fftshift(kernel_ft))

    image_ft = _fft.fftn(large_array)
    image_ft *= kernel_ft
    blured_large_array = _fft.ifftn(image_ft)
    return blured_large_array[pad_size:-pad_size]
示例#20
0
def wiener(data, impulse_response=None, filter_params={}, K=0.25,
           predefined_filter=None):
    """Minimum Mean Square Error (Wiener) inverse filter.

    Parameters
    ----------
    data : (M,N) ndarray
        Input data.
    K : float or (M,N) ndarray
        Ratio between power spectrum of noise and undegraded
        image.
    impulse_response : callable `f(r, c, **filter_params)`
        Impulse response of the filter.  See LPIFilter2D.__init__.
    filter_params : dict
        Additional keyword parameters to the impulse_response function.

    Other Parameters
    ----------------
    predefined_filter : LPIFilter2D
        If you need to apply the same filter multiple times over different
        images, construct the LPIFilter2D and specify it here.

    """
    check_nD(data, 2, 'data')

    if not isinstance(K, float):
        check_nD(K, 2, 'K')

    if predefined_filter is None:
        filt = LPIFilter2D(impulse_response, **filter_params)
    else:
        filt = predefined_filter

    F, G = filt._prepare(data)
    _min_limit(F, val=np.finfo(F.real.dtype).eps)

    H_mag_sqr = np.abs(F) ** 2
    F = 1 / F * H_mag_sqr / (H_mag_sqr + K)

    return _centre(np.abs(fft.ifftshift(fft.ifftn(G * F))), data.shape)
示例#21
0
def scale_image_3d(image, factor):
    """Scales up the image by the scaling factor.
    Input:
    image
    factor"""
    size_x = image.shape[0]
    size_y = image.shape[1]
    size_z = image.shape[2]
    center_x = size_x // 2
    center_y = size_y // 2
    center_z = size_z // 2
    window_x = int(size_x // factor)
    window_y = int(size_y // factor)
    window_z = int(size_z // factor)
    image_ft = _fft.fftn(
        image[center_x - window_x // 2:center_x + window_x // 2,
              center_y - window_y // 2:center_y + window_y // 2,
              center_z - window_z // 2:center_z + window_z // 2],
        [size_x, size_y, size_z])
    image_scaled = abs(
        _fft.ifftn(_fft.fftshift(image_ft), [size_x, size_y, size_z]))
    return image_scaled
示例#22
0
def elser_particle(array_size,
                   particle_size,
                   feature_size,
                   return_blured=True):
    """Return a binary contrast particle. 'particle_size' and 'feature_size'
    should both be given in pixels."""
    if particle_size > array_size - 2:
        raise ValueError("Particle size must be <= array_size is "
                         f"({particle_size} > {array_size}-2)")

    x_coordinates = _numpy.arange(array_size) - array_size / 2. + 0.5
    y_coordinates = _numpy.arange(array_size) - array_size / 2. + 0.5
    z_coordinates = _numpy.arange(array_size) - array_size / 2. + 0.5
    radius = _numpy.sqrt(x_coordinates[_numpy.newaxis, _numpy.newaxis, :]**2 +
                         y_coordinates[_numpy.newaxis, :, _numpy.newaxis]**2 +
                         z_coordinates[:, _numpy.newaxis, _numpy.newaxis]**2)
    particle_mask = radius > particle_size / 2.
    kernel_scaling = float(feature_size)**2 / float(array_size)**2
    lp_kernel = _fft.fftshift(_numpy.exp(-radius**2 * kernel_scaling))

    particle = _numpy.random.random((array_size, ) * 3)

    for _ in range(4):
        # binary constrast
        particle_average = _numpy.median(particle[~particle_mask])
        particle[particle > particle_average] = 1.
        particle[particle <= particle_average] = 0.
        particle[particle_mask] = 0.
        # smoothen
        particle_ft = _fft.fftn(particle)
        particle_ft *= lp_kernel
        particle[:, :] = abs(_fft.ifftn(particle_ft))

    if not return_blured:
        particle_average = _numpy.median(particle[~particle_mask])
        particle[particle > particle_average] = 1.
        particle[particle <= particle_average] = 0.

    return particle
示例#23
0
def inverse(data, impulse_response=None, filter_params={}, max_gain=2,
            predefined_filter=None):
    """Apply the filter in reverse to the given data.

    Parameters
    ----------
    data : (M,N) ndarray
        Input data.
    impulse_response : callable `f(r, c, **filter_params)`
        Impulse response of the filter.  See LPIFilter2D.__init__.
    filter_params : dict
        Additional keyword parameters to the impulse_response function.
    max_gain : float
        Limit the filter gain.  Often, the filter contains zeros, which would
        cause the inverse filter to have infinite gain.  High gain causes
        amplification of artefacts, so a conservative limit is recommended.

    Other Parameters
    ----------------
    predefined_filter : LPIFilter2D
        If you need to apply the same filter multiple times over different
        images, construct the LPIFilter2D and specify it here.

    """
    check_nD(data, 2, 'data')
    if predefined_filter is None:
        filt = LPIFilter2D(impulse_response, **filter_params)
    else:
        filt = predefined_filter

    F, G = filt._prepare(data)
    _min_limit(F, val=np.finfo(F.real.dtype).eps)

    F = 1 / F
    mask = np.abs(F) > max_gain
    F[mask] = np.sign(F[mask]) * max_gain

    return _centre(np.abs(fft.ifftshift(fft.ifftn(G * F))), data.shape)
示例#24
0
# https://docs.scipy.org/doc/scipy/reference/tutorial/fft.html
import numpy as np
from scipy.fft import ifftn
import matplotlib.pyplot as plt
import matplotlib.cm as cm

N = 30
f, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2,
                                                     3,
                                                     sharex='col',
                                                     sharey='row')
xf = np.zeros((N, N))
xf[0, 5] = 1
xf[0, N - 5] = 1
Z = ifftn(xf)
ax1.imshow(xf, cmap=cm.Reds)
ax4.imshow(np.real(Z), cmap=cm.gray)
xf = np.zeros((N, N))
xf[5, 0] = 1
xf[N - 5, 0] = 1
Z = ifftn(xf)
ax2.imshow(xf, cmap=cm.Reds)
ax5.imshow(np.real(Z), cmap=cm.gray)
xf = np.zeros((N, N))
xf[5, 10] = 1
xf[N - 5, N - 10] = 1
Z = ifftn(xf)
ax3.imshow(xf, cmap=cm.Reds)
ax6.imshow(np.real(Z), cmap=cm.gray)
plt.show()
示例#25
0
# xf[N-3, 0] = 1
# Z = ifftn(xf)
# ax2.imshow(xf, cmap=cm.Reds)
# ax5.imshow(np.real(Z), cmap=cm.gray)
# xf = np.zeros((N, N))
# xf[5, 10] = 1
# xf[N-5, N-10] = 1
# Z = ifftn(xf)
# ax3.imshow(xf, cmap=cm.Reds)
# ax6.imshow(np.real(Z), cmap=cm.gray)
# plt.show()
plt.figure()
x = np.linspace(0, 2 * np.pi)
y = np.sin(x)
yy = fft(y)
ytest = ifftn(yy)
plt.plot(x, y, '--')
# plt.plot(x,yy)
# plt.plot(x,ytest)
y = 2 * np.sin(x)
yy = fft(y)
ytest = ifftn(yy / 2)
plt.plot(x, y)
plt.scatter(x, yy)
plt.scatter(x, ytest)

# import numpy as np
# import matplotlib.pyplot as plt

# def Rotation_2D(x,y,theta_degree):
#     theta = theta_degree*(np.pi/180)
示例#26
0
def phase_cross_correlation(reference_image, moving_image, *,
                            upsample_factor=1, space="real",
                            return_error=True, reference_mask=None,
                            moving_mask=None, overlap_ratio=0.3):
    """Efficient subpixel image translation registration by cross-correlation.

    This code gives the same precision as the FFT upsampled cross-correlation
    in a fraction of the computation time and with reduced memory requirements.
    It obtains an initial estimate of the cross-correlation peak by an FFT and
    then refines the shift estimation by upsampling the DFT only in a small
    neighborhood of that estimate by means of a matrix-multiply DFT.

    Parameters
    ----------
    reference_image : array
        Reference image.
    moving_image : array
        Image to register. Must be same dimensionality as
        ``reference_image``.
    upsample_factor : int, optional
        Upsampling factor. Images will be registered to within
        ``1 / upsample_factor`` of a pixel. For example
        ``upsample_factor == 20`` means the images will be registered
        within 1/20th of a pixel. Default is 1 (no upsampling).
        Not used if any of ``reference_mask`` or ``moving_mask`` is not None.
    space : string, one of "real" or "fourier", optional
        Defines how the algorithm interprets input data. "real" means
        data will be FFT'd to compute the correlation, while "fourier"
        data will bypass FFT of input data. Case insensitive. Not
        used if any of ``reference_mask`` or ``moving_mask`` is not
        None.
    return_error : bool, optional
        Returns error and phase difference if on, otherwise only
        shifts are returned. Has noeffect if any of ``reference_mask`` or
        ``moving_mask`` is not None. In this case only shifts is returned.
    reference_mask : ndarray
        Boolean mask for ``reference_image``. The mask should evaluate
        to ``True`` (or 1) on valid pixels. ``reference_mask`` should
        have the same shape as ``reference_image``.
    moving_mask : ndarray or None, optional
        Boolean mask for ``moving_image``. The mask should evaluate to ``True``
        (or 1) on valid pixels. ``moving_mask`` should have the same shape
        as ``moving_image``. If ``None``, ``reference_mask`` will be used.
    overlap_ratio : float, optional
        Minimum allowed overlap ratio between images. The correlation for
        translations corresponding with an overlap ratio lower than this
        threshold will be ignored. A lower `overlap_ratio` leads to smaller
        maximum translation, while a higher `overlap_ratio` leads to greater
        robustness against spurious matches due to small overlap between
        masked images. Used only if one of ``reference_mask`` or
        ``moving_mask`` is None.

    Returns
    -------
    shifts : ndarray
        Shift vector (in pixels) required to register ``moving_image``
        with ``reference_image``. Axis ordering is consistent with
        numpy (e.g. Z, Y, X)
    error : float
        Translation invariant normalized RMS error between
        ``reference_image`` and ``moving_image``.
    phasediff : float
        Global phase difference between the two images (should be
        zero if images are non-negative).

    References
    ----------
    .. [1] Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup,
           "Efficient subpixel image registration algorithms,"
           Optics Letters 33, 156-158 (2008). :DOI:`10.1364/OL.33.000156`
    .. [2] James R. Fienup, "Invariant error metrics for image reconstruction"
           Optics Letters 36, 8352-8357 (1997). :DOI:`10.1364/AO.36.008352`
    .. [3] Dirk Padfield. Masked Object Registration in the Fourier Domain.
           IEEE Transactions on Image Processing, vol. 21(5),
           pp. 2706-2718 (2012). :DOI:`10.1109/TIP.2011.2181402`
    .. [4] D. Padfield. "Masked FFT registration". In Proc. Computer Vision and
           Pattern Recognition, pp. 2918-2925 (2010).
           :DOI:`10.1109/CVPR.2010.5540032`

    """
    if (reference_mask is not None) or (moving_mask is not None):
        return _masked_phase_cross_correlation(reference_image, moving_image,
                                               reference_mask, moving_mask,
                                               overlap_ratio)

    # images must be the same shape
    if reference_image.shape != moving_image.shape:
        raise ValueError("images must be same shape")

    # assume complex data is already in Fourier space
    if space.lower() == 'fourier':
        src_freq = reference_image
        target_freq = moving_image
    # real data needs to be fft'd.
    elif space.lower() == 'real':
        src_freq = fftn(reference_image)
        target_freq = fftn(moving_image)
    else:
        raise ValueError('space argument must be "real" of "fourier"')

    # Whole-pixel shift - Compute cross-correlation by an IFFT
    shape = src_freq.shape
    image_product = src_freq * target_freq.conj()
    cross_correlation = ifftn(image_product)

    # Locate maximum
    maxima = np.unravel_index(np.argmax(np.abs(cross_correlation)),
                              cross_correlation.shape)
    midpoints = np.array([np.fix(axis_size / 2) for axis_size in shape])

    float_dtype = image_product.real.dtype

    shifts = np.stack(maxima).astype(float_dtype, copy=False)
    shifts[shifts > midpoints] -= np.array(shape)[shifts > midpoints]

    if upsample_factor == 1:
        if return_error:
            src_amp = np.sum(np.real(src_freq * src_freq.conj()))
            src_amp /= src_freq.size
            target_amp = np.sum(np.real(target_freq * target_freq.conj()))
            target_amp /= target_freq.size
            CCmax = cross_correlation[maxima]
    # If upsampling > 1, then refine estimate with matrix multiply DFT
    else:
        # Initial shift estimate in upsampled grid
        upsample_factor = np.array(upsample_factor, dtype=float_dtype)
        shifts = np.round(shifts * upsample_factor) / upsample_factor
        upsampled_region_size = np.ceil(upsample_factor * 1.5)
        # Center of output array at dftshift + 1
        dftshift = np.fix(upsampled_region_size / 2.0)
        # Matrix multiply DFT around the current shift estimate
        sample_region_offset = dftshift - shifts*upsample_factor
        cross_correlation = _upsampled_dft(image_product.conj(),
                                           upsampled_region_size,
                                           upsample_factor,
                                           sample_region_offset).conj()
        # Locate maximum and map back to original pixel grid
        maxima = np.unravel_index(np.argmax(np.abs(cross_correlation)),
                                  cross_correlation.shape)
        CCmax = cross_correlation[maxima]

        maxima = np.stack(maxima).astype(float_dtype, copy=False)
        maxima -= dftshift

        shifts += maxima / upsample_factor

        if return_error:
            src_amp = np.sum(np.real(src_freq * src_freq.conj()))
            target_amp = np.sum(np.real(target_freq * target_freq.conj()))

    # If its only one row or column the shift along that dimension has no
    # effect. We set to zero.
    for dim in range(src_freq.ndim):
        if shape[dim] == 1:
            shifts[dim] = 0

    if return_error:
        # Redirect user to masked_phase_cross_correlation if NaNs are observed
        if np.isnan(CCmax) or np.isnan(src_amp) or np.isnan(target_amp):
            raise ValueError(
                "NaN values found, please remove NaNs from your "
                "input data or use the `reference_mask`/`moving_mask` "
                "keywords, eg: "
                "phase_cross_correlation(reference_image, moving_image, "
                "reference_mask=~np.isnan(reference_image), "
                "moving_mask=~np.isnan(moving_image))")

        return shifts, _compute_error(CCmax, src_amp, target_amp),\
            _compute_phasediff(CCmax)
    else:
        return shifts
示例#27
0
 def test_ihfftn(self):
     x = random((30, 20, 10))
     assert_array_almost_equal(fft.ifftn(x)[:, :, :6], fft.ihfftn(x))
     assert_array_almost_equal(fft.ihfftn(x) * np.sqrt(30 * 20 * 10),
                               fft.ihfftn(x, norm="ortho"))
示例#28
0
    def potential(self, i, sobo=False, sphere=False):
        """Get the potential between the electron and nucleus (Using Cartesian Coordinates, NO gaussian product rule, fft).

        Parameters
        ----------
        i : int
            The atomic center index.
        sobo : Bool
            If True, use sobolev preconditioning. If False, no sobolev preconditioning.

        Returns
        -------
        numpy array
            The potential matrix.
        """
        if sphere is False:

            x_3d, y_3d, z_3d = np.meshgrid(self.r, self.r, self.r)
            V_mat = np.zeros((self.num_of_basis, self.num_of_basis),
                             dtype=complex)
            coulomb_e_p = 1 / np.sqrt(
                (x_3d - self.atomic_position[i - 1][0])**2 +
                (y_3d - self.atomic_position[i - 1][1])**2 +
                (z_3d - self.atomic_position[i - 1][2])**2)

            if sobo is True:
                spacing = (self.max_r - self.min_r) / (self.num_of_div - 1)
                r_freq = spyfft.fftfreq(self.num_of_div, spacing)
                x_freq_3d, y_freq_3d, z_freq_3d, = np.meshgrid(
                    r_freq, r_freq, r_freq)
                precond_in_k = (1 + (0.5) * ((2 * np.pi)**2) *
                                (x_freq_3d**2 + y_freq_3d**2 + z_freq_3d**2))

            for mu in range(self.num_of_basis):
                for nu in range(self.num_of_basis):
                    potential_mu_nu_temp = np.zeros(
                        (self.num_of_div, self.num_of_div, self.num_of_div),
                        dtype=complex)
                    for p in range(self.num_of_gauss):
                        for q in range(self.num_of_gauss):
                            int_func_1 = self.GF(
                                self.a_overlap_mat[p][mu],
                                np.sqrt(
                                    (x_3d - self.atomic_position[mu][0])**2 +
                                    (y_3d - self.atomic_position[mu][1])**2 +
                                    (z_3d - self.atomic_position[mu][2])**2))
                            int_func_2 = self.GF(
                                self.a_overlap_mat[q][nu],
                                np.sqrt(
                                    (x_3d - self.atomic_position[nu][0])**2 +
                                    (y_3d - self.atomic_position[nu][1])**2 +
                                    (z_3d - self.atomic_position[nu][2])**2))

                            if sobo is False:
                                integrate_func = np.multiply(
                                    int_func_1,
                                    np.multiply(coulomb_e_p, int_func_2))
                            elif sobo is True:
                                int_func_2_fft = spyfft.ifftn(
                                    spyfft.fftn(
                                        np.multiply(coulomb_e_p, int_func_2)) /
                                    precond_in_k)
                                integrate_func = np.real(
                                    np.multiply(int_func_1, int_func_2_fft))

                            potential_mu_nu_temp -= self.d_overlap_mat[p][
                                mu] * self.d_overlap_mat[q][nu] * (
                                    2 * self.a_overlap_mat[p][mu] / m.pi
                                )**(3 / 4) * (2 * self.a_overlap_mat[q][nu] /
                                              m.pi)**(3 / 4) * integrate_func
                            # print(potential_mu_nu_temp)
                    # print("Potential", potential_mu_nu_temp)
                    V_mat[mu][nu] += spyint.simpson(
                        spyint.simpson(
                            spyint.simpson(potential_mu_nu_temp, self.r),
                            self.r), self.r)
            return np.real(V_mat)

        elif sphere is True:
            theta = np.linspace(0, m.pi, 50)
            radius = np.linspace(0, self.max_r, self.num_of_div)
            r_2d, theta_2d = np.meshgrid(radius, theta)
            V_mat = np.zeros((self.num_of_basis, self.num_of_basis),
                             dtype=complex)
            min_r = 0
            max_r = 100
            for mu in range(self.num_of_basis):
                for nu in range(self.num_of_basis):
                    overlap_mu_nu_temp = 0
                    for p in range(self.num_of_gauss):
                        for q in range(self.num_of_gauss):
                            new_a, new_R, new_K = self.two_GF(
                                self.a_overlap_mat[p][mu],
                                self.a_overlap_mat[q][nu],
                                self.atomic_position[mu],
                                self.atomic_position[nu])
                            new_RR = new_R - self.atomic_position[0]
                            new_RR_abs = m.sqrt(np.inner(new_RR, new_RR))
                            # Please use a function instead of a lambda function so that debugging is easier.
                            int_func = lambda t, r: (2 * m.pi * (r)**2) * (
                                m.sin(t) / (m.sqrt(r**2 + new_RR_abs**2 - 2 * r
                                                   * new_RR_abs * m.cos(t))
                                            )) * new_K * self.GF(new_a, r)
                            overlap_mu_nu_temp += self.d_overlap_mat[p][
                                mu] * self.d_overlap_mat[q][nu] * (
                                    2 * new_a /
                                    m.pi)**(3 / 4) * spyint.dblquad(
                                        int_func, min_r, max_r, 0, m.pi)[0]
                    V_mat[mu][nu] += overlap_mu_nu_temp
            return V_mat
示例#29
0
 def itransformation_3d(group):
     # return pywt.idwtn(group, 'bior1.5')
     return ifftn(group)
def _ifft(im_fft):
    """shifted ifft 2D
    """
    return ifftshift(ifftn(ifftshift(im_fft)))