Exemplo n.º 1
0
def simcheck(data, nphases):
    norients = data.shape[0]//nphases       # need to use integer divide

    # check user input before proceeding
    assert nphases*norients == data.shape[0]

    newshape = norients, nphases, data.shape[-2], data.shape[-1]

    # FT data only along spatial dimensions
    ft_data = fftshift(
                fftn(ifftshift(
                    data, axes=(1, 2)),
                 axes=(1, 2)),
            axes=(1, 2))
    # average only along phase, **not** orientation
    # This should be the equivalent of the FT of the average image per each
    # phase (i.e it should be symmetric as the phases will have averaged out)
    ft_data_avg = ft_data.reshape(newshape).mean(1)
    # Do the same, but take the absolute value before averaging, in this case
    # the signal should add up because the phase has been removed
    ft_data_avg_abs = np.abs(ft_data).reshape(newshape).mean(1)
    # Take the difference of the average power and the power of the average
    ft_data_diff = ft_data_avg_abs-abs(ft_data_avg)

    return ft_data_diff, ft_data_avg_abs, ft_data_avg
Exemplo n.º 2
0
def get_der_dLv(A, v, a, b):
    # A = (a * delta + bE)
    # v = Km, m = Lv
    # L = A^(-2)
    G = np.zeros(v.shape, dtype=np.complex128)
    # delta = laplacian
    delta = get_delta(A, a, b)
    # turn v into furier space
    for i in range(len(v)):
        G[i] = fftn(v[i])
    # in fourier space we get a simple multiplication and get delta*v, delta^2*v(like Lv)
    delta_v = G * delta
    delta2_v = G * delta**2

    # get back from fourier space
    Dv = np.zeros_like(G)
    D2v = np.zeros_like(G)
    for i in range(len(v)):
        Dv[i] = np.real(ifftn(delta_v[i]))
        D2v[i] = np.real(ifftn(delta2_v[i]))

    # return derivative of Lv
    # dLv/da = ((a*delta + bE)^2 v)/da = 2(a*delta +bE)*delta*v = 2(a*delta^2 + b*delta)*v
    # dLv/db = 2(a*delta + bE) * E * v = 2(a*delta + bE)v
    del delta2_v, delta_v, G
    return np.real(2 * a * D2v + 2 * b * Dv), np.real(2 * a * Dv + 2 * b * v)
Exemplo n.º 3
0
def Lv(A, v):
    G = np.zeros(v.shape, dtype=np.complex128)
    for i in range(len(v)):
        G[i] = fftn(v[i])
    Lv = A * G
    Dv = np.zeros_like(G)

    for i in range(len(v)):
        Dv[i] = np.real(ifftn(Lv[i]))

    return np.real(Dv)
Exemplo n.º 4
0
    def __call__(self, momentum):
        if (hasattr(self, 'operator')
                and momentum.shape[1:] == self.operator.shape):
            G = np.zeros(momentum.shape, dtype=np.complex128)
            for i in xrange(len(momentum)):
                G[i] = fftn(momentum[i])

            F = G * self.operator

            vector_field = np.zeros_like(momentum)
            for i in xrange(len(momentum)):
                vector_field[i] = np.real(ifftn(F[i]))

            return vector_field
        else:
            self.set_operator(momentum.shape[1:])
            return self.__call__(momentum)
Exemplo n.º 5
0
 def fftx(ar):
     return fftn(ar,axes=[0,1])
Exemplo n.º 6
0
def norm_xcorr(t,a,method=None,trim=True,do_ssd=False):
	"""
	Fast normalized cross-correlation for n-dimensional arrays

	Inputs:
	----------------
		t 	The template. Must have at least 2 elements, which 
			cannot all be equal.

		a 	The search space. Its dimensionality must match that of 
			the template.

		method 	The convolution method to use when computing the 
			cross-correlation. Can be either 'direct', 'fourier' or
			None. If method == None (default), the convolution time 
			is estimated for both methods and the best one is chosen
			for the given input array sizes.

		trim 	If True (default), the output array is trimmed down to  
			the size of the search space. Otherwise, its size will  
			be (f.shape[dd] + t.shape[dd] -1) for dimension dd.

		do_ssd 	If True, the sum of squared differences between the 
			template and the search image will also be calculated.
			It is very efficient to calculate normalized 
			cross-correlation and the SSD simultaneously, since they
			require many of the same quantities.

	Output:
	----------------
		nxcorr 	An array of cross-correlation coefficients, which may  
			vary from -1.0 to 1.0.
		[ssd] 	[Returned if do_ssd == True. See fast_ssd for details.]

	Wherever the search space has zero  variance under the template,
	normalized  cross-correlation is undefined. In such regions, the
	correlation coefficients are set to zero.

	References:
		Hermosillo et al 2002: Variational Methods for Multimodal Image
		Matching, International Journal of Computer Vision 50(3),
		329-343, 2002
		<http://www.springerlink.com/content/u4007p8871w10645/>

		Lewis 1995: Fast Template Matching, Vision Interface, 
		p.120-123, 1995
		<http://www.idiom.com/~zilla/Papers/nvisionInterface/nip.html>

		<http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation>

	Alistair Muldal
	Department of Pharmacology
	University of Oxford
	<*****@*****.**>

	Sept 2012

	"""

	if t.size < 2:
		raise Exception('Invalid template')
	if t.size > a.size:
		raise Exception('The input array must be smaller than the template')

	std_t,mean_t = np.std(t),np.mean(t)

	if std_t == 0:
		raise Exception('The values of the template must not all be equal')

	t = np.float64(t)
	a = np.float64(a)

	# output dimensions of xcorr need to match those of local_sum
	outdims = np.array([a.shape[dd]+t.shape[dd]-1 for dd in xrange(a.ndim)])

	# would it be quicker to convolve in the spatial or frequency domain? NB
	# this is not very accurate since the speed of the Fourier transform
	# varies quite a lot with the output dimensions (e.g. 2-radix case)
	if method == None:
		spatialtime, ffttime = get_times(t,a,outdims)
		if spatialtime < ffttime:
			method = 'spatial'
		else:
			method = 'fourier'

	if method == 'fourier':
		# # in many cases, padding the dimensions to a power of 2
		# # *dramatically* improves the speed of the Fourier transforms
		# # since it allows using radix-2 FFTs
		# fftshape = [nextpow2(ss) for ss in a.shape]

		# Fourier transform of the input array and the inverted template

		# af = fftn(a,shape=fftshape)
		# tf = fftn(ndflip(t),shape=fftshape)

		af = fftn(a,shape=outdims)
		tf = fftn(ndflip(t),shape=outdims)

		# 'non-normalized' cross-correlation
		xcorr = np.real(ifftn(tf*af))

	else:
		xcorr = convolve(a,t,mode='constant',cval=0)

	# local linear and quadratic sums of input array in the region of the
	# template
	ls_a = local_sum(a,t.shape)
	ls2_a = local_sum(a**2,t.shape)

	# now we need to make sure xcorr is the same size as ls_a
	xcorr = procrustes(xcorr,ls_a.shape,side='both')

	# local standard deviation of the input array
	ls_diff = ls2_a - (ls_a**2)/t.size
	ls_diff = np.where(ls_diff < 0,0,ls_diff)
	sigma_a = np.sqrt(ls_diff)

	# standard deviation of the template
	sigma_t = np.sqrt(t.size-1.)*std_t

	# denominator: product of standard deviations
	denom = sigma_t*sigma_a

	# numerator: local mean corrected cross-correlation
	numer = (xcorr - ls_a*mean_t)

	# sigma_t cannot be zero, so wherever the denominator is zero, this must
	# be because sigma_a is zero (and therefore the normalized cross-
	# correlation is undefined), so set nxcorr to zero in these regions
	tol = np.sqrt(np.finfo(denom.dtype).eps)
	nxcorr = np.where(denom < tol,0,numer/denom)

	# if any of the coefficients are outside the range [-1 1], they will be
	# unstable to small variance in a or t, so set them to zero to reflect
	# the undefined 0/0 condition
	nxcorr = np.where(np.abs(nxcorr-1.) > np.sqrt(np.finfo(nxcorr.dtype).eps),nxcorr,0)

	# calculate the SSD if requested
	if do_ssd:
		# quadratic sum of the template
		tsum2 = np.sum(t**2.)

		# SSD between template and image
		ssd = ls2_a + tsum2 - 2.*xcorr

		# normalise to between 0 and 1
		ssd -= ssd.min()
		ssd /= ssd.max()

		if trim:
			nxcorr = procrustes(nxcorr,a.shape,side='both')
			ssd = procrustes(ssd,a.shape,side='both')
		return nxcorr,ssd

	else:
		if trim:
			nxcorr = procrustes(nxcorr,a.shape,side='both')
		return nxcorr
Exemplo n.º 7
0
def benchmark(t,a,outdims,maxtime=60):
	import resource

	# benchmark spatial convolutions
	# ---------------------------------
	convreps = 0
	tic = resource.getrusage(resource.RUSAGE_SELF).ru_utime
	toc = tic
	while (toc-tic) < maxtime:
		convolve(a,t,mode='constant',cval=0)
		# xcorr = convolve(a,t,mode='full')
		convreps += 1
		toc = resource.getrusage(resource.RUSAGE_SELF).ru_utime
	convtime = (toc-tic)/convreps

	# convtime == k(N1+N2)
	N = t.size*a.size
	k_conv = convtime/N

	# benchmark 1D Fourier transforms
	# ---------------------------------
	veclist = [np.random.randn(ss) for ss in outdims]
	fft1times = []
	fftreps = []
	for vec in veclist:
		reps = 0
		tic = resource.getrusage(resource.RUSAGE_SELF).ru_utime
		toc = tic
		while (toc-tic) < maxtime:
			fftn(vec)
			toc = resource.getrusage(resource.RUSAGE_SELF).ru_utime
			reps += 1
		fft1times.append((toc-tic)/reps)
		fftreps.append(reps)
	fft1times = np.asarray(fft1times)

	# fft1_time == k*N*log(N)
	N = np.asarray([vec.size for vec in veclist])
	k_fft = np.mean(fft1times/(N*np.log(N)))

	# # benchmark ND Fourier transforms
	# # ---------------------------------
	# arraylist = [t,a]
	# fftntimes = []
	# fftreps = []
	# for array in arraylist:
	# 	reps = 0
	# 	tic = resource.getrusage(resource.RUSAGE_SELF).ru_utime
	# 	toc = tic
	# 	while (toc-tic) < maxtime:
	# 		fftn(array,shape=a.shape)
	# 		reps += 1
	# 		toc = resource.getrusage(resource.RUSAGE_SELF).ru_utime
	# 	fftntimes.append((toc-tic)/reps)
	# 	fftreps.append(reps)
	# fftntimes = np.asarray(fftntimes)

	# # fftn_time == k*prod(dimensions)*log(prod(dimensions)) for an M-dimensional array
	# nlogn = np.array([aa.size*np.log(aa.size) for aa in arraylist])
	# k_fft = np.mean(fftntimes/nlogn)

	return k_conv,k_fft,convreps,fftreps
Exemplo n.º 8
0
def fast_ssd(t,a,method=None,trim=True):
	"""

	Fast sum of squared differences (SSD block matching) for n-dimensional
	arrays

	Inputs:
	----------------
		t 	The template. Must have at least 2 elements, which 
			cannot all be equal.

		a 	The search space. Its dimensionality must match that of 
			the template.

		method 	The convolution method to use when computing the 
			cross-correlation. Can be either 'direct', 'fourier' or
			None. If method == None (default), the convolution time 
			is estimated for both methods and the best one is chosen
			for the given input array sizes.

		trim 	If True (default), the output array is trimmed down to  
			the size of the search space. Otherwise, its size will  
			be (f.shape[dd] + t.shape[dd] -1) for dimension dd.

	Output:
	----------------
		ssd 	An array containing the sum of squared differences 
			between the image and the template, with the values
			normalized in the range -1.0 to 1.0.

	Wherever the search space has zero  variance under the template,
	normalized  cross-correlation is undefined. In such regions, the
	correlation coefficients are set to zero.

	References:
		Hermosillo et al 2002: Variational Methods for Multimodal Image
		Matching, International Journal of Computer Vision 50(3),
		329-343, 2002
		<http://www.springerlink.com/content/u4007p8871w10645/>

		Lewis 1995: Fast Template Matching, Vision Interface, 
		p.120-123, 1995
		<http://www.idiom.com/~zilla/Papers/nvisionInterface/nip.html>


	Alistair Muldal
	Department of Pharmacology
	University of Oxford
	<*****@*****.**>

	Sept 2012

	"""

	if t.size < 2:
		raise Exception('Invalid template')
	if t.size > a.size:
		raise Exception('The input array must be smaller than the template')

	std_t,mean_t = np.std(t),np.mean(t)

	if std_t == 0:
		raise Exception('The values of the template must not all be equal')

	# output dimensions of xcorr need to match those of local_sum
	outdims = np.array([a.shape[dd]+t.shape[dd]-1 for dd in xrange(a.ndim)])

	# would it be quicker to convolve in the spatial or frequency domain? NB
	# this is not very accurate since the speed of the Fourier transform
	# varies quite a lot with the output dimensions (e.g. 2-radix case)
	if method == None:
		spatialtime, ffttime = get_times(t,a,outdims)
		if spatialtime < ffttime:
			method = 'spatial'
		else:
			method = 'fourier'

	if method == 'fourier':
		# # in many cases, padding the dimensions to a power of 2
		# # *dramatically* improves the speed of the Fourier transforms
		# # since it allows using radix-2 FFTs
		# fftshape = [nextpow2(ss) for ss in a.shape]

		# Fourier transform of the input array and the inverted template

		# af = fftn(a,shape=fftshape)
		# tf = fftn(ndflip(t),shape=fftshape)

		af = fftn(a,shape=outdims)
		tf = fftn(ndflip(t),shape=outdims)

		# 'non-normalized' cross-correlation
		xcorr = np.real(ifftn(tf*af))

	else:
		xcorr = convolve(a,t,mode='constant',cval=0)

	# quadratic sum of the template
	tsum2 = np.sum(t**2.)

	# local quadratic sum of input array in the region of the template
	ls2_a = local_sum(a**2,t.shape)

	# now we need to make sure xcorr is the same size as ls2_a
	xcorr = procrustes(xcorr,ls2_a.shape,side='both')

	# SSD between template and image
	ssd = ls2_a + tsum2 - 2.*xcorr

	# normalise to between 0 and 1
	ssd -= ssd.min()
	ssd /= ssd.max()

	if trim:
		ssd = procrustes(ssd,a.shape,side='both')

	return ssd
Exemplo n.º 9
0
 def fftx(ar):
     return fftn(ar, axes=[0, 1])
Exemplo n.º 10
0
def make_wavelets(filename, order, nangles, nscales, sym):
    """ Make a wavelet transform from an HDF5 file
    """
    # Set wavelet type
    if sym:
        wav = dgauss.dgauss_nd_sym
    else:
        wav = dgauss.dgauss_nd

    # Get info from input signal
    with h5py.File(filename) as src:
        spacing = (
            abs(src['Longitude'][1] - src['Longitude'][0]),
            abs(src['Latitude'][1] - src['Latitude'][0]))
        nxs, nys, _ = src['Raster'].shape
        shape = (nxs, nys)

        # Generate axes for transform
        scales = dgauss.generate_scales(nscales, shape, spacing, order)
        angles = linspace(
            0, pi * (1 - 1 / nangles), nangles)
        axes = [
            (0, 'Angle', angles),
            (1, 'Scale', scales),
            (2, 'Longitude', src['Longitude'][...]),
            (3, 'Latitude', src['Latitude'][...]),
        ]

        # Remove NaNs and pad array...
        raster = src['Raster'][..., 0]
        mean = nanmean(nanmean(raster))
        raster[isnan(raster)] = mean
        pad_raster, pad_mask = pad_array(raster)
        pad_shape = pad_raster.shape
        fft_data = fftn(pad_raster)

        # Generate sink file
        sink_fname = os.path.splitext(filename)[0] \
                     + '_deriv_order{0}.hdf5'.format(order)
        with h5py.File(sink_fname) as sink:
            sink_shape = angles.shape + scales.shape + shape
            sink.require_dataset('Raster', shape=sink_shape, dtype=float64)

            # Attach dimension labels to raster, write to sink
            for idx, label, dim in axes:
                sink.require_dataset(name=label,
                                     shape=dim.shape,
                                     dtype=float64,
                                     exact=True,
                                     data=dim)
                sink['Raster'].dims.create_scale(dset=sink[label], name=label)
                sink['Raster'].dims[idx].attach_scale(sink[label])

            # Evaluate transforms
            progbar = pyprind.ProgBar(len(angles) * len(scales) + 1)
            freqs = fft_frequencies(pad_shape, spacing)
            for aidx, angle in enumerate(angles):
                rfreqs = rotate(freqs, (angle,))
                for sidx, scale in enumerate(scales):
                    item = 'Angle: {0:0.2f} deg, Scale: {1:0.2f} deg'.format(
                        angle * 180 / pi, scale)
                    progbar.update(item_id=item)
                    filtered = ifftn(
                        fft_data * wav(rfreqs, order=order, scale=scale))
                    sink['Raster'][aidx, sidx, ...] = filtered[pad_mask].real
Exemplo n.º 11
0
def make_wavelets(filename, order, nangles, nscales, sym):
    """ Make a wavelet transform from an HDF5 file
    """
    # Set wavelet type
    if sym:
        wav = dgauss.dgauss_nd_sym
    else:
        wav = dgauss.dgauss_nd

    # Get info from input signal
    with h5py.File(filename) as src:
        spacing = (abs(src['Longitude'][1] - src['Longitude'][0]),
                   abs(src['Latitude'][1] - src['Latitude'][0]))
        nxs, nys, _ = src['Raster'].shape
        shape = (nxs, nys)

        # Generate axes for transform
        scales = dgauss.generate_scales(nscales, shape, spacing, order)
        angles = linspace(0, pi * (1 - 1 / nangles), nangles)
        axes = [
            (0, 'Angle', angles),
            (1, 'Scale', scales),
            (2, 'Longitude', src['Longitude'][...]),
            (3, 'Latitude', src['Latitude'][...]),
        ]

        # Remove NaNs and pad array...
        raster = src['Raster'][..., 0]
        mean = nanmean(nanmean(raster))
        raster[isnan(raster)] = mean
        pad_raster, pad_mask = pad_array(raster)
        pad_shape = pad_raster.shape
        fft_data = fftn(pad_raster)

        # Generate sink file
        sink_fname = os.path.splitext(filename)[0] \
                     + '_deriv_order{0}.hdf5'.format(order)
        with h5py.File(sink_fname) as sink:
            sink_shape = angles.shape + scales.shape + shape
            sink.require_dataset('Raster', shape=sink_shape, dtype=float64)

            # Attach dimension labels to raster, write to sink
            for idx, label, dim in axes:
                sink.require_dataset(name=label,
                                     shape=dim.shape,
                                     dtype=float64,
                                     exact=True,
                                     data=dim)
                sink['Raster'].dims.create_scale(dset=sink[label], name=label)
                sink['Raster'].dims[idx].attach_scale(sink[label])

            # Evaluate transforms
            progbar = pyprind.ProgBar(len(angles) * len(scales) + 1)
            freqs = fft_frequencies(pad_shape, spacing)
            for aidx, angle in enumerate(angles):
                rfreqs = rotate(freqs, (angle, ))
                for sidx, scale in enumerate(scales):
                    item = 'Angle: {0:0.2f} deg, Scale: {1:0.2f} deg'.format(
                        angle * 180 / pi, scale)
                    progbar.update(item_id=item)
                    filtered = ifftn(fft_data *
                                     wav(rfreqs, order=order, scale=scale))
                    sink['Raster'][aidx, sidx, ...] = filtered[pad_mask].real
Exemplo n.º 12
0
def cfftn(data,axes):
    '''Centered fft'''
    return fftpack.ifftshift(fftpack.fftn(fftpack.fftshift(data,axes=axes)))
Exemplo n.º 13
0
def convolve_weighted_fft(in1, in2, mode="full", weighting="None", displayplots=False):
    """Convolve two N-dimensional arrays using FFT.

    Convolve `in1` and `in2` using the fast Fourier transform method, with
    the output size determined by the `mode` argument.
    This is generally much faster than `convolve` for large arrays (n > ~500),
    but can be slower when only a few output values are needed, and can only
    output float arrays (int or object array inputs will be cast to float).

    Parameters
    ----------
    in1 : array_like
        First input.
    in2 : array_like
        Second input. Should have the same number of dimensions as `in1`;
        if sizes of `in1` and `in2` are not equal then `in1` has to be the
        larger array.
    mode : str {'full', 'valid', 'same'}, optional
        A string indicating the size of the output:
        ``full``
           The output is the full discrete linear convolution
           of the inputs. (Default)
        ``valid``
           The output consists only of those elements that do not
           rely on the zero-padding.
        ``same``
           The output is the same size as `in1`, centered
           with respect to the 'full' output.

    Returns
    -------
    out : array
        An N-dimensional array containing a subset of the discrete linear
        convolution of `in1` with `in2`.
    """
    in1 = np.asarray(in1)
    in2 = np.asarray(in2)

    if np.isscalar(in1) and np.isscalar(in2):  # scalar inputs
        return in1 * in2
    elif not in1.ndim == in2.ndim:
        raise ValueError("in1 and in2 should have the same rank")
    elif in1.size == 0 or in2.size == 0:  # empty arrays
        return np.array([])

    s1 = np.array(in1.shape)
    s2 = np.array(in2.shape)
    complex_result = np.issubdtype(in1.dtype, complex) or np.issubdtype(in2.dtype, complex)
    size = s1 + s2 - 1

    if mode == "valid":
        _check_valid_mode_shapes(s1, s2)

    # Always use 2**n-sized FFT
    fsize = 2 ** np.ceil(np.log2(size)).astype(int)
    fslice = tuple([slice(0, int(sz)) for sz in size])
    if not complex_result:
        fft1 = rfftn(in1, fsize)
        fft2 = rfftn(in2, fsize)
        theorigmax = np.max(np.absolute(irfftn(gccproduct(fft1, fft2, "None"), fsize)[fslice]))
        ret = irfftn(gccproduct(fft1, fft2, weighting, displayplots=displayplots), fsize)[
            fslice
        ].copy()
        ret = irfftn(gccproduct(fft1, fft2, weighting, displayplots=displayplots), fsize)[
            fslice
        ].copy()
        ret = ret.real
        ret *= theorigmax / np.max(np.absolute(ret))
    else:
        fft1 = fftpack.fftn(in1, fsize)
        fft2 = fftpack.fftn(in2, fsize)
        theorigmax = np.max(np.absolute(fftpack.ifftn(gccproduct(fft1, fft2, "None"))[fslice]))
        ret = fftpack.ifftn(gccproduct(fft1, fft2, weighting, displayplots=displayplots))[
            fslice
        ].copy()
        ret *= theorigmax / np.max(np.absolute(ret))

    # scale to preserve the maximum

    if mode == "full":
        return ret
    elif mode == "same":
        return _centered(ret, s1)
    elif mode == "valid":
        return _centered(ret, s1 - s2 + 1)