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

ltiLinearKernels.h

00001 /*
00002  * Copyright (C) 2000, 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 .......: ltiLinearKernels.h
00027  * authors ....: Pablo Alvarado
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 28.04.00
00030  * revisions ..: $Id: ltiLinearKernels.h,v 1.10 2006/02/08 11:22:35 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_LINEARKERNELS_H_
00034 #define _LTI_LINEARKERNELS_H_
00035 
00036 #include <vector>
00037 #include "ltiArray.h"
00038 #include "ltiMatrix.h"
00039 #include "ltiTypes.h"
00040 #include "ltiTypeInfo.h"
00041 
00042 namespace lti {
00043 
00044   /**
00045    * one-dimensional filter kernel
00046    *
00047    * The template type of this class should coincide with the template
00048    * class of the vector be convolved with.  For example, if you want
00049    * to convolve a kernel1D with a vector<double>, you will need a
00050    * kernel1D<double> (@see lti::convolution).
00051    *
00052    * If you instantiate a kernel1D of a fixed point type, like
00053    * kernel1D<int> or kernel1D<ubyte>, you also need to consider the
00054    * "norm" of the kernel (see lti::kernel1D<T>::getNorm() and
00055    * lti::kernel1D<T>::setNorm(const T&)). This "norm" allows the
00056    * representation of numbers less than 1.0.  You can see this norm as the
00057    * value to be consider as 1.0, when operating with the kernel.
00058    * For example, if you have a kernel1D<ubyte> with the values [64,128,64]
00059    * and norm=255, the the interpreted values during convolution will be
00060    * [0.25,0.5,0.25].  With floating-point types, the norm will be always
00061    * assumed to be 1.0.  For other types the default norms are the following:
00062    *
00063    * For int:              65536
00064    * For ubyte:              255
00065    * Otherwise:                1.0
00066    *
00067    * @see lti::convolution
00068    */
00069   template<class T>
00070   class kernel1D : public array<T> {
00071   public:
00072     /**
00073      * default constructor
00074      */
00075     kernel1D();
00076     /** construct a filter kernel indexed from <em>from</em> to <em>to</em> and
00077   initialized with the value <em>init</em> */
00078     kernel1D(const int& from,
00079        const int& to,
00080        const T& init=T());
00081     /** construct a kernel from a one dimensional vector
00082         @param other the source vector
00083         @param theOffset this is the index in the vector that corresponds to
00084                          the index '0' in the filter kernel
00085     */
00086     kernel1D(const vector<T>& other,const int& theOffset);
00087 
00088     /**
00089      * If \a init is true this constructor is equivalent to calling
00090      * kernel1D(const int& from, const int& to), and thus initializing
00091      * all elements with T(). However, in some cases the elements need
00092      * not be initialized during construction, since complex
00093      * initializion is required. Especially for large kernel1Ds, the
00094      * unnecessary constructor initialization is very time consuming.
00095      *
00096      * If \a init is false, memory is allocated but no initialization
00097      * takes place.
00098      *
00099      * @param init initialize matrix or not
00100      * @param from first index
00101      * @param to last index
00102      */
00103     kernel1D(const bool& init, const int& from, const int& to);
00104 
00105     /** copy constructor
00106         @param other the one dimensional kernel to be copied
00107     */
00108     kernel1D(const kernel1D& other);
00109 
00110     /**
00111      * destructor
00112      */
00113     virtual ~kernel1D();
00114 
00115     /**
00116      * returns name of this type ("kernel1D")
00117      */
00118     const char* getTypeName() const {return "kernel1D";};
00119 
00120     /**
00121      * copy member
00122      * @param other the one dimensional kernel to be copied
00123      * @return a reference to this instance
00124      */
00125     kernel1D& copy(const kernel1D& other);
00126 
00127     /**
00128      * clone member
00129      * @return a pointer to a copy of this object
00130      */
00131     virtual mathObject* clone() const {
00132       return (new kernel1D<T>(*this));
00133     }
00134 
00135     /**
00136      * copy from kernel of different type
00137      * @param other a one dimensional kernel of another type
00138      * @return a reference to this instance
00139      */
00140     template<class U>
00141     kernel1D& castFrom(const kernel1D<U>& other) {
00142       array<T>::castFrom(other);
00143       norm = T(other.getNorm());
00144       return (*this);
00145     };
00146 
00147     /**
00148      * copy the content of the other vector in this kernel and assign
00149      * the index (firstElement) to the first element of the vector.
00150      * For example if <code>other</code> is a 3 dimensional vector, then
00151      * <code>castFrom(other,-1)</code> is a 3-elements-kernel which indices
00152      * lay inside [-1,1].
00153      * @param other the vector with the data to be copied
00154      * @param firstElement index for the first element of the vector
00155      * @return a reference to this instance
00156      */
00157     kernel1D<T>& castFrom(const vector<T>& other,
00158                           const int& firstElement = 0);
00159 
00160     /**
00161      * get offset position of element 0
00162      * @return the position of the element with index 0 in the memory array.
00163      *         This value is the same as -firstIdx()
00164      */
00165     int getOffset() const;
00166 
00167     /**
00168      * set offset position of element 0
00169      * @return the position of the element with index 0 in the memory array.
00170      *         This value is the same as -firstIdx()
00171      */
00172     void setOffset(const int& theOffset);
00173 
00174 
00175     /**
00176      * get normalization factor
00177      *
00178      * The normalization factor is used by the fixed point types as a
00179      * representation of the value 1.  For example, the norm for a
00180      * kernel1D<ubyte> can be 255, if the filter kernel don't need values
00181      * greater than 1.0.
00182      */
00183     inline const T& getNorm() const {
00184       return norm;
00185     }
00186 
00187     /**
00188      * set normalization factor
00189      * @see getNorm()
00190      */
00191     inline void setNorm(const T& n) {
00192       norm=n;
00193     };
00194 
00195     /**
00196      * denormalize divide all elements by norm and set the norm to 1!
00197      */
00198     void denormalize();
00199 
00200     /**
00201      * Mirror the other kernel and leave the result here, i.e.
00202      * at(x) = other.at(-x);
00203      * @param other the kernel to be copied and then mirrored
00204      * @return a reference to this instance
00205      */
00206     kernel1D<T>& mirror(const kernel1D<T>& other);
00207 
00208     /**
00209      * Mirror this kernel, i.e.
00210      * at(y,x) = at(-y,-x);
00211      * @return a reference to this instance
00212      */
00213     kernel1D<T>& mirror();
00214 
00215     /**
00216      * write the object in the given ioHandler
00217      */
00218     virtual bool write(ioHandler& handler,const bool complete = true) const;
00219 
00220     /**
00221      * read the object from the given ioHandler
00222      */
00223     virtual bool read(ioHandler& handler,const bool complete = true);
00224 
00225   protected:
00226     /**
00227      * Normalisation factor.
00228      *
00229      * This value will be ignored for floating point formats.
00230      * For fixed point formats, this value corresponds to 1.0
00231      */
00232     T norm;
00233   };
00234 
00235   template <class T>
00236     class sepKernel;
00237 
00238   /**
00239    * two-dimensional filter kernel
00240    *
00241    * The template type of this class should coincide with the template
00242    * class of the matrix or channel to be convolved with.  For
00243    * example, if you want to convolve a kernel2D with a channel8, you
00244    * will need a kernel2D<channel8::value_type> or
00245    * kernel2D<ubyte>. The offset of the kernel is at
00246    * int(columns()/2),int(rows()/2). This means that for kernels of
00247    * odd width and height, the origin (0,0) is exactly in the center,
00248    * while for kernels with even width and/or height, it is shifted
00249    * towards the upper left corner.
00250    *
00251    * If you instantiate a kernel2D of a fixed point type, like
00252    * kernel2D<int> or kernel2D<ubyte>, you also need to consider the
00253    * "norm" of the kernel (see lti::kernel2D<T>::getNorm() and
00254    * lti::kernel2D<T>::setNorm(const T&)). This "norm" allows the
00255    * representation of numbers less than 1.0.  You can see this norm as the
00256    * value to be consider as 1.0, when operating with the kernel.
00257    * For example, if you have a kernel2D<ubyte> with the values [64,128,64]
00258    * and norm=255, the the interpreted values during convolution will be
00259    * [0.25,0.5,0.25].  With floating-point types, the norm will be always
00260    * assumed to be 1.0.  For other types the default norms are the following:
00261    *
00262    * For int:              65536
00263    * For ubyte:              255
00264    * Otherwise:                1.0
00265    *
00266    * You can generate 2D kernels from separable ones using the
00267    * castFrom() method.  For example:
00268    *
00269    *  \code
00270    *  lti::gaussKernel2D<float> gauss(5); // a sepKernel 5x5 
00271    *  lti::kernel2D<float>      kern;     // a 2D kernel;
00272    *  
00273    *  kern.castFrom(gauss);
00274    *  \endcode   
00275    *
00276    * You can also use the outerProduct member to construct a 2D kernel from
00277    * two 1D ones:
00278    *
00279    *  \code
00280    *  lti::gaussKernel1D<float> colKern(3); // a 1D kernel
00281    *  lti::gaussKernel1D<float> rowKern(5); // another 1D kernel
00282    *
00283    *  lti::kernel2D<float>      kern;     // a 2D kernel;
00284    *  
00285    *  kern.outerProd(colKern,rowKern);    // outer product of both kernels
00286    *  \endcode   
00287    *
00288    * @see lti::convolution
00289    */
00290   template<class T>
00291   class kernel2D : public matrix<T> {
00292   public:
00293     /**
00294      * default constructor
00295      */
00296     kernel2D();
00297 
00298     /**
00299      * copy constructor
00300      * @param other the kernel to be copied
00301      */
00302     kernel2D(const kernel2D& other);
00303 
00304     /**
00305      * Create a new kernel of indicated size and initial value. The offset is
00306      * kept at zero.
00307      *
00308      * @param rows number of rows
00309      * @param columns number of columns
00310      * @param iniValue initial value of all elements
00311      */
00312     kernel2D(const int& rows, const int& columns, const T& iniValue = T());
00313 
00314     /**
00315      * Create a new kernel with indicated indices.
00316      *
00317      * @param fromRow index of the lower row of the kernel
00318      * @param fromCol index of the lower column of the kernel
00319      * @param toRow index of the higher row of the kernel
00320      * @param toCol index of the higher column of the kernel
00321      * @param iniValue the initial value for the elements of the kernel
00322      *
00323      * You can initialize a 5x3 kernel to filter a lti::channel with
00324      * following code:
00325      *
00326      * \code
00327      * lti::kernel2D<channel::value_type> aKernel(-1,-2,1,2,0);
00328      * aKernel.at(-1,-2)=0.2;
00329      * aKernel.at(-1,-1)=0.2;
00330      * aKernel.at(0,0)=0.2;
00331      * aKernel.at(1,1)=0.2;
00332      * aKernel.at(1,2)=0.2;
00333      * \endcode
00334      */
00335     kernel2D(const int& fromRow,const int& fromCol,
00336              const int& toRow,const int& toCol,
00337              const T& iniValue = T());
00338 
00339     /**
00340      * If \a init is true this constructor is equivalent to calling
00341      * kernel2D(const int& rows, const int& columns), and thus initializing
00342      * all elements with T(). However, in some cases the elements need
00343      * not be initialized during construction, since complex
00344      * initializion is required. Especially for large kernel2Ds, the
00345      * unnecessary constructor initialization is very time consuming.
00346      *
00347      * If \a init is false, memory is allocated but no initialization
00348      * takes place.
00349      *
00350      * @param init initialize matrix or not
00351      * @param rows number of rows
00352      * @param columns number of columns
00353      */
00354     kernel2D(const bool& init, const int& rows, const int& columns);
00355 
00356     /**
00357      * If \a init is true this constructor is equivalent to calling
00358      * kernel2D(const int& fromRow,const int& fromCol, const int&
00359      * toRow,const int& toCol), and thus initializing all elements
00360      * with T(). However, in some cases the elements need not be
00361      * initialized during construction, since complex initializion is
00362      * required. Especially for large kernel2Ds, the unnecessary
00363      * constructor initialization is very time consuming.
00364      *
00365      * If \a init is false, memory is allocated but no initialization
00366      * takes place.
00367      *
00368      * @param init initialize matrix or not
00369      * @param fromRow index of the lower row of the kernel
00370      * @param fromCol index of the lower column of the kernel
00371      * @param toRow index of the higher row of the kernel
00372      * @param toCol index of the higher column of the kernel
00373      */
00374     kernel2D(const bool& init, const int& fromRow,const int& fromCol,
00375              const int& toRow,const int& toCol);
00376 
00377     /**
00378      * destructor
00379      */
00380     virtual ~kernel2D();
00381 
00382     /**
00383      * copy member
00384      * @param other the kernel to be copied
00385      * @return a reference to this instance
00386      */
00387     kernel2D<T>& copy(const kernel2D<T>& other);
00388 
00389     /**
00390      * returns name of this type ("kernel2D")
00391      */
00392     const char* getTypeName() const {return "kernel2D";};
00393 
00394     /**
00395      * clone member
00396      * @return a pointer to a copy of this object
00397      */
00398     virtual mathObject* clone() const {
00399       return (new kernel2D<T>(*this));
00400     };
00401 
00402     /**
00403      * copy from kernel of different type
00404      * @param other a one dimensional kernel of another type
00405      * @return a reference to this instance
00406      */
00407     template<class U>
00408     kernel2D<T>& castFrom(const kernel2D<U>& other) {
00409       // implementation needs to be here due to bug in VC++
00410       matrix<T>::castFrom(other);
00411       offset = other.getOffset();
00412       norm = static_cast<T>(other.getNorm());
00413       return (*this);
00414     };
00415 
00416     /**
00417      * copy the content of the other matrix in this kernel and assign
00418      * the index (firstRow,firstColumn) to the first element of the matrix.
00419      * For example if <code>other</code> is a 3x3 matrix, then
00420      * <code>castFrom(other,-1,-1)</code> is a 3x3 kernel which indices
00421      * lay inside [-1,1].
00422      * @param other the matrix with the data to be copied
00423      * @param firstRow index for the first row of the matrix
00424      * @param firstColumn index for the first column of the matrix
00425      * @return a reference to this instance
00426      */
00427     kernel2D<T>& castFrom(const matrix<T>& other,
00428                           const int& firstRow,
00429                           const int& firstColumn);
00430 
00431     /**
00432      * copy the content of the other matrix in this kernel and assign
00433      * the index (firstRow,firstColumn) to the first element of the matrix.
00434      * For example if <code>other</code> is a 3x3 matrix, then
00435      * <code>castFrom(other,-1,-1)</code> is a 3x3 kernel which indices
00436      * lay inside [-1,1].
00437      * @param other the matrix with the data to be copied
00438      * @param firstElement index for the first element of the matrix
00439      * @return a reference to this instance
00440      */
00441     kernel2D<T>& castFrom(const matrix<T>& other,
00442                           const point& firstElement = point(0,0));
00443 
00444 
00445     /**
00446      * copy the contents of the other separable kernel in this
00447      * two-dimensional kernel
00448      */
00449     kernel2D<T>& castFrom(const sepKernel<T>& other);
00450 
00451     /**
00452      * resize kernel with indicated indexes
00453      *
00454      * @param fromRow index of the lower row of the kernel
00455      * @param fromCol index of the lower column of the kernel
00456      * @param toRow index of the higher row of the kernel
00457      * @param toCol index of the higher column of the kernel
00458      * @param iniValue the initial value for the elements of the kernel
00459      * @param copyData if true, keep data (see lti::matrix::resize())
00460      * @param initNew initialize new elements with the <code>iniValue</code>.
00461      *
00462      * You can initialize a 5x3 kernel to filter a lti::channel with
00463      * following code:
00464      *
00465      * \code
00466      * lti::kernel2D<channel::value_type> aKernel;
00467      * aKernel.resize(-1,-2,1,2,0,false);
00468      * aKernel.at(-1,-2)=0.2;
00469      * aKernel.at(-1,-1)=0.2;
00470      * aKernel.at(0,0)=0.2;
00471      * aKernel.at(1,1)=0.2;
00472      * aKernel.at(1,2)=0.2;
00473      * \endcode
00474      */
00475     void resize(const int& fromRow,const int& fromCol,
00476                 const int& toRow,const int& toCol,
00477     const T& iniValue = T(),
00478     const bool& copyData=true,
00479     const bool& initNew=true);
00480 
00481     /**
00482      * fills this kernel between the "from's" and "to's" with the
00483      * contents of the matrix <code>mat</code> starting at
00484      * <code>startAtRow</code> and <code>startAtCol</code>
00485      *
00486      * @param mat      the matrix with the data to be copied
00487      * @param fromRow  first row of the submatrix to be filled
00488      * @param fromCol  first column of the submatrix to be filled
00489      * @param toRow    last row of the submatrix to be filled
00490      * @param toCol    last column of the submatrix to be filled
00491      * @param startAtRow starting row of <code>mat</code> where the data is
00492      *                   located.
00493      * @param startAtCol starting column of <code>mat</code> where the data
00494      *                   is located.
00495      */
00496     void fill(const matrix<T>& mat,
00497               const int& fromRow= MinInt24,
00498               const int& fromCol= MinInt24,
00499               const int& toRow=   MaxInt24,
00500               const int& toCol=   MaxInt24,
00501               const int& startAtRow=0,
00502               const int& startAtCol=0);
00503 
00504     /**
00505      * fills this kernel between the "from's" and "to's" with the
00506      * contents of the matrix <code>mat</code> starting at
00507      * <code>startAtRow</code> and <code>startAtCol</code>
00508      *
00509      * @param data     the data that should fill this kernel
00510      * @param fromRow  first row of the submatrix to be filled
00511      * @param fromCol  first column of the submatrix to be filled
00512      * @param toRow    last row of the submatrix to be filled
00513      * @param toCol    last column of the submatrix to be filled
00514      */
00515     void fill(const T* data,
00516               const int& fromRow= MinInt24,
00517               const int& fromCol= MinInt24,
00518               const int& toRow=   MaxInt24,
00519               const int& toCol=   MaxInt24);
00520 
00521 
00522     /**
00523      * get normalization factor
00524      *
00525      * The normalization factor is used by the fixed point types as a
00526      * representation of the value 1.  For example, the norm for a
00527      * kernel1D<ubyte> can be 255, if the filter kernel don't need
00528      * values greater than 1.0.
00529      */
00530     inline const T& getNorm() const {
00531       return norm;
00532     };
00533 
00534     /**
00535      * set normalization factor
00536      * @see getNorm()
00537      */
00538     inline void setNorm(const T& n) {
00539       norm=n;
00540     }
00541 
00542     /**
00543      * returns offset, i.e. center of the filter-kernel
00544      * @return the position of the element with index 0 in the memory array.
00545      *         This value is the same as -firstIdx()
00546      */
00547     const point& getOffset() const;
00548 
00549     /**
00550      *  set kernel offset, i.e. center of the filter-kernel
00551      * @param p the position of the element with index (0,0) in the memory
00552      *          array.
00553      *          This value is the same as point(-firstRow(),-firstColumns()).
00554      */
00555     void setOffset(const point& p);
00556 
00557     /**
00558      * first row index
00559      */
00560     inline int firstRow() const {
00561       return -offset.y;
00562     };
00563 
00564     /**
00565      * last row index
00566      */
00567     inline int lastRow() const {
00568       return this->rows()-this->offset.y-1;
00569     }
00570 
00571     /**
00572      * first column index
00573      */
00574     inline int firstColumn() const {
00575       return -this->offset.x;
00576     }
00577 
00578     /**
00579      * last column index
00580      */
00581     inline int lastColumn() const {
00582       return this->columns()-this->offset.x-1;
00583     };
00584 
00585     /**
00586      * access operator with offset
00587      */
00588     inline T& at(const point& p) {
00589       return matrix<T>::at(p+this->offset);
00590     };
00591 
00592     /**
00593      * access operator with offset
00594      */
00595     inline const T& at(const point& p) const {
00596       return matrix<T>::at(p+offset);
00597     }
00598 
00599     /**
00600      * access operator with offset
00601      */
00602     inline T& at(const int& y,const int& x) {
00603       return matrix<T>::at(y+offset.y,x+offset.x);
00604     }
00605  
00606     /**
00607      * access operator with offset
00608      */
00609     inline const T& at(const int& y,const int& x) const {
00610       return matrix<T>::at(y+offset.y,x+offset.x);
00611     }
00612 
00613     /**
00614      * outer product of two kernel1D.
00615      * The first kernel is a column kernel and the second kernel is a
00616      * row kernel.
00617      *
00618      * @param colKernel column kernel
00619      * @param rowKernel row kernel
00620      * @return a reference to this kernel
00621      *
00622      * If you want to convert a separable kernel (lti::sepKernel<T>) into a
00623      * 2D kernel, see also the methods castFrom().
00624      *
00625      * The final kernel will contain colKernel.size() rows and rowKernel.size()
00626      * columns.  Each row will be equal to the rowKernel multiplied by the
00627      * respective colKernel element.
00628      */
00629     kernel2D<T>& outerProduct(const kernel1D<T>& colKernel,
00630             const kernel1D<T>& rowKernel);
00631 
00632     /**
00633      * denormalize divide all elements by norm and set the norm to 1!
00634      */
00635     void denormalize();
00636 
00637     /**
00638      * Mirror the other kernel and leave the result here, i.e.
00639      * at(y,x) = other.at(-y,-x);
00640      * @param other the kernel to be copied and then mirrored
00641      * @return a reference to this instance
00642      */
00643     kernel2D<T>& mirror(const kernel2D<T>& other);
00644 
00645     /**
00646      * Mirror this kernel, i.e.
00647      * at(y,x) = at(-y,-x);
00648      * @return a reference to this instance
00649      */
00650     kernel2D<T>& mirror();
00651 
00652     /**
00653      * write the object in the given ioHandler
00654      */
00655     virtual bool write(ioHandler& handler,const bool complete = true) const;
00656 
00657     /**
00658      * read the object from the given ioHandler
00659      */
00660     virtual bool read(ioHandler& handler,const bool complete = true);
00661 
00662   protected:
00663     /**
00664      * absolute coordinates of the kernel point (0,0)
00665      */
00666     point offset;
00667 
00668     /** Normalisation factor.
00669         This value will be ignored for floating point formats.
00670         For fixed point formats, this value corresponds to 1.0 */
00671     T norm;
00672   };
00673 
00674   /**
00675    * Separable Kernel.
00676    *
00677    * A separable kernel is a %vector of one dimensional kernels.
00678    * If a two dimensional kernel can be separated, the convolution can be
00679    * applied in a very efficient way.
00680    *
00681    * A filter kernel K is called separable "in one pair", if the matrix
00682    * representation of K can be produced as an outer product of two
00683    * one-dimensional kernels Kx and Ky.
00684    *
00685    * The template type of this class should coincide with the template
00686    * class of the matrix or channel to be convolved with.
00687    * For example, if you want to convolve a sepKernel with a lti::channel, you
00688    * will need a sepKernel<channel::value_type> or sepKernel<float>.
00689    *
00690    * If you instantiate a sepKernel of a fixed point type, like
00691    * sepKernel<int> or sepKernel<ubyte>, you also need to consider the
00692    * "norm" of the kernel (see lti::sepKernel<T>::getNorm() and
00693    * lti::sepKernel<T>::setNorm(const T&)). This "norm" allows the
00694    * representation of numbers less than 1.0.  You can see this norm as the
00695    * value to be consider as 1.0, when operating with the kernel.
00696    * For example, if you have a sepKernel<ubyte> with the values [64,128,64]
00697    * and norm=255, the the interpreted values during convolution will be
00698    * [0.25,0.5,0.25].  With floating-point types, the norm will be always
00699    * assumed to be 1.0.  For other types the default norms are the following:
00700    * (see lti::typeInfo)
00701    *
00702    * - For int:              65536
00703    * - For ubyte:              255
00704    * - Otherwise:              1.0
00705    *
00706    * @see convolution
00707    *
00708    */
00709   template<class T>
00710   class sepKernel : public mathObject {
00711   public:
00712     /**
00713      * default constructor
00714      */
00715     sepKernel();
00716 
00717     /**
00718      * copy constructor
00719      * @param other the kernel to be copied.
00720      */
00721     sepKernel(const sepKernel& other);
00722 
00723     /**
00724      * construct a separable kernel with one filter pair, all elements
00725      * of the subfilters initialized with the given value.
00726      * @param from first index of the one dimensional filter kernel
00727      * @param to   last index of the one dimensional filter kernel
00728      * @param iniValue initial value for the kernel elements
00729      */
00730     sepKernel(const int& from,const int& to,const T& iniValue=T());
00731 
00732     /**
00733      * construct a symmetrical separable kernel
00734      *
00735      * The resulting separable kernel will have just one filter pair, where
00736      * the row and column filters are identical.
00737      *
00738      * @param subkernel the one-dimensional kernel to be used as row and
00739      *                  column filter.
00740      */
00741     sepKernel(const kernel1D<T>& subkernel);
00742 
00743     /**
00744      * destructor
00745      */
00746     virtual ~sepKernel();
00747 
00748     /**
00749      * copy member
00750      * @param other the kernel to be copied.
00751      * @return a reference to this instance
00752      */
00753     sepKernel& copy(const sepKernel& other);
00754 
00755     /**
00756      * returns name of this type ("sepKernel")
00757      */
00758     const char* getTypeName() const {return "sepKernel";};
00759 
00760     /**
00761      * clone member
00762      * @return a pointer to a copy of this instance
00763      */
00764     virtual mathObject* clone() const {
00765       return (new sepKernel<T>(*this));
00766     };
00767 
00768     /**
00769      * copy from kernel of another type
00770      * @param other a separable kernel of another type
00771      * @return a reference to this instance
00772      */
00773     template<class U>
00774     sepKernel& castFrom(const sepKernel<U>& other) {
00775       // implementation needs to be here due to VC++ bug
00776       rowKernels.resize(other.getNumberOfPairs());
00777       colKernels.resize(other.getNumberOfPairs());
00778       for (int i=0;i<other.getNumberOfPairs();i++) {
00779   rowKernels[i].castFrom(other.getRowFilter(i));
00780   colKernels[i].castFrom(other.getColFilter(i));
00781       }
00782       return (*this);
00783     }
00784 
00785     /**
00786      * separate a 2D kernel into 1D kernels
00787      *
00788      * Try to separate the two dimensional kernel <code>k</code>.  Stop the
00789      * separation if the error between original and separated kernel is less
00790      * than <code>maxDev</code>.
00791      *
00792      * @param k the two dimensional filter to be separated
00793      * @param maxDev the maximal deviation per element to be achieved
00794      * @return true if the separation succeeded or false otherwise.
00795      */
00796     bool separate(const kernel2D<T>& k,const double &maxDev=0.01);
00797 
00798     /**
00799      * number of filter pairs
00800      */
00801     int getNumberOfPairs() const;
00802 
00803     /**
00804      * set the number of column/row 1D-filters
00805      */
00806     void setNumberOfPairs(const int& numPairs);
00807 
00808     /**
00809      * return a row-kernel
00810      * @param i the index of the row filter.  This value must be between
00811      *        0 and getNumberOfPairs()
00812      */
00813     inline kernel1D<T>& getRowFilter(const int& i) {
00814       // check for limits
00815       assert(i<static_cast<int>(rowKernels.size()));
00816       return rowKernels[i];
00817     };
00818 
00819     /**
00820      * return a column-kernel
00821      * @param i the index of the column filter.  This value must be between
00822      *        0 and getNumberOfPairs()
00823      */
00824     inline kernel1D<T>& getColFilter(const int& i) {
00825       // check for limits
00826       assert(i<static_cast<int>(colKernels.size()));
00827       return colKernels[i];      
00828     };
00829 
00830     /**
00831      * return an unmodifiable row kernel
00832      * @param i the index of the row filter.  This value must be between
00833      *        0 and getNumberOfPairs()
00834      */
00835     inline const kernel1D<T>& getRowFilter(const int& i) const {
00836       // check for limits
00837       assert(i<static_cast<int>(rowKernels.size()));
00838       return rowKernels[i];
00839     }
00840 
00841     /**
00842      * return an unmodifiable column kernel
00843      * @param i the index of the column filter.  This value must be between
00844      *        0 and getNumberOfPairs()
00845      */
00846     inline const kernel1D<T>& getColFilter(const int& i) const {
00847       // check for limits
00848       assert(i<static_cast<int>(colKernels.size()));
00849       return colKernels[i];
00850     };
00851 
00852     /**
00853      * denormalize divide all elements by norm and set the norm to 1!
00854      */
00855     void denormalize();
00856 
00857     /**
00858      * multiply each 1D kernel with a constant value
00859      * @param value the value to be multiplied with
00860      * @return a reference to this object
00861      */
00862     sepKernel<T>& multiply(const T& value);
00863 
00864     /**
00865      * set the norm of each individual 1D kernel to the given value
00866      * @param newNorm the value to be used as norm
00867      * @return a reference to this object
00868      */
00869     void setNorm(const T& newNorm);
00870 
00871     /**
00872      * returns the sum of the elements of the resulting 2D kernel
00873      */
00874     T sumOfElements() const;
00875 
00876     /**
00877      * Mirror the other kernel and leave the result here, i.e.
00878      * at(y,x) = other.at(-y,-x);
00879      * @param other the kernel to be copied and then mirrored
00880      * @return a reference to this instance
00881      */
00882     sepKernel<T>& mirror(const sepKernel<T>& other);
00883 
00884     /**
00885      * Mirror this kernel, i.e.
00886      * at(y,x) = at(-y,-x);
00887      * @return a reference to this instance
00888      */
00889     sepKernel<T>& mirror();
00890 
00891     /**
00892      * write the object in the given ioHandler
00893      */
00894     virtual bool write(ioHandler& handler,const bool complete = true) const;
00895 
00896     /**
00897      * read the object from the given ioHandler
00898      */
00899     virtual bool read(ioHandler& handler,const bool complete = true);
00900 
00901     /**
00902      * @name Apply Methods
00903      */
00904     //@{
00905 
00906     /**
00907      * applies a C-function to each element of the kernel.
00908      * 
00909      * In the following example, kernel \a kernel is initialized with
00910      * 4.0. After applying \a sqrt(), all elements of \a kernel are 2.0.
00911      * \code
00912      * sepKernel<float> kern(-2,2,4.0);
00913      * kern.apply(sqrt);
00914      * \endcode
00915      * @param function a pointer to a C-function
00916      * @return a reference to the actual kernel
00917      */
00918     sepKernel<T>& apply(T (*function)(T));
00919 
00920     /**
00921      * applies a C-function to each element of the kernel.
00922      * @param function a pointer to a C-function
00923      * @return a reference to the actual kernel
00924      */
00925     sepKernel<T>& apply(T (*function)(const T&));
00926 
00927     /**
00928      * applies a C-function to each element of the other kernel and leaves
00929      * the result here.
00930      * @param other the source kernel
00931      * @param function a pointer to a C-function
00932      * @return a reference to the actual kernel
00933      */
00934     sepKernel<T>& apply(const sepKernel<T>& other,T (*function)(T));
00935 
00936 
00937     /**
00938      * applies a C-function to each element the other kernel and
00939      * leaves the result here.
00940      * @param other the kernel with the source data
00941      * @param function a pointer to a C-function
00942      * @return a reference to the actual kernel
00943      */
00944     sepKernel<T>& apply(const sepKernel<T>& other,T (*function)(const T&));
00945 
00946     //@}
00947 
00948   protected:
00949     /**
00950      * list of one-dimensional row kernels
00951      */
00952     std::vector< kernel1D<T> > rowKernels;
00953 
00954     /**
00955      * list of one-dimensional column kernels
00956      */
00957     std::vector< kernel1D<T> > colKernels;
00958 
00959   };
00960 
00961   // ----------------------------------------------------------
00962   //   Typical used types
00963   // ----------------------------------------------------------
00964 
00965   /**
00966    * one dimensional kernel of integers
00967    */
00968   typedef kernel1D<int>    ikernel1D;
00969 
00970   /**
00971    * one dimensional kernel of floats
00972    */
00973   typedef kernel1D<float>  fkernel1D;
00974 
00975   /**
00976    * one dimensional kernel of doubles
00977    */
00978   typedef kernel1D<double> dkernel1D;
00979 
00980   /**
00981    * one dimensional kernel of unsigned bytes
00982    */
00983   typedef kernel1D<ubyte>  bkernel1D;
00984 
00985   /**
00986    * two dimensional kernel of integers
00987    */
00988   typedef kernel2D<int>    ikernel2D;
00989 
00990   /**
00991    * two dimensional kernel of floats
00992    */
00993   typedef kernel2D<float>  fkernel2D;
00994 
00995   /**
00996    * two dimensional kernel of doubles
00997    */
00998   typedef kernel2D<double> dkernel2D;
00999 
01000   /**
01001    * two dimensional kernel of bkernel
01002    */
01003   typedef kernel2D<ubyte>  bkernel2D;
01004 
01005   /**
01006    * separable kernel of integers
01007    */
01008   typedef sepKernel<int>    isepKernel;
01009 
01010   /**
01011    * separable kernel of floats
01012    */
01013   typedef sepKernel<float>  fsepKernel;
01014 
01015   /**
01016    * separable kernel of doubles
01017    */
01018   typedef sepKernel<double> dsepKernel;
01019 
01020   /**
01021    * separable kernel of unsigned bytes
01022    */
01023   typedef sepKernel<ubyte>  bsepKernel;
01024 
01025 
01026 }
01027 
01028 #endif

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