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

| Camera MTF Estimation |

## Classes
class | SlantedEdgeMTFOptions
| Pass options to one of the slantedEdgeMTF() functions. More...
## Functions
template<class Vector>
double | mtfFitGaussian (Vector const &mtf)
| Fit a Gaussian function to a given MTF.
template<... >
void | slantedEdgeMTF (...)
| Determine the magnitude transfer function of the camera.

## Detailed Description

Determine the magnitude transfer function (MTF) of a camera using the slanted edge method.

## Function Documentation

template<... >
void vigra::slantedEdgeMTF | ( |  | ... | ) |

Determine the magnitude transfer function of the camera.

This operator estimates the magnitude transfer function (MTF) of a camera by means of the slanted edge method described in:

ISO Standard No. 12233: "Photography - Electronic still picture cameras - Resolution measurements", 2000

The input must be an image that contains a single step edge with bright pixels on one side and dark pixels on the other. However, the intensity values must be neither saturated nor zero. The algorithms computes the MTF from the Fourier transform of the edge's derivative. Thus, if the actual MTF is unisotropic, the estimated MTF does actually only apply in the direction perpendicular to the edge - several edges at different orientations are required to estimate an unisotropic MTF.

The algorithm returns a sequence of frequency / attenuation pairs. The frequency axis is normalized so that the Nyquist frequency of the original image is 0.5. Since the edge's derivative is computed with subpixel accuracy, the attenuation can usually be computed for frequencies significantly above the Nyquist frequency as well. The MTF estimate ends at either the first zero crossing of the MTF or at frequency 1, whichever comes earlier.

The present implementation improves the original slanted edge algorithm according to ISO 12233 in a number of ways:

- The edge is not required to run nearly vertically or horizontally (i.e. with a slant of approximately 5 degrees). The algorithm will automatically compute the edge's actual angle and adjust estimates accordingly. However, it is still necessary for the edge to be somewhat slanted, because subpixel-accurate estimation of the derivative is impossible otherwise (i.e. the edge position perpendicular to the edge direction must differ by at least 1 pixel between the two ends of the edge).

- Our implementation uses a more accurate subpixel derivative algrithm. In addition, we first perform a shading correction in order to reduce possible derivative bias due to nonuniform illumination.

- If the input image is large enough (i.e. there are at least 20 pixels on either side of the edge over the edge's entire length), our algorithm attempts to subtract the estimated noise power spectrum from the estimated MTF.

The source value type (`SrcAccessor::value_type`) must be a scalar type which is convertible to `double`. The result is written into the result sequence, whose `value_type` must be constructible from two `double` values. Algorithm options can be set via the options object (see vigra::NoiseNormalizationOptions for details).

Declarations:

pass arguments explicitly:

        namespace vigra {
            template <class SrcIterator, class SrcAccessor, class BackInsertable>
            void
            slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, BackInsertable & mtf,
                        SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOptions());
        }

use argument objects in conjunction with Argument Object Factories :

        namespace vigra {
            template <class SrcIterator, class SrcAccessor, class BackInsertable>
            void
            slantedEdgeMTF(triple<SrcIterator, SrcIterator, SrcAccessor> src, BackInsertable & mtf,
                           SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOptions())
        }

Usage:

#include <vigra/slanted_edge_mtf.hxx>
Namespace: vigra

        vigra::BImage src(w,h);
        std::vector<vigra::TinyVector<double, 2> > mtf;

        ...
        vigra::slantedEdgeMTF(srcImageRange(src), mtf);

        // print the frequency / attenuation pairs found
        for(int k=0; k<result.size(); ++k)
            std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation: " << mtf[k][1] << std::endl;

Required Interface:

        SrcIterator upperleft, lowerright;
        SrcAccessor src;

        typedef SrcAccessor::value_type SrcType;
        typedef NumericTraits<SrcType>::isScalar isScalar;
        assert(isScalar::asBool == true);

        double value = src(uperleft);

        BackInsertable result;
        typedef BackInsertable::value_type ResultType;
        double intensity, variance;
        result.push_back(ResultType(intensity, variance));

template<class Vector>
double vigra::mtfFitGaussian | ( | Vector const & | mtf | ) |

Fit a Gaussian function to a given MTF.

This function expects a squence of frequency / attenuation pairs as produced by slantedEdgeMTF() and finds the best fitting Gaussian point spread function (Gaussian functions are good approximations of the PSF of many real cameras). It returns the standard deviation (scale) of this function. The algorithm computes the standard deviation by means of a linear least square on the logarithm of the MTF, i.e. an algebraic fit rather than a Euclidean fit - thus, the resulting Gaussian may not be the one that intuitively fits the data optimally.

Declaration:

        namespace vigra {
            template <class Vector>
            double mtfFitGaussian(Vector const & mtf);
        }

Usage:

#include <vigra/slanted_edge_mtf.hxx>
Namespace: vigra

        vigra::BImage src(w,h);
        std::vector<vigra::TinyVector<double, 2> > mtf;

        ...
        vigra::slantedEdgeMTF(srcImageRange(src), mtf);
        double scale = vigra::mtfFitGaussian(mtf)

        std::cout << "The camera PSF is approximately a Gaussian at scale " << scale << std::endl;

Required Interface:

        Vector mtf;
        int numberOfMeasurements = mtf.size()

        double frequency = mtf[0][0];
        double attenuation = mtf[0][1];

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python VIGRA 1.6.0 (13 Aug 2008)