Source code for piv.fft_correlator

import pyfftw
import numpy as np

from peak_detection import find_peak

[docs]class FFTCorrelator(object): """ An FFT Correlation Class for a PIV Evaluation of two frames It uses the `pyfftw <https://hgomersall.github.io/pyFFTW/>`_ library for performant FFT. This class is also responsible for calculating the Shift after the correlation. """ def __init__(self, window_a_size, window_b_size, scale_fft='default'): """ Initialize fftw objects for FFTs with the pyfftw library The necessary functions are loaded and memory allocated. :param window_a_size: size of the interrogation window :param window_b_size: size of the search window :param str scale_fft: if set to upscale, the padding will be upscaled """ max_fsize = max([window_a_size, window_b_size]) pad = self._set_padding(max_fsize, scale_fft) ffta_shape = (window_a_size, window_a_size) ffta_memory = pyfftw.empty_aligned(ffta_shape, dtype='float64') self._fa_fft = pyfftw.builders.rfft2(ffta_memory, pad) fftb_shape = (window_b_size, window_b_size) fftb_memory = pyfftw.empty_aligned(fftb_shape, dtype='float64') self._fb_fft = pyfftw.builders.rfft2(fftb_memory, pad) ifft_shape = (window_b_size, window_b_size//2 + 1) ifft_memory = pyfftw.empty_aligned(ifft_shape, dtype='complex128') self._ift_fft = pyfftw.builders.irfft2(ifft_memory, pad)
[docs] def _set_padding(self, windows_size, scale_fft): """Set zero padding size for FFTs""" if scale_fft == 'default': pad = 2*windows_size if scale_fft == 'upscale': pad = 2**np.ceil(np.log2(2*windows_size)) return (pad, pad)
[docs] def _evaluate_windows(self, window_a, window_b): """ Calculate the FFT of both windows, correlate and transform back. In order to decrease the error a mean subtraction is performed. To compensate for the indexing during the FFT a FFT Shift is performed. :param window_a: interrogation window :param window_b: search window :returns: correlation window """ fft_a = self._fa_fft(window_a - np.mean(window_a)) fft_b = self._fb_fft(window_b - np.mean(window_b)) fft_corr = fft_a*np.conj(fft_b) inv_fft = self._ift_fft(fft_corr) return np.fft.fftshift(inv_fft)
[docs] def get_displacement(self, window_a, window_b, subpixel_method='gaussian'): """ Compute the displacement out of correlation. First the correlation is performed and afterwards the shift is calculated. For the displacement calculation the function .. autofunction:: piv.peak_detection.find_peak is called with the subpixel_method passed on as parameter. If a padding was needed, it is removed from the calculated displacement. :param window_a: interrogation window :param window_b: search window :param str subpixel_method: method for peak finder :returns: shift in x and y direction as tuple """ correlation = self._evaluate_windows(window_a, window_b) xi, yi = find_peak(correlation, subpixel_method) cx, cy = correlation.shape corr_pad = (window_b.shape[0] - window_a.shape[0])/2. return (cx/2. - xi - corr_pad, cy/2. - yi - corr_pad)