This is the original method of Heeger for the computation of 2D optical flow. More...
#include <ofHeeger.h>
Public Member Functions | |
| OFHeeger (i3d::Image3d< VOXEL > const &in) | |
| virtual | ~OFHeeger () |
| virtual void | ClearWorkingData (void) |
| int | GetState (void) const |
| int | PrintState (void) const |
| int | SetParams (const int bankSize=4, const VOXEL s1=4.0, const VOXEL s2=3.0, const VOXEL s3=1.5, const VOXEL per=6.0) |
| virtual void | PrintSpecs (void) const |
| void | SaveWorkingImages (void) const |
| virtual int | SaveEnergyImages (const VOXEL Vx, const VOXEL Vy, const char *name) const |
| int | GetNumberOfTilts (void) const |
| double | GetTiltStepping (void) const |
| int | GetNumberOfFilters (void) const |
| double | GetBankStepping (void) const |
| VOXEL | GetxSigma (void) const |
| VOXEL | GetySigma (void) const |
| VOXEL | GettSigma (void) const |
| VOXEL | GetPeriod (void) const |
| virtual int | BankPreparation (void) |
| virtual int | BankConvolution (void) |
| virtual int | ComputeEnergy (void) |
| virtual int | ComputeParsevals (void) |
| virtual int | ComputeFlow (Image3d< VOXEL > &Fx, Image3d< VOXEL > &Fy) |
| virtual int | ComputeParsevalsAndFlow (Image3d< VOXEL > &Fx, Image3d< VOXEL > &Fy) |
| virtual int | FillResponsesCache (const int cx, const int cy) |
| virtual int | SaveResponsesCache (void) |
Public Attributes | |
| i3d::Image3d< VOXEL > const & | In |
Protected Member Functions | |
| unsigned int | FRIndex (const int bankTilt, const int bankFilter, const int vx, const int vy) const |
| unsigned int | FRCacheIndex (const int bankTilt, const int bankFilter, const int vx, const int vy) const |
Protected Attributes | |
| int | state |
| int | BankSize |
| int | BankTilts |
| VOXEL | xSigma |
| VOXEL | ySigma |
| VOXEL | tSigma |
| VOXEL | Period |
| struct GaborFilter3D< VOXEL > ** | Filters |
| VOXEL * | FilterResponses |
| VOXEL * | FilterResponsesCache [2 *NUMBEROFSPEEDS][2 *NUMBEROFSPEEDS] |
| i3d::Image3d< VOXEL > *** | OutRe |
| i3d::Image3d< VOXEL > *** | OutIm |
Static Protected Attributes | |
| static const VOXEL | RAF [21] |
This is the original method of Heeger for the computation of 2D optical flow.
The images the class works with must be then 3D, i.e. 2D+time.
The class splitted the method into several parts, which are roughly outlined here. The computation progress is reflected in the state property. There exists a method for each part of the method. These functions automatically inspect and toggle the state property. The process is started with method SetParams(). A wrapper that calls the respective methods in a correct sequence is included in the class as well.
Main constructor: Initiate the method with a read-only reference to the input 3D image.
The initialization may fail, when input image is smaller than 10x10x5 voxels. Therefore, inspect a state of the class after the initialization (state should be CREATED or INCORRECTINPUT).
| [in] | in | an input 2D+t image on which an optical flow is going to be computed |
Destructor: Clears the memory before the class is destroyed. In fact, it only calls ClearWorkingData().
| void OFHeeger< VOXEL >::ClearWorkingData | ( | void | ) | [virtual] |
Clears and frees all working data/arrays/images besides the input one.
The state is set to CREATED or PARAMSKNOWN depending if params were already known (i.e. state >= PARAMSKNOWN).
Reimplemented in OFHeegerANI< VOXEL >.
| int OFHeeger< VOXEL >::GetState | ( | void | ) | const [inline] |
Reads the state of the method.
| int OFHeeger< VOXEL >::PrintState | ( | void | ) | const |
Prints the human-readable name of the method's state, see the description of states, and returns it.
| int OFHeeger< VOXEL >::SetParams | ( | const int | bankSize = 4, |
|
| const VOXEL | s1 = 4.0, |
|||
| const VOXEL | s2 = 3.0, |
|||
| const VOXEL | s3 = 1.5, |
|||
| const VOXEL | per = 6.0 | |||
| ) |
Sets some parameters of the method.
It also resets the interal state to PARAMSKNOWN.
It does not allocate OFHeeger::Filters and working images OFHeeger::OutRe and OFHeeger::OutIm. However, it frees them from the memory prior reseting parameters of the method because this is the last place we know about their structure. After new parameters are set, there seems to be no way to safely free the old memory. The feeing is governed by the ClearWorkingData() function.
| [in] | bankSize | number of filters in a bank to be used, minimum 2 |
| [in] | s1 | sigma along direction of movement, default 4.0 |
| [in] | s2 | sigma spatialy perpendicular to direction, default 3.0 |
| [in] | s3 | sigma temporarily perpendicular to direction, default 1.5 |
| [in] | per | period of sine wave, default 6.0 |
| void OFHeeger< VOXEL >::PrintSpecs | ( | void | ) | const [virtual] |
Pretty print a content of parameters of the method.
Reimplemented in OFHeegerANI< VOXEL >.
| void OFHeeger< VOXEL >::SaveWorkingImages | ( | void | ) | const |
Saves complex working images, if possible.
Otherwise, it is an empty function.
The file names are heegerXXYYReZ.ics and heegerXXYYImZ.ics where XX is a number of tilt/bank, YY is a number of filter within a bank and Z stands for 'C' if the files are saved just after the convolution stage, for 'E' after energies are computed and for 'P' after Gaussian in the Parseval approximation stage.
If OFHeeger::state is inappropriate, the function does nothing.
| int OFHeeger< VOXEL >::SaveEnergyImages | ( | const VOXEL | Vx, | |
| const VOXEL | Vy, | |||
| const char * | name | |||
| ) | const [virtual] |
Saves Fourier images of filtering banks together with a Fourier image of a 2D motion plane.
The energy of filters is stored in red channel. The intersection of filter with a plane is in green channel. The 2D motion plane is in blue channel. Channels are outputs of functions GetGaborEnergyExtImage(), GetGaborEnergyExtImageWithMotion() and GetFourierEnergyOfMotion().
The output image is i3d::RGB16 image of dimensions (2*ONEPERIOD,2*ONEPERIOD,2*ONEPERIOD) with the DC frequency positioned at [ONEPERIOD,ONEPERIOD,ONEPERIOD]. The file names are heegerXXYYname.ics where XX is a number of tilt/bank, YY is a number of filter within a bank and name is supplied suffix. The suffix may be used to encode the motion plane (Vx,Vy).
If OFHeeger::state is not BANKPREPARED or higher, the function does nothing.
| [in] | Vx | x-element of a movement |
| [in] | Vy | y-element of a movement |
| [in] | name | the suffix of the output images |
Reimplemented in OFHeegerANI< VOXEL >.
| int OFHeeger< VOXEL >::GetNumberOfTilts | ( | void | ) | const [inline] |
Returns the number of tilts used in the method or -1 if this number is not set yet.
| double OFHeeger< VOXEL >::GetTiltStepping | ( | void | ) | const [inline] |
Returns the tilt stepping in radians or -1 when the BankTilts is not set yet.
| int OFHeeger< VOXEL >::GetNumberOfFilters | ( | void | ) | const [inline] |
Returns the number of filters in each bank used in the method or -1 if this number is not set yet.
| double OFHeeger< VOXEL >::GetBankStepping | ( | void | ) | const [inline] |
Returns the degree in radians between adjacent filters in a bank or -1 when the BankSize is not set yet.
| VOXEL OFHeeger< VOXEL >::GetxSigma | ( | void | ) | const [inline] |
Returns the OFHeeger::xSigma or -1 when it hasn't been set yet.
| VOXEL OFHeeger< VOXEL >::GetySigma | ( | void | ) | const [inline] |
Returns the OFHeeger::ySigma or -1 when it hasn't been set yet.
| VOXEL OFHeeger< VOXEL >::GettSigma | ( | void | ) | const [inline] |
Returns the OFHeeger::tSigma or -1 when it hasn't been set yet.
| VOXEL OFHeeger< VOXEL >::GetPeriod | ( | void | ) | const [inline] |
Returns the OFHeeger::Period or -1 when it hasn't been set yet.
| int OFHeeger< VOXEL >::BankPreparation | ( | void | ) | [virtual] |
Prepares class for filtering.
The function allocates memory for filter templates, ideal filter responses, the 2nd-level cache for ideal filter responses and working images, which shall store convolution results. The (1st-level global) "normalized" ideal filter responses are computed. The 2nd-level local filter respones will be computed on demand during the flow computations (OFHeeger::ComputeFlow() and OFHeeger::ComputeParsevalsAndFlow()). More on this in docs of the OFHeeger::FilterResponsesCache. However, if a associated cache file exists and the internal state is PARAMSKNOWN then the 2nd-level cache is filled from this file.
The interal state is set to BANKPREPARED.
Reimplemented in OFHeegerANI< VOXEL >, and OFHeegerANI_DC< VOXEL >.
| int OFHeeger< VOXEL >::BankConvolution | ( | void | ) | [virtual] |
A convolution with Gabor bank.
It removes DC from input image and then calls filtering routine ApplyIIRGaborInteger1D(). It removes DC from input image and then conducts filtering with routines ModulateImage(), ApplyIIRGaussInteger1DGB() and DemodulateImage(). The DC offset removing is ala Heeger, i.e. the local means are being subtracted.
The interal state is set to BANKCONVOLVED.
Reimplemented in OFHeegerANI< VOXEL >, and OFHeegerANI_DC< VOXEL >.
| int OFHeeger< VOXEL >::ComputeEnergy | ( | void | ) | [virtual] |
Computes Fourier energy from convolved images.
It works with the complex working images OFHeeger::OutRe and OFHeeger::OutIm directly, modifies them inplace. In fact, since the energy is real number, only the OFHeeger::OutRe's content changes to hold energies. The OFHeeger::OutIm is kept untouched (not released) because it will be used right in the follow-up function ComputeParsevals() in the method's workflow.
The internal state is set to ENERGYCOMPUTED.
| int OFHeeger< VOXEL >::ComputeParsevals | ( | void | ) | [virtual] |
Approximates relation between local image energies and values available after Fourier transform by computing Gaussian on energy images.
It seems that most reasonable filters and their Fourier transforms can be covered under a Gaussian with sigma=0.8, whose Fourier transform covers approximately an area of frequencies -16 to 16. Hence, in this stage all energy images are filtered with isotropic Gaussian with sigma=0.8.
Since we use the ApplyIIRGauss3() in this function, which works with two separate input and output images, the smoothed energies are stored in OFHeeger::OutIm afterwards. The OFHeeger::OutRe is released from memory.
The internal state is set to PARSEVALSGAUSS.
| int OFHeeger< VOXEL >::ComputeFlow | ( | Image3d< VOXEL > & | Fx, | |
| Image3d< VOXEL > & | Fy | |||
| ) | [virtual] |
Computes the optical flow sensed from the original (time-lapse) input image OFHeeger::In.
A 2D velocity is assigned to every voxel in the input image. The first elements of 2D velocities are stored voxel-wise in the output image Fx, the second elements in the Fy. The size of output images Fx and Fy is therefore the size of input image OFHeeger::In.
This function merely compares the "Parsevaled" energies measured in the input image to theoretical filter energies. The theoretical energies should correspond to filter responses on random 2D image moving with a certain velocity, the function IntegrateGaborQEnergy(). The comparison is quantitatively evaluated by computing an error rate: sum of squared differences. The goal is to find such 2D velocity that minimizes the error rate.
Note that we are inspecting results of OFHeeger::BankTilts times OFHeeger::BankSize filters. We are comparing this amount of energies computed from the input image to several the-same-sized groups of theoretical filter responses (each groups theoretical responses from 2D random image moving with certain given velocity). If we imagine a 3D plot with x-axis showing a filter tilt, y-axis showing a filter spatial tuning and z-axis showing response of a filter, each group as well as the sensed values samples some plane in this plot. What we do then to find a correct velocity is to find a theory-at-some-velocity-induced plane that matches the real-measured one the best.
We observed that zero-velocity can be judged directly from a shape of the real-measured plane. It forms a ridge in an otherwise flat plane. The ridge heads along the spatial y-axis and is positioned at "center" tilt (x-axis), i.e. filters tuned for zero-velocity with any spatial tuning had strongest responses. However, sometimes in the real data the ridge is not that strong and not that obvious. We implemented a RidgeRatio detection in this function which, in case it detects ridge, superseeds the plane-comparing evaluation and directly assigns velocity (0,0) to a voxel in question.
To compute the RidgeRatio, the function compares measured responses of a center tilt (a "no-velocity" tilt) with its two neighbors of the same spatial tuning and counts how many neighbors has strictly smaller response. If the number is strictly above 1.2 times the number of spatial tuning used in the method (the OFHeeger::BankTilts) the ridge is deemed present.
The (0,0) velocity is also assigned when measured responses are zero (or close to zero) for given voxel.
The internal state is set to FLOWCOMPUTED.
| [in] | Fx | output image to be filled with x element of optical flow |
| [in] | Fy | output image to be filled with y element of optical flow |
| int OFHeeger< VOXEL >::ComputeParsevalsAndFlow | ( | Image3d< VOXEL > & | Fx, | |
| Image3d< VOXEL > & | Fy | |||
| ) | [virtual] |
This is an optimized variant to computations of "Parseval" and optical flow stages.
Refer to original documentations of OFHeeger::ComputeParsevals() and OFHeeger::ComputeFlow() to learn some properties of this function.
The difference to the original OFHeeger::ComputeFlow() is that memory was rearranged to improve the memory accessing pattern and so the wall-time demand of the two stages. Originally, there are several images holding the computed energies from the input image OFHeeger::In. Assessing some velocity vector for voxel at given position required to read voxel values at this position from all images. When there is not enough free memory on the processor, the images had to swapped away resulting in shifting images back and forth between the main memory and swap for every single image position. The performance was completely lost.
The new arrangement sort of interlaces images such that voxel from all images at given position forms a continuous block in the memory. In fact all voxels from all images at given z-coordinate forms one such block. As a result, there are OFHeeger::In.GetSizeZ() such blocks in the memory (or many of them possibly swapped away). To assess velocity vector, however, only one block is required in the memory. The original working images OFHeeger::OutRe and OFHeeger::OutIm are released from memory to keep the overall memory usage at some reasonable pace.
Otherwise, nothing changes compared to the original functions (including the Note about zeroing nearly zero voxel values).
The internal state is set to FLOWCOMPUTED.
| [in] | Fx | output image to be filled with x element of optical flow |
| [in] | Fy | output image to be filled with y element of optical flow |
| int OFHeeger< VOXEL >::FillResponsesCache | ( | const int | cx, | |
| const int | cy | |||
| ) | [virtual] |
Fills given cell [cx,cy] of the 2nd-level cache OFHeeger::FilterResponsesCache.
If the cache cell is not empty, the function does nothing.
The building/filling of cache is time demanding.
If one is to measure the time required to compute flows on many input images, we suggest to first compute a flow on some single image (side effect will be the initiation of the cache) or just prefill the cache explicitly with this function before the measured computation shall happen. A subsequent flow computations should benefit from the cache and perform a lot faster.
The function can be used when the OFHeeger::state is BANKPREPARED (i.e. after executing OFHeeger::SetParams()) or "higher". The function does not modify the internal state OFHeeger::state.
| [in] | cx | the first index to the array OFHeeger::FilterResponsesCache |
| [in] | cy | the second index to the array OFHeeger::FilterResponsesCache |
Reimplemented in OFHeegerANI< VOXEL >.
| int OFHeeger< VOXEL >::SaveResponsesCache | ( | void | ) | [virtual] |
Saves the 2nd-level cache OFHeeger::FilterResponsesCache into a (persistent) file.
The file is read again automatically by the OFHeeger::BankPreparation(), when found. In fact, it is only read when the OFHeeger::state was PARAMSKNOWN which indicates that new/different filters are used. Otherwise, the state indicates that "still the same old" filters are used again and, thus, the cache remains valid.
The function is recomended to be used right after the OFHeeger::ComputeFlow(), OFHeeger::ComputeParsevalsAndFlow() or OFHeeger::FillResponsesCache() because only these functions build the 2nd-level cache. Hence, it is advisable to store the content of the cache before it is cleared (for instance, as a result of freeing all structures after the flow computation is done).
The building of cache is time demanding.
If one is to measure the time required to compute flows on many input images, we suggest to first compute a flow on some single image (side effect will be the initiation of the cache) or just prefill the cache explicitly with OFHeeger::FillResponsesCache() function before the measured computation shall happen. A subsequent flow computations should benefit from the cache and perform a lot faster.
The function does not modify the internal state OFHeeger::state.
Reimplemented in OFHeegerANI< VOXEL >.
| unsigned int OFHeeger< VOXEL >::FRIndex | ( | const int | bankTilt, | |
| const int | bankFilter, | |||
| const int | vx, | |||
| const int | vy | |||
| ) | const [inline, protected] |
An inline indexer to the array OFHeeger::FilterResponses.
The parameters vx and vy must be integers within the bound of <-NUMBEROFSPEEDS,NUMBEROFSPEEDS>, refer to ofHeeger.h to see the actual number. Similarily, the parameter bankTilt must be between 0 and OFHeeger::BankTilts and the parameter bankFilter must be between 0 and OFHeeger::BankSize, all left-inclusively, right-exclusively.
| [in] | bankTilt | number of filter bank |
| [in] | bankFilter | number of filter in a bank |
| [in] | vx | x element of a LUTed velocity |
| [in] | vy | y element of a LUTed velocity |
| unsigned int OFHeeger< VOXEL >::FRCacheIndex | ( | const int | bankTilt, | |
| const int | bankFilter, | |||
| const int | vx, | |||
| const int | vy | |||
| ) | const [inline, protected] |
An inline indexer to elements of the array OFHeeger::FilterResponsesCache.
The parameters vx and vy must be integers within the bound of <0,4>, representing decimals between 0.1 and 0.5, inclusively, in steps of 0.1. To read an ideal Gabor response for a filter tunned to, for instance, 2nd spatial direction and 3rd tilt and velocity (-2.4,1.8), one should read OFHeeger::FilterResponsesCache[-5+NUMBEROFSPEEDS][3+NUMBEROFSPEEDS][FRCacheIndex(3,2,1,3)], if it exists! (-2.4 and 1.8 are decomposed to -2.5 + 0.1 and 1.5 + 0.3 which points to cell [-2.5*2+NUMBEROFSPEEDS][1.5*2+NUMBEROFSPEEDS].)
| [in] | bankTilt | number of filter bank |
| [in] | bankFilter | number of filter in a bank |
| [in] | vx | x decimal of a LUTed velocity |
| [in] | vy | y decimal of a LUTed velocity |
A read-only public reference to the input image.
It defines the internal state of the computation, use the defines .
Note that some specialized versions of this method may compute more consequent steps at once, e.g. bank convolution and energy computations can be done simultaneously when certain method is used.
The computation is characterized by the following 7 steps:
Some more states may exist for different reasons:
The number of filters in a bank, must be positive even number not less than two.
The number of banks (one tilt is one bank) used by the method is BankTilts.
It must be odd positive integer not less than one, because there must be always a "90deg-tilt" bank for stationary "movements". In fact, it minus one divided by 2 tells how many different velocities the method should be able to detect. This is so because two tilts are required to detect the same velocity in one and the opposite directions.
Currently, it is set to NUMBEROFSPEEDS+1 firmly. Note that NUMBEROFSPEEDS tells twice the number of maximum integer velocity, hence there are (NUMBEROFSPEEDS/2) *2+1 tilts.
The sigma of Gaussian envelope of template Gabor filter.
This one heads along the supposed direction of movement. This number must be strictly greater than OFHeeger::ySigma and OFHeeger::tSigma.
The sigma of Gaussian envelope of template Gabor filter.
This one heads perpendicular to the supposed direction of movement, perpendicular in the spatial plane.
The sigma of Gaussian envelope of template Gabor filter.
This one heads perpendicular to the supposed direction of movement, perpendicular in the temporal plane.
The period of sine wave of template Gabor filter.
The sine heads perpendicular to the supposed direction of movement, perpendicular in the temporal plane.
struct GaborFilter3D< VOXEL >** OFHeeger< VOXEL >::Filters [protected] |
An array of pointers to sample filters each representing each filtering bank.
Filters in the associated bank differs only in the spatial directions which are, obviously, driven by the bank. The length of the array should be OFHeeger::BankTilts.
VOXEL* OFHeeger< VOXEL >::FilterResponses [protected] |
An array of (some) precomputed ideal Gabor responses.
This is truly a look-up-table to avoid repetative computing of the same values. Note that for every pixel in the 2D+t image one must "compare" computed filter reponses to ideal responses over several velocities (vx,vy) to guess a real velocity present in the image. Since every pixel is first examined with the same set of velocities, the look-up-table comes as a welcomed time-saver. It is perhaps explained better in the OFHeeger::FilterResponsesCache.
The array is "linearized" multi-dimensional array originally of the format [vx][vy][FilterInBank][FilterBank]. That's where the term "filter cell", i.e. the number of velocities stored for each filter given by the constant FILTERCELLSIZE, come from. Now, the array "linearizes" the format [vx][vy][FilterInBank][FilterBank]. The number of all filters in this LUT is given as OFHeeger::BankTilts times OFHeeger::BankSize times the FILTERCELLSIZE.
Moral: One would have to allocate many intermediate arrays which may lie over the memory arbitrarily. We opted for this representation to ease allocation of the array and to make sure all values lie continuously in the memory for fast access (hoping to benefit from cpu caches).
To ease the navigation within this array, one may use the inline function FRIndex().
VOXEL* OFHeeger< VOXEL >::FilterResponsesCache[2 *NUMBEROFSPEEDS][2 *NUMBEROFSPEEDS] [protected] |
Cache for LUT of ideal Gabor responses on subpixel velocities (aka 2nd-level cache), similarily to the OFHeeger::FilterResponses array.
The OFHeeger::ComputeFlow() and OFHeeger::ComputeParsevalsAndFlow() functions search for a correct velocity using a global search first in the region of -0.5*NUMBEROFSPEEDS to +0.5*NUMBEROFSPEEDS in steps of 0.5 both for x and y. Subpixel search in the vicinity of a global minimum found in the first search is conducted then. Ideal Gabor responses to many different velocities must be available because they are (very often) used in both searches. Since the first search needs the same set of velocities for every voxel in the input image, a precomputed common LUT OFHeeger::FilterResponses becomes very handy. The second search may use different sets of velocities for different voxels. Hence an on-demand filled array, this array, is created during the second stage.
This array is filled on-demand, unlike the array for the first search. We recognize a velocity cell consisting of 25 * OFHeeger::BankTilts * OFHeeger::BankSize, i.e. there are 5 times 5 combinations of velocities each having to hold values of ideal Gabor responses for every tilt vs. spatial direction combination. For example, a cell [-3][2] (*) holds responses to velocities -1.4 to -1.0 for x and 1.1 to 1.5 for y -- right-adjacent inclusive intervals with stepping of 0.1. Note that the global search uses a step of 0.5 (BTW: that's why only 5 times 5 velocity combinations fit into each cell) and non-integer indices are not allowed in arrays, hence a multiple of two is used. Say, a global extreme was located at (-1,0) during the first search, the following four cells will be additionally examined: [-3+NUMBEROFSPEEDS][-1+NUMBEROFSPEEDS], [-3+NUMBEROFSPEEDS][0+NUMBEROFSPEEDS], [-2+NUMBEROFSPEEDS][-1+NUMBEROFSPEEDS] and [-2+NUMBEROFSPEEDS][0+NUMBEROFSPEEDS]. Everytime a cell's content is computed, it is saved until the end of flow computation, to be reused eventually.
(*) Actually, negative indices in arrays are not allowed in the C++. We use a shift by NUMBEROFSPEEDS that renders a "cell [0][0]" to an array position of [NUMBEROFSPEEDS][NUMBEROFSPEEDS]. The cell from the example is actually located at [-3+NUMBEROFSPEEDS][2+NUMBEROFSPEEDS].
The structure is initialized at creation time (in the constructors) and cleared with OFHeeger::ClearWorkingData(). Empty cell is indicated with NULL. Otherwise a pointer exists and points to an array of length 16 times OFHeeger::BankTilts times OFHeeger::BankSize. Every cell's content can be accessed via indexer FRCacheIndex().
Real part of a complex working images.
These are stored in an array according to the tilt of the bank, the second index is a filter's index within a given bank, e.g. OutRe[tilt][direction] points to a certain image. Hence, after initialization, the array OutRe should be OFHeeger::BankTilts long with each element pointing at an array of length OFHeeger::BankSize.
Complex part of a complex working images.
These are stored in an array according to the tilt of the bank, the second index is a filter's index within a given bank, e.g. OutIm[tilt][direction] points to a certain image. Hence, after initialization, the array OutRe should be OFHeeger::BankTilts long with each element pointing at an array of length OFHeeger::BankSize.
{ 0.0, 0.0, 0.000598874, 0.00296992, 0.00911867, 0.0214467, 0.0424803,
0.0745317, 0.119364, 0.177901, 0.25, 0.334335, 0.428381, 0.528522,
0.630265, 0.728553, 0.818135, 0.893976, 0.951655, 0.987726, 1.0 }
A helper array of constants that approximate filter Responses Adjusting Function (RAF).
The adjusting function is: y=(0.5*sin((y-0.5)*PI)+0.5)*(0.5*sin((y-0.5)*PI)+0.5) . The range and domain of y is the interval <0:1> with 0 and 1 included. Thus, the responses must be stretched to <0:1> beforehand.
The array splits the interval into 20 regular intervals (with 21 knots), each of length 0.05. Simple linear interpolation can be used to obtain values within any such interval.
1.7.1