LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiGenericInterpolator.h

00001 /*
00002  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
00003  * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany
00004  *
00005  * This file is part of the LTI-Computer Vision Library (LTI-Lib)
00006  *
00007  * The LTI-Lib is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License (LGPL)
00009  * as published by the Free Software Foundation; either version 2.1 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * The LTI-Lib is distributed in the hope that it will be
00013  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00014  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with the LTI-Lib; see the file LICENSE.  If
00019  * not, write to the Free Software Foundation, Inc., 59 Temple Place -
00020  * Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 /*----------------------------------------------------------------
00025  * project ....: LTI Digital Image/Signal Processing Library
00026  * file .......: ltiGenericInterpolator.h
00027  * authors ....: Pablo Alvarado
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 12.6.2001
00030  * revisions ..: $Id: ltiGenericInterpolator.h,v 1.8 2006/02/08 11:10:53 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_GENERIC_INTERPOLATOR_H_
00034 #define _LTI_GENERIC_INTERPOLATOR_H_
00035 
00036 #include "ltiImage.h"
00037 #include "ltiVector.h"
00038 #include "ltiScalarValuedInterpolation.h"
00039 
00040 namespace lti {
00041 
00042   /**
00043    * This functor use a generic interpolation concept based on look-up-tables 
00044    * for the interpolation kernels.
00045    *
00046    * The LUT allow to considerably accelerate the computation times, but a
00047    * little bit precision is lost due to the unavoidable quantization present
00048    * in the LUT.
00049    *
00050    * The type T of the template is the type of the elements of the vector
00051    * or matrix used.
00052    */
00053   template <class T>
00054   class genericInterpolator : public scalarValuedInterpolation<T> {
00055   public:
00056     /**
00057      * The parameters for the class genericInterpolator
00058      */
00059     class parameters : public scalarValuedInterpolation<T>::parameters {
00060     public:
00061       /**
00062        * Types for interpolation kernels.
00063        */
00064       enum eInterpolationKernelType {
00065         BilinearKernel, /**< Bilinear interpolation kernel.
00066                          * The neighborhood size is always 2x2.
00067                          * This implementation
00068                          * is slower than the optimized version in the functor
00069                          * lti::bilinearInterpolation, but is provided for
00070                          * completeness.
00071                          */
00072         BicubicKernel,  /**< Bicubic interpolation.
00073                          * The neighborhood size is always 4x4.
00074                          * The kernel provided here is after Sonka et.al. 
00075                          * pp. 67
00076                          *
00077                          * \f[ h(x)=\begin{cases}
00078                          * 1-2|x|^2+|x|^3 & \text{for $0\leq|x|\leq 1$} \\
00079                          * 4-8|x|+5|x|^2-|x|^3 & \text{for $1\leq|x|\leq 2$}\\
00080                          * 0 & \text{otherwise}
00081                          * \end{cases} \f]
00082                          */
00083         GenericKernel   /**< Generic interpolation.
00084                          * The generic interpolation uses the kernelLUT given
00085                          * in the parameters.
00086                          */
00087       };
00088 
00089       /**
00090        * default constructor
00091        */
00092       parameters() : scalarValuedInterpolation<T>::parameters() {
00093         kernelType = eInterpolationKernelType(BicubicKernel);
00094         numSamplesPerInterval = int(128);
00095         this->boundaryType = Constant;
00096         kernelLUT.clear();
00097       };
00098 
00099       /**
00100        * Constructor to set explicitelly the desired boundaryType
00101        */
00102       parameters(const eBoundaryType btype) 
00103         : scalarValuedInterpolation<T>::parameters(btype) {
00104         kernelType = eInterpolationKernelType(BicubicKernel);
00105         numSamplesPerInterval = int(256);
00106         this->boundaryType = Constant;
00107         kernelLUT.clear();
00108       };
00109 
00110       /**
00111        * copy constructor
00112        * @param other the parameters object to be copied
00113        */
00114       parameters(const parameters& other) 
00115         : scalarValuedInterpolation<T>::parameters() {
00116         copy(other);
00117       }
00118       
00119       /**
00120        * destructor
00121        */
00122       ~parameters() {
00123         kernelLUT.clear();
00124       };
00125 
00126       /**
00127        * returns name of this type
00128        */
00129       const char* getTypeName() const {
00130         return "genericInterpolator::parameters";
00131       };
00132 
00133       /**
00134        * copy the contents of a parameters object
00135        * @param other the parameters object to be copied
00136        * @return a reference to this parameters object
00137        */
00138       parameters& copy(const parameters& other) {
00139 #     ifndef _LTI_MSC_6
00140         // MS Visual C++ 6 is not able to compile this...
00141         scalarValuedInterpolation<T>::parameters::copy(other);
00142 #     else
00143         // ...so we have to use this workaround.
00144         // Conditional on that, copy may not be virtual.
00145         scalarValuedInterpolation<T>::parameters&
00146           (scalarValuedInterpolation<T>::parameters::* p_copy)
00147           (const scalarValuedInterpolation<T>::parameters&) =
00148           scalarValuedInterpolation<T>::parameters::copy;
00149         (this->*p_copy)(other);
00150 #     endif
00151         
00152         kernelType = other.kernelType;
00153         numSamplesPerInterval = other.numSamplesPerInterval;
00154         kernelLUT.copy(other.kernelLUT);
00155         return *this;
00156       };
00157 
00158       /**
00159        * copy the contents of a parameters object
00160        * @param other the parameters object to be copied
00161        * @return a reference to this parameters object
00162        */
00163       parameters& operator=(const parameters& other) {
00164         return copy(other);
00165       };
00166 
00167       /**
00168        * returns a pointer to a clone of the parameters
00169        */
00170       virtual functor::parameters* clone() const {
00171         return new parameters(*this);
00172       };
00173 
00174 #     ifndef _LTI_MSC_6
00175       /**
00176        * write the parameters in the given ioHandler
00177        * @param handler the ioHandler to be used
00178        * @param complete if true (the default) the enclosing begin/end will
00179        *        be also written, otherwise only the data block will be written.
00180        * @return true if write was successful
00181        */
00182       virtual bool write(ioHandler& handler,const bool complete=true) const
00183 #     else
00184       /**
00185        * this function is required by MSVC only, as a workaround for a
00186        * very awful bug, which exists since MSVC V.4.0, and still by
00187        * V.6.0 with all bugfixes (so called "service packs") remains
00188        * there...  This method is also public due to another bug, so please
00189        * NEVER EVER call this method directly: use write() instead
00190        */
00191       bool writeMS(ioHandler& handler,const bool complete=true) const
00192 #     endif
00193       {
00194         bool b = true;
00195         if (complete) {
00196           b = handler.writeBegin();
00197         }
00198         
00199         if (b) {
00200           switch (kernelType) {
00201             case BilinearKernel:
00202               lti::write(handler,"kernelType","BilinearKernel");
00203               break;
00204             case BicubicKernel:
00205               lti::write(handler,"kernelType","BicubicKernel");
00206               break;
00207             case GenericKernel:
00208               lti::write(handler,"kernelType","GenericKernel");
00209               break;
00210             default:
00211               lti::write(handler,"kernelType","Unknown");
00212               b=false;
00213           }
00214           
00215           lti::write(handler,"numSamplesPerInterval",numSamplesPerInterval);
00216           lti::write(handler,"kernelLUT",kernelLUT);
00217         }
00218 
00219 #     ifndef _LTI_MSC_6
00220         // This is the standard C++ code, which MS Visual C++ 6 is not able to
00221         // compile...
00222         b = b && scalarValuedInterpolation<T>::parameters::write(handler,
00223                                                                  false);
00224 #     else
00225         bool (scalarValuedInterpolation<T>::parameters::*
00226               p_writeMS)(ioHandler&,
00227                          const bool) const =
00228           scalarValuedInterpolation<T>::parameters::writeMS;
00229         b = b && (this->*p_writeMS)(handler,false);
00230 #     endif
00231 
00232         if (complete) {
00233           b = b && handler.writeEnd();
00234         }
00235 
00236         return b;
00237       }
00238 
00239 #     ifdef _LTI_MSC_6
00240       /**
00241        * write the parameters in the given ioHandler
00242        * @param handler the ioHandler to be used
00243        * @param complete if true (the default) the enclosing begin/end will
00244        *        be also written, otherwise only the data block will be written.
00245        * @return true if write was successful
00246        */
00247       bool write(ioHandler& handler,
00248                  const bool complete=true) const {
00249         // ...we need this workaround to cope with another really
00250         // awful MSVC bug.
00251         return writeMS(handler,complete);
00252       }
00253 #     endif
00254 
00255 
00256 #     ifndef _LTI_MSC_6
00257       /**
00258        * read the parameters from the given ioHandler
00259        * @param handler the ioHandler to be used
00260        * @param complete if true (the default) the enclosing begin/end will
00261        *        be also written, otherwise only the data block will be written.
00262        * @return true if write was successful
00263        */
00264       virtual bool read(ioHandler& handler,const bool complete=true)
00265 #     else
00266       /**
00267        * this function is required by MSVC only, as a workaround for a
00268        * very awful bug, which exists since MSVC V.4.0, and still by
00269        * V.6.0 with all bugfixes (so called "service packs") remains
00270        * there...  This method is also public due to another bug, so please
00271        * NEVER EVER call this method directly: use read() instead
00272        */
00273       bool readMS(ioHandler& handler,const bool complete=true)
00274 #     endif
00275       {
00276         bool b = true;
00277         if (complete) {
00278           b = handler.readBegin();
00279         }
00280         
00281         if (b) {
00282           std::string str;
00283           
00284           lti::read(handler,"kernelType",str);
00285           if (str.find("ilinear") != std::string::npos) {
00286             kernelType = BilinearKernel;
00287           } else if (str.find("icubic") != std::string::npos) {
00288             kernelType = BicubicKernel;            
00289           } else if (str.find("eneric") != std::string::npos) {
00290             kernelType = GenericKernel;
00291           } else {
00292             handler.setStatusString("Unknown interpolator kernel type");
00293             b=false;
00294           }
00295 
00296           lti::read(handler,"numSamplesPerInterval",numSamplesPerInterval);
00297           lti::read(handler,"kernelLUT",kernelLUT);
00298         }
00299 
00300 #       ifndef _LTI_MSC_6
00301         // This is the standard C++ code, which MS Visual C++ 6 is not
00302         // able to compile...
00303         b = b && scalarValuedInterpolation<T>::parameters::read(handler,false);
00304 #       else
00305         bool (scalarValuedInterpolation<T>::parameters::* p_readMS)(ioHandler&,
00306                                                         const bool) =
00307           scalarValuedInterpolation<T>::parameters::readMS;
00308         b = b && (this->*p_readMS)(handler,false);
00309 #       endif
00310 
00311         if (complete) {
00312           b = b && handler.readEnd();
00313         }
00314         
00315         return b;
00316       }
00317 
00318 #     ifdef _LTI_MSC_6
00319       /**
00320        * read the parameters from the given ioHandler
00321        * @param handler the ioHandler to be used
00322        * @param complete if true (the default) the enclosing begin/end will
00323        *        be also written, otherwise only the data block will be written.
00324        * @return true if write was successful
00325        */
00326       bool read(ioHandler& handler,const bool complete=true) {
00327         // ...we need this workaround to cope with another really awful MSVC
00328         // bug.
00329         return readMS(handler,complete);
00330       }
00331 #     endif
00332 
00333       // ------------------------------------------------
00334       // the parameters
00335       // ------------------------------------------------
00336 
00337       /**
00338        * Interpolation type to be used.
00339        *
00340        * Default: Bicubic
00341        */
00342       eInterpolationKernelType kernelType;
00343 
00344       /**
00345        * Number of samples in the interpolation table for a unit interval.
00346        * 
00347        * The total number of elements in the LUT will be this value multiplied
00348        * by the number of unit intervals of the interpolation kernel.
00349        *
00350        * Default value: 256
00351        */
00352       int numSamplesPerInterval;
00353 
00354       /**
00355        * Generic interpolation kernel.
00356        * 
00357        * If the kernelType is GenericKernel then this kernel LUT will be used.
00358        * To be a valid kernel, this vector must have a size \a n times
00359        * numSamplesPerInterval, with \a n even.  If the validity of the
00360        * kernel LUT cannot be confirmed, a Bilinear Kernel will be used
00361        * instead, but setParameters will return false.
00362        *
00363        * Default value: empty kernel
00364        */
00365       fvector kernelLUT;
00366     };
00367 
00368     /**
00369      * default constructor
00370      */
00371     genericInterpolator();
00372 
00373     /**
00374      * Construct an interpolator with the given parameters
00375      */
00376     genericInterpolator(const parameters& params);
00377 
00378     /**
00379      * Construct an interpolator with the given boundary type
00380      */
00381     genericInterpolator(const eBoundaryType boundaryType);
00382 
00383     /**
00384      * copy constructor
00385      * @param other the object to be copied
00386      */
00387     genericInterpolator(const genericInterpolator<T>& other);
00388 
00389     /**
00390      * destructor
00391      */
00392     virtual ~genericInterpolator();
00393 
00394     /**
00395      * returns the name of this type ("genericInterpolator")
00396      */
00397     virtual const char* getTypeName() const;
00398 
00399     /**
00400      * Returns the interpolated value of the vector at the real valued
00401      * position x.
00402      * @param src vector<T> with the source data.
00403      * @param x the real valued position to be interpolated.
00404      * @return the interpolated value of the vector.
00405      */
00406     T apply(const vector<T>& src,const float& x) const;
00407 
00408     /**
00409      * Returns the interpolated value of the vector specified with
00410      * use() at the real valued position x.
00411      * @param x the real valued position to be interpolated.
00412      * @return the interpolated value of the vector.  */
00413     T apply(const float& x) const;
00414 
00415     /**
00416      * Returns the interpolated value of the matrix at the real valued
00417      * position (row,col).
00418      *
00419      * @param src matrix<T> with the source data.
00420      * @param row which row
00421      * @param col which column
00422      * @return the interpolated value of the matrix.
00423      */
00424     T apply(const matrix<T>& src,
00425             const float& row,
00426             const float& col) const;
00427 
00428     /**
00429      * Returns the interpolated value of the matrix at the real valued
00430      * position p.
00431      *
00432      * @param src matrix<T> with the source data.
00433      * @param p the real valued position to be interpolated.
00434      * @return the interpolated value of the matrix.
00435      */
00436     T apply(const matrix<T>& src,const tpoint<float>& p) const;
00437 
00438     /**
00439      * Returns the interpolated value of the matrix specified with
00440      * use() at the real valued position (row,col).
00441      *
00442      * @param row which row
00443      * @param col which column
00444      * @return the interpolated value of the matrix.  */
00445     T apply(const float& row, const float& col) const;
00446 
00447     /**
00448      * Returns the interpolated value of the matrix specified with
00449      * use() at the real valued position p.
00450      *
00451      * @param p the real valued position to be interpolated.
00452      * @return the interpolated value of the matrix.
00453      */
00454     T apply(const tpoint<float>& p) const;
00455 
00456     /**
00457      * Returns the interpolated value of the matrix at the real valued
00458      * position (row,col).  This method is not virtual and can be used
00459      * if this interpolation type is used as template parameter in time
00460      * critical situations
00461      *
00462      * @param src matrix<T> with the source data.
00463      * @param row which row
00464      * @param col which column
00465      * @return the interpolated value of the matrix.
00466      */
00467     T interpolate(const matrix<T>& src,
00468                   const float row,
00469                   const float col) const;
00470 
00471     /**
00472      * Returns the interpolated value of the matrix specified with
00473      * use() at the real valued position (row,col).  This method is
00474      * not virtual and can be used if this interpolation type is used
00475      * as template parameter in time critical situations
00476      *
00477      * @param row which row
00478      * @param col which column
00479      * @return the interpolated value of the matrix.
00480      */
00481     inline T interpolate(const float row,
00482                          const float col) const {
00483       return interpolate(*this->theMatrix,row,col);
00484     };
00485 
00486     /**
00487      * Returns the interpolated value of the matrix at the real valued
00488      * position (row,col).
00489      *
00490      * This method does not check if the given coordinates and the rest of
00491      * used points in the src matrix lie within the valid range.  This is
00492      * left to you.  Please consider that for the generic interpolation
00493      * not only the point(trunc(col),trunc(row)) is used, but a nxn 
00494      * neighborhood centered such that (col,row) is nearest to the center.
00495      *
00496      * This method is not virtual and can be used in time critical situations,
00497      * where you prefer to take the boundary control by yourself.
00498      *
00499      * @param src matrix<T> with the source data.
00500      * @param row which row
00501      * @param col which column
00502      * @return the interpolated value of the matrix.
00503      */
00504     inline T interpolateUnchk(const matrix<T>& src,
00505                               const float row,
00506                               const float col);
00507 
00508     /**
00509      * Returns the interpolated value of the matrix specified with
00510      * use() at the real valued position (row,col).  This method is
00511      * not virtual and can be used if this interpolation type is used
00512      * as template parameter in time critical situations
00513      *
00514      * @param row which row
00515      * @param col which column
00516      * @return the interpolated value of the matrix.
00517      */
00518     inline T interpolateUnchk(const float row,
00519                               const float col);
00520 
00521     /**
00522      * copy data of "other" functor.
00523      * @param other the functor to be copied
00524      * @return a reference to this functor object
00525      */
00526     genericInterpolator& copy(const genericInterpolator& other);
00527 
00528     /**
00529      * returns a pointer to a clone of this functor.
00530      */
00531     virtual functor* clone() const;
00532 
00533     /**
00534      * returns used parameters
00535      */
00536     const parameters& getParameters() const;
00537 
00538     /**
00539      * returns used parameters
00540      */
00541     virtual bool updateParameters();
00542 
00543     /**
00544      * Return a read only reference to the last computed LUT.
00545      *
00546      * This method is mainly used for debugging purposes.
00547      */
00548     inline const vector<float>& getLUT() const;
00549 
00550     /**
00551      * Compute the generic interpolated value for the given coefficients
00552      * and values.
00553      *
00554      * This method is provided for convenience only.  Use at your own
00555      * risk.
00556      *
00557      * @param fx fractional term between 0.0f (inclusive) and 1.0f (exclusive)
00558      * @param data pointer to an array with the support samples.  It has at
00559      *             least \a n elements, with \a n the number of unit intervals
00560      *             in the interpolation kernel.
00561      *             Their position will be assumed to be from 
00562      *             -(n/2-1) to n/2, so that the
00563      *             interval 0..1 lies exaclty in the middle.
00564      *
00565      * @return interpolated value between the three values
00566      */
00567     inline T compute(const float fx,const T* data) const;
00568     
00569     /**
00570      * Compute the generic interpolated value for the given coefficients
00571      * and values.
00572      *
00573      * This method is provided for convenience only.  Use at your own
00574      * risk.
00575      *
00576      * @param fy fractional term between 0.0 and 1.0
00577      * @param fx fractional term between 0.0 and 1.0
00578      * @param data pointer to an array of arrays with the support samples.
00579      *
00580      * @return interpolated value between the four corners
00581      */
00582     inline T compute(const float fy,
00583                      const float fx,
00584                      const T** data) const;
00585 
00586   protected:
00587     /**
00588      * The interpolation kernel is traversed in revers order than
00589      * the data.  To save the first computation time, we store the
00590      * sample index for the first element of the last interval
00591      */
00592     int lastIntervalFirstSample;
00593 
00594     /**
00595      * Number of intervals really used.
00596      *
00597      * The value given in the parameters might be ignored depending on the
00598      * chosen kernel type.
00599      */
00600     int numberOfIntervals;
00601 
00602     /**
00603      * This is the number that need to be substracted  to a position point
00604      * to get the first valid support sample.
00605      * It is usually numberOfIntervals/2 - 1;
00606      */
00607     int firstSampleOffset;
00608      
00609     /**
00610      * Interval size taken from the parameters numSamplesPerInterval;
00611      */
00612     int intervalSize;
00613 
00614     /**
00615      * @name Buffers
00616      */
00617     /**
00618      * For the two dimensional interpolation, this vector will administrate
00619      * the memory array required.
00620      */
00621     vector<T> column;
00622 
00623     /**
00624      * This pointer will always point to the first element of column
00625      */
00626     T* firstElemColumn;
00627 
00628     /**
00629      * This is a small window that can be used to save temporarily the
00630      * sample supporting points
00631      */
00632     mutable matrix<T> buffer;
00633 
00634     /**
00635      * This pointer to arrays is initialized to have the proper size, but
00636      * you have to set the second pointers by yourself
00637      */
00638     mutable const T** rows;
00639 
00640     /**
00641      * This is initialized to point a the buffer's rows.
00642      */
00643     const T** bufferRows;
00644 
00645     //@}
00646 
00647     /**
00648      * @name Kernel initialization routines
00649      */
00650     //@{
00651     /**
00652      * Interpolation kernel.
00653      *
00654      * This is initialized by the initLUT
00655      */
00656     vector<float> interpolationKernel;
00657 
00658     /**
00659      * Initialize the interpolation kernel LUT based on the parameters
00660      * settings.
00661      *
00662      * The LUT has only positive entries, but represents the interval from
00663      * -halfSize+1 to halfSize.  No use of the symmetrical properties of the
00664      * kernel are exploited to improve efficiency, since less comparisons are
00665      * required.
00666      */
00667     bool initLUT();
00668 
00669     /**
00670      * Initialization of the bilinear kernel.
00671      * Two unit intervals wlll be initialized.
00672      */
00673     bool initBilinearLUT();
00674 
00675     /**
00676      * Initialization of the bicubic kernel.
00677      * Four unit intervals wlll be initialized.
00678      * The kernel provided here is after Sonka et.al. page 67:
00679      * \code
00680      *           /     
00681      *          |  1-2|x|^2 + |x|^3           for 0<=x<=1
00682      *  h(x) = <   4-8|x|^2 + 5|x|^2 - |x|^3  for 1<x<=2
00683      *          |  0                          otherwise 
00684      *           \
00685      * \endcode
00686      */
00687     bool initBicubicLUT();
00688 
00689     /**
00690      * Generic kernel initialization.
00691      * 
00692      * This method checks that the kernelLUT in the parameters is a valid
00693      * kernel and sets all required attributes.
00694      */
00695     bool initGenericLUT();
00696 
00697     //@}
00698   };
00699 }
00700 
00701 #include "ltiGenericInterpolator_inline.h"
00702 
00703 #endif

Generated on Sat Apr 10 15:25:34 2010 for LTI-Lib by Doxygen 1.6.1