latest version v1.9 - last update 10 Apr 2010 |
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