[ VIGRA Homepage | Class Index | Function Index | File Index | Main Page ]

| Fast Fourier Transform |
--- | --- | ---

## Functions
template<...> void | moveDCToCenter (SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor sa, DestImageIterator dest_upperleft, DestAccessor da)
| Rearrange the quadrants of a Fourier image so that the origin is in the image center.
template<...> void | moveDCToUpperLeft (SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor sa, DestImageIterator dest_upperleft, DestAccessor da)
| Rearrange the quadrants of a Fourier image so that the origin is in the image's upper left.
template<...> void | applyFourierFilter (triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, pair< FilterImageIterator, FilterAccessor > filter, pair< DestImageIterator, DestAccessor > dest)
| Apply a filter (defined in the frequency domain) to an image.
template<...> void | applyFourierFilterFamily (triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, const ImageArray< FilterType > &filters, ImageArray< DestImage > &results)
| Apply an array of filters (defined in the frequency domain) to an image.
template<...> void | fourierTransformRealEE (triple< SrcTraverser, SrcTraverser, SrcAccessor > src, pair< DestTraverser, DestAccessor > dest, fftw_real norm)
| Real Fourier transforms for even and odd boundary conditions (aka. cosine and sine transforms).

## Detailed Description

This documentation describes the VIGRA interface to FFTW 3. There is also an interface to the older version FFTW 2

VIGRA uses the FFTW Fast Fourier Transform package to perform Fourier transformations. VIGRA provides a wrapper for FFTW's complex number type (FFTWComplex), but FFTW's functions are used verbatim. If the image is stored as a FFTWComplexImage, the simplest call to an FFT function is like this:

        vigra::FFTWComplexImage spatial(width,height), fourier(width,height);
        ... // fill image with data

        // create a plan with estimated performance optimization
        fftw_plan forwardPlan = fftw_plan_dft_2d(height, width,
                                    (fftw_complex *)spatial.begin(), (fftw_complex *)fourier.begin(),
                                    FFTW_FORWARD, FFTW_ESTIMATE );
        // calculate FFT (this can be repeated as often as needed,
        //                with fresh data written into the source array)
        fftw_execute(forwardPlan);

        // release the plan memory
        fftw_destroy_plan(forwardPlan);

        // likewise for the inverse transform
        fftw_plan backwardPlan = fftw_plan_dft_2d(height, width,
                                     (fftw_complex *)fourier.begin(), (fftw_complex *)spatial.begin(),
                                     FFTW_BACKWARD, FFTW_ESTIMATE);
        fftw_execute(backwardPlan);
        fftw_destroy_plan(backwardPlan);

        // do not forget to normalize the result according to the image size
        transformImage(srcImageRange(spatial), destImage(spatial),
                       std::bind1st(std::multiplies<FFTWComplex>(), 1.0 / width / height));

Note that in the creation of a plan, the height must be given first. Note also that `spatial.begin()` may only be passed to `fftw_plan_dft_2d` if the transform shall be applied to the entire image. When you want to restrict operation to an ROI, you can create a copy of the ROI in an image of appropriate size, or you may use the Guru interface to FFTW.

More information on using FFTW can be found here.

FFTW produces fourier images that have the DC component (the origin of the Fourier space) in the upper left corner. Often, one wants the origin in the center of the image, so that frequencies always increase towards the border of the image. This can be achieved by calling moveDCToCenter(). The inverse transformation is done by moveDCToUpperLeft().

#include "vigra/fftw3.hxx"
Namespace: vigra

## Function Documentation

void applyFourierFilter (...)

| Apply a filter (defined in the frequency domain) to an image. After transferring the image into the frequency domain, it is multiplied pixel-wise with the filter and transformed back. The result is always put into the given FFTWComplexImage `destImg` which must have the right size. Finally, the result will be normalized to compensate for the two FFTs. The input and filter images can be scalar images (more precisely, `SrcAccessor::value_type` must be scalar) or FFTWComplexImages (in this case, one conversion is saved). The DC entry of the filter must be in the upper left, which is the position where FFTW expects it (see moveDCToUpperLeft()). You can optionally pass two fftwnd_plans as last parameters, the forward plan and the in-place backward plan. Both must have been created for the right image size (see sample code). Declarations: pass arguments explicitly:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
                class FilterImageIterator, class FilterAccessor>
            void applyFourierFilter(SrcImageIterator srcUpperLeft,
                                    SrcImageIterator srcLowerRight, SrcAccessor sa,
                                    FilterImageIterator filterUpperLeft, FilterAccessor fa,
                                    FFTWComplexImage & destImg)

            template <class SrcImageIterator, class SrcAccessor,
                class FilterImageIterator, class FilterAccessor>
            void applyFourierFilter(SrcImageIterator srcUpperLeft,
                                    SrcImageIterator srcLowerRight, SrcAccessor sa,
                                    FilterImageIterator filterUpperLeft, FilterAccessor fa,
                                    FFTWComplexImage & destImg,
                                    const fftwnd_plan & forwardPlan, const fftwnd_plan & backwardPlan)
        }
use argument objects in conjunction with Argument Object Factories:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
                class FilterImageIterator, class FilterAccessor>
            inline
            void applyFourierFilter(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
                                    pair<FilterImageIterator, FilterAccessor> filter,
                                    FFTWComplexImage &destImg)

            template <class SrcImageIterator, class SrcAccessor,
                class FilterImageIterator, class FilterAccessor>
            inline
            void applyFourierFilter(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
                                    pair<FilterImageIterator, FilterAccessor> filter,
                                    FFTWComplexImage &destImg,
                                    const fftwnd_plan &forwardPlan, const fftwnd_plan &backwardPlan)
        }
Usage: #include "vigra/fftw3.hxx" Namespace: vigra
        // create a Gaussian filter in Fourier space
        vigra::FImage gaussFilter(w, h), filter(w, h);
        for(int y=0; y<h; ++y)
            for(int x=0; x<w; ++x)
            {
                xx = float(x - w / 2) / w;
                yy = float(y - h / 2) / h;

                gaussFilter(x,y) = std::exp(-(xx*xx + yy*yy) / 2.0 * scale);
            }

        // applyFourierFilter() expects the filter's DC in the upper left
        moveDCToUpperLeft(srcImageRange(gaussFilter), destImage(filter));

        vigra::FFTWComplexImage result(w, h);

        vigra::applyFourierFilter(srcImageRange(image), srcImage(filter), result);
For inspection of the result, FFTWMagnitudeAccessor might be useful. If you want to apply the same filter repeatedly, it may be more efficient to use the FFTW functions directly with FFTW plans optimized for good performance.

void applyFourierFilterFamily (...)

| Apply an array of filters (defined in the frequency domain) to an image. This provides the same functionality as applyFourierFilter(), but applying several filters at once allows to avoid repeated Fourier transforms of the source image. Filters and result images must be stored in vigra::ImageArray data structures. In contrast to applyFourierFilter(), this function adjusts the size of the result images and the the length of the array. Declarations: pass arguments explicitly:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor, class FilterType>
            void applyFourierFilterFamily(SrcImageIterator srcUpperLeft,
                                          SrcImageIterator srcLowerRight, SrcAccessor sa,
                                          const ImageArray<FilterType> &filters,
                                          ImageArray<FFTWComplexImage> &results)
        }
use argument objects in conjunction with Argument Object Factories:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor, class FilterType>
            inline
            void applyFourierFilterFamily(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
                                          const ImageArray<FilterType> &filters,
                                          ImageArray<FFTWComplexImage> &results)
        }
Usage: #include "vigra/fftw3.hxx" Namespace: vigra
        // assuming the presence of a real-valued image named "image" to
        // be filtered in this example

        vigra::ImageArray<vigra::FImage> filters(16, image.size());

        for (int i=0; i<filters.size(); i++)
             // create some meaningful filters here
             createMyFilterOfScale(i, destImage(filters[i]));

        vigra::ImageArray<vigra::FFTWComplexImage> results();

        vigra::applyFourierFilterFamily(srcImageRange(image), filters, results);

void fourierTransformRealEE (...)

| Real Fourier transforms for even and odd boundary conditions (aka. cosine and sine transforms). If the image is real and has even symmetry, its Fourier transform is also real and has even symmetry. The Fourier transform of a real image with odd symmetry is imaginary and has odd symmetry. In either case, only about a quarter of the pixels need to be stored because the rest can be calculated from the symmetry properties. This is especially useful, if the original image is implicitly assumed to have reflective or anti-reflective boundary conditions. Then the "negative" pixel locations are defined as
        even (reflective boundary conditions):      f[-x] = f[x]     (x = 1,...,N-1)
        odd (anti-reflective boundary conditions):  f[-1] = 0
                                                    f[-x] = -f[x-2]  (x = 2,...,N-1)
end similar at the other boundary (see the FFTW documentation for details). This has the advantage that more efficient Fourier transforms that use only real numbers can be implemented. These are also known as cosine and sine transforms respectively. If you use the odd transform it is important to note that in the Fourier domain, the DC component is always zero and is therefore dropped from the data structure. This means that index 0 in an odd symmetric Fourier domain image refers to the first harmonic. This is especially important if an image is first cosine transformed (even symmetry), then in the Fourier domain multiplied with an odd symmetric filter (e.g. a first derivative) and finally transformed back to the spatial domain with a sine transform (odd symmetric). For this to work properly the image must be shifted left or up by one pixel (depending on whether the x- or y-axis is odd symmetric) before the inverse transform can be applied. (see example below). The real Fourier transform functions are named `fourierTransformReal??` where the questions marks stand for either `E` or `O` indicating whether the x- and y-axis is to be transformed using even or odd symmetry. The same functions can be used for both the forward and inverse transforms, only the normalization changes. For signal processing, the following normalization factors are most appropriate:
                              forward             inverse
        ------------------------------------------------------------
        X even, Y even           1.0         4.0 * (w-1) * (h-1)
        X even, Y odd           -1.0        -4.0 * (w-1) * (h+1)
        X odd,  Y even          -1.0        -4.0 * (w+1) * (h-1)
        X odd,  Y odd            1.0         4.0 * (w+1) * (h+1)
where `w` and `h` denote the image width and height. Declarations: pass arguments explicitly:
        namespace vigra {
            template <class SrcTraverser, class SrcAccessor,
                      class DestTraverser, class DestAccessor>
            void
            fourierTransformRealEE(SrcTraverser sul, SrcTraverser slr, SrcAccessor src,
                                   DestTraverser dul, DestAccessor dest, fftw_real norm);

            fourierTransformRealEO, fourierTransformRealOE, fourierTransformRealOO likewise
        }
use argument objects in conjunction with Argument Object Factories:
        namespace vigra {
            template <class SrcTraverser, class SrcAccessor,
                      class DestTraverser, class DestAccessor>
            void
            fourierTransformRealEE(triple<SrcTraverser, SrcTraverser, SrcAccessor> src,
                                   pair<DestTraverser, DestAccessor> dest, fftw_real norm);

            fourierTransformRealEO, fourierTransformRealOE, fourierTransformRealOO likewise
        }
Usage: #include "vigra/fftw3.hxx" Namespace: vigra
        vigra::FImage spatial(width,height), fourier(width,height);
        ... // fill image with data

        // forward cosine transform == reflective boundary conditions
        fourierTransformRealEE(srcImageRange(spatial), destImage(fourier), (fftw_real)1.0);

        // multiply with a first derivative of Gaussian in x-direction
        for(int y = 0; y < height; ++y)
        {
            for(int x = 1; x < width; ++x)
            {
                double dx = x * M_PI / (width - 1);
                double dy = y * M_PI / (height - 1);
                fourier(x-1, y) = fourier(x, y) * dx * exp(-(dx*dx + dy*dy) * scale*scale / 2.0);
            }
            fourier(width-1, y) = 0.0;
        }

        // inverse transform -- odd symmetry in x-direction, even in y,
        //                      due to symmetry of the filter
        fourierTransformRealOE(srcImageRange(fourier), destImage(spatial),
                               (fftw_real)-4.0 * (width+1) * (height-1));

void moveDCToCenter (...)

| Rearrange the quadrants of a Fourier image so that the origin is in the image center. FFTW produces fourier images where the DC component (origin of fourier space) is located in the upper left corner of the image. The quadrants are placed like this (using a 4x4 image for example):
                DC 4 3 3
                 4 4 3 3
                 1 1 2 2
                 1 1 2 2
After applying the function, the quadrants are at their usual places:
                2 2  1 1
                2 2  1 1
                3 3 DC 4
                3 3  4 4
This transformation can be reversed by moveDCToUpperLeft(). Note that the transformation must not be executed in place - input and output images must be different. Declarations: pass arguments explicitly:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
              class DestImageIterator, class DestAccessor>
            void moveDCToCenter(SrcImageIterator src_upperleft,
                                   SrcImageIterator src_lowerright, SrcAccessor sa,
                                   DestImageIterator dest_upperleft, DestAccessor da);
        }
use argument objects in conjunction with Argument Object Factories:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
                      class DestImageIterator, class DestAccessor>
            void moveDCToCenter(
                triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
                pair<DestImageIterator, DestAccessor> dest);
        }
Usage: #include "vigra/fftw3.hxx" Namespace: vigra
        vigra::FFTWComplexImage spatial(width,height), fourier(width,height);
        ... // fill image with data

        // create a plan with estimated performance optimization
        fftw_plan forwardPlan = fftw_plan_dft_2d(height, width,
                                    (fftw_complex *)spatial.begin(), (fftw_complex *)fourier.begin(),
                                    FFTW_FORWARD, FFTW_ESTIMATE );
        // calculate FFT
        fftw_execute(forwardPlan);

        vigra::FFTWComplexImage rearrangedFourier(width, height);
        moveDCToCenter(srcImageRange(fourier), destImage(rearrangedFourier));

        // delete the plan
        fftw_destroy_plan(forwardPlan);

void moveDCToUpperLeft (...)

| Rearrange the quadrants of a Fourier image so that the origin is in the image's upper left. This function is the inversion of moveDCToCenter(). See there for declarations and a usage example. Declarations: pass arguments explicitly:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
              class DestImageIterator, class DestAccessor>
            void moveDCToUpperLeft(SrcImageIterator src_upperleft,
                                   SrcImageIterator src_lowerright, SrcAccessor sa,
                                   DestImageIterator dest_upperleft, DestAccessor da);
        }
use argument objects in conjunction with Argument Object Factories:
        namespace vigra {
            template <class SrcImageIterator, class SrcAccessor,
                      class DestImageIterator, class DestAccessor>
            void moveDCToUpperLeft(
                triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
                pair<DestImageIterator, DestAccessor> dest);
        }

© Ullrich Köthe (koethe@informatik.uni-hamburg.de) Cognitive Systems Group, University of Hamburg, Germany | html generated using doxygen and Python VIGRA 1.3.2 (27 Jan 2005)