Source code for pyflct.flct

import numpy as np

from .utils import column_row_of_two

try:
    from pyflct import _flct as _pyflct
except ImportError:
    _pyflct = None


__all__ = ["flct"]


[docs] def flct( image1, image2, deltat, deltas, sigma, order="row", quiet=False, biascor=False, thresh=0.0, absflag=False, skip=None, xoff=0, yoff=0, interp=False, kr=None, pc=False, latmin=0, latmax=0.2, ): """ Performs Fourier Local Correlation Tracking by calling the FLCT C library. .. note:: * In the references there are some dat files which can be used to test the FLCT code. The best method to read those dat files is the `pyflct.read_2_images` and `pyflct.read_3_images` as the arrays would automatically be read in row major format. * If you use the IDL IO routines to get the input arrays from ``dat`` files, the IDL routines always read the binary files in the column major, but both Python and C, on which these functions are written are row major so the order of the arrays have to be changed which can be done with the ``order`` keyword. This may lead to different values in both the cases. * If your input arrays are column major then pass the `order` parameter as `column` and it will automatically take care of the order change. But this can produce some changes in the values of the arrays. .. warning:: All the below limitations have been directly taken from the C source user manual without any modifications. The original user manual can be found `here <http://solarmuri.ssl.berkeley.edu/~fisher/public/software/FLCT/C_VERSIONS/flct_1.06/doc/flct.pdf>`__. * FLCT is unable to find flows that are normal to image gradients. This is a defect of the LCT concept. * FLCT cannot determine velocities on scales below the scale size of structures in the images. This is a defect of the LCT concept. * Images that have minimal structure can give nonsensical velocity results. * Results can depend on value of ``sigma``, so you must experiment to determine the best choice of ``sigma``. * Velocities corresponding to shifts less than 0.1 - 0.2 pixels are not always detected. It may be necessary to increase the amount of time between images, depending on the noise level in the images. Sometimes using the filtering option helps. * Velocities computed within ``sigma`` pixels of the image edges can be unreliable. * Noisy images can result in spurious velocity results unless a suitable threshold value ``thresh`` is chosen. Parameters ---------- image1 : `numpy.ndarray` The first image. image2 : `numpy.ndarray` The second image taken after ``deltat`` time of the first one. deltat : `float` The time interval between the two images in seconds. deltas : `float` Units of length of the side of a single pixel. Velocity is computed in units of ``deltas`` / ``deltat``. sigma : `float` Sub-images are weighted by Gaussian of width `sigma`. Results can depend on value of `sigma`. The user must experiment to determine best choice of `sigma`. If `sigma` is set to 0, only single values of shifts are returned. These values correspond to the overall shifts between the two images. order : {"row" | "column"}, optional The order in which the array elements are stored that is whether they are stored as row major or column major. Defaults to `row`. quiet : `bool`, optional If set to `True` all the error messages of FLCT C code will be suppressed. Defaults to `False`. biascor : `bool`, optional If set to `True` bias correction will be applied while computing the velocities. This bias is intrinsic to the FLCT algorithm and can underestimate the velocities during calculations. For more details visit `here <http://cgem.ssl.berkeley.edu/cgi-bin/cgem/FLCT/artifact/ac3d8244c3221e8b>`__. thresh : `float`, optional A calculation will not be done for a pixel if the average absolute value between the two images is less than ``thresh``. If ``thresh`` is between 0 and 1, ``thresh`` is assumed given in in relative units of the maximum absolute pixel value in the average of the two images. Defaults to 0. absflag : `bool`, optional This is set to `True` to force the ``thresh`` values between 0 and 1 to be considered in absolute terms. Defaults to False. skip : `int`, optional The number of pixels to be skipped in the ``x`` and ``y`` direction after each calculation of a velocity for a pixel. Defaults to `None`. xoff : `int`, optional The offset in "x" direction after ``skip`` is enabled. Defaults to 0. yoff : `int`, optional The offset in "y" direction after ``skip`` is enabled. Defaults to 0. interp : `bool`, optional If set to `True` interpolation will be performed at the skipped pixels. Defaults to `False`. kr : `float`, optional Apply a low-pass filter to the sub-images, with a Gaussian of a characteristic wavenumber that is a factor of ``kr`` times the largest possible wave numbers in "x", "y" directions. ``kr`` should be positive. Defaults to `None` pc : `bool`, optional Set to `True` if the images are Plate Carrée projected. Defaults to `False`. latmin : `float`, optional Lower latitude limit in radians, used with ``pc``. Defaults to 0. latmax : `float`, optional Upper latitude limit in radians, used with ``pc``. Defaults to 0.2. Returns ------- `tuple` A tuple containing the velocity `~numpy.ndarray` in the following order ``vx``, ``vy``, and ``vm``. ``vx`` is the velocity at every pixel location in the ``x`` direction. ``vy`` is the velocity at every pixel location in the ``y`` direction. ``vm`` is the mask array which is set to 1 at pixel locations where the FLCT calculations were performed, 0 where the calculations were not performed and 0.5 where the results were interpolated. References ---------- * `FLCT software package <http://cgem.ssl.berkeley.edu/cgi-bin/cgem/FLCT/home>`__. * Welsch et al, ApJ 610, 1148, (2004) * Fisher & Welsch, PASP 383, 373, (2008) * Fisher et al., ApJS, accepted (2020) """ # Checking whether the C extension is correctly built. if _pyflct is None: raise ImportError("C extension for flct is missing, please rebuild.") if order.lower() not in ["row", "column"]: raise ValueError("The order of the arrays is not correctly specified. It can only be 'row' or 'column'") # If order is column then order swap is performed. if order == "column": image1, image2 = column_row_of_two(image1, image2) image1 = np.array(image1) image2 = np.array(image2) if quiet is True: verbose = 0 else: verbose = 1 if biascor is False: biascor = 0 else: biascor = 1 if absflag is False: absflag = 0 else: absflag = 1 if interp is False: interp = 0 else: interp = 1 if skip is not None: if skip <= 0: raise ValueError("Skip value must be greater than zero.") if np.abs(xoff) >= skip or np.abs(yoff) >= skip: raise ValueError("The absolute value of 'xoff' and 'yoff' must be less than skip.") else: skip = 0 if kr is not None: if kr <= 0.0 or kr >= 20.0: raise ValueError("The value of 'kr' must be between 0 and 20.") afilter = 1 else: kr = 0.0 afilter = 0 if xoff < 0: xoff = skip - np.abs(xoff) if yoff < 0: yoff = skip - np.abs(yoff) nx = image1.shape[0] ny = image2.shape[1] if sigma == 0: nx = 1 ny = 1 if skip is not None: if skip >= nx or skip >= ny: raise ValueError("Skip is greater than the input dimensions") # This takes care of the order transformations in the C code. transp = 1 vx = np.zeros((nx * ny,), dtype=np.float64) vy = np.zeros((nx * ny,), dtype=np.float64) vm = np.zeros((nx * ny,), dtype=np.float64) if pc is True: ierflct, vx_c, vy_c, vm_c = _pyflct.pyflct_plate_carree( transp, image1, image2, nx, ny, deltat, deltas, sigma, vx, vy, vm, thresh, absflag, afilter, kr, skip, xoff, yoff, interp, latmin, latmax, biascor, verbose, ) else: ierflct, vx_c, vy_c, vm_c = _pyflct.pyflct( transp, image1, image2, nx, ny, deltat, deltas, sigma, vx, vy, vm, thresh, absflag, afilter, kr, skip, xoff, yoff, interp, biascor, verbose, ) # The arrays returned from the FLCT C function are actually 2D arrays but stored as # single dimension array. So after getting them we need to reshape them in the original # shape of the input images. vx_c = vx_c.reshape((nx, ny)) vy_c = vy_c.reshape((nx, ny)) vm_c = vm_c.reshape((nx, ny)) return (vx_c, vy_c, vm_c)