last update 20 Sep 2009 |
00001 /* 00002 * Copyright (C) 1998-2004 00003 * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany 00004 * 00005 * 00006 * This file is part of the Computer Vision and Robotics Library (CVR-Lib) 00007 * 00008 * The CVR-Lib is free software; you can redistribute it and/or 00009 * modify it under the terms of the BSD License. 00010 * 00011 * All rights reserved. 00012 * 00013 * Redistribution and use in source and binary forms, with or without 00014 * modification, are permitted provided that the following conditions are met: 00015 * 00016 * 1. Redistributions of source code must retain the above copyright notice, 00017 * this list of conditions and the following disclaimer. 00018 * 00019 * 2. Redistributions in binary form must reproduce the above copyright notice, 00020 * this list of conditions and the following disclaimer in the documentation 00021 * and/or other materials provided with the distribution. 00022 * 00023 * 3. Neither the name of the authors nor the names of its contributors may be 00024 * used to endorse or promote products derived from this software without 00025 * specific prior written permission. 00026 * 00027 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00028 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00029 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00030 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00031 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00032 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00033 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00034 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00035 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00036 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00037 * POSSIBILITY OF SUCH DAMAGE. 00038 */ 00039 00040 /** 00041 * \file cvrSeparableKernel.h 00042 * Contains the template class seperableKernel<T> 00043 * \author Pablo Alvarado 00044 * \date 28.04.2000 00045 * 00046 * $Id: cvrSeparableKernel.h,v 1.7 2006/09/05 09:10:38 doerfler Exp $ 00047 */ 00048 00049 #ifndef _CVR_SEPARABLE_KERNEL_H_ 00050 #define _CVR_SEPARABLE_KERNEL_H_ 00051 00052 #include "cvrKernel1D.h" 00053 #include "cvrKernel2D.h" 00054 #include "cvrTypes.h" 00055 00056 #include <vector> 00057 00058 namespace cvr { 00059 00060 /** 00061 * Separable Kernel. 00062 * 00063 * A separable kernel is a %vector of one dimensional kernels. 00064 * If a two dimensional kernel can be separated, the convolution can be 00065 * applied in a very efficient way. 00066 * 00067 * A filter kernel K is called separable "in one pair", if the matrix 00068 * representation of K can be produced as an outer product of two 00069 * one-dimensional kernels Kx and Ky. 00070 * 00071 * The template type of this class should coincide with the template class of 00072 * the matrix or channel to be convolved with. For example, if you want to 00073 * convolve a separableKernel with a cvr::channel, you will need a 00074 * separableKernel<channel::value_type> or separableKernel<float>. 00075 * 00076 * If you instantiate a separableKernel of a fixed point type, like 00077 * separableKernel<int> or separableKernel<ubyte>, you also need to consider 00078 * the "norm" of the kernel (see cvr::separableKernel<T>::getNorm() and 00079 * cvr::separableKernel<T>::setNorm(const T&)). This "norm" allows the 00080 * representation of numbers less than 1.0. You can see this norm as the 00081 * value to be consider as 1.0, when operating with the kernel. For example, 00082 * if you have a separableKernel<ubyte> with the values [64,128,64] and 00083 * norm=255, the the interpreted values during convolution will be 00084 * [0.25,0.5,0.25]. With floating-point types, the norm will be always 00085 * assumed to be 1.0. For other types the default norms are the following: 00086 * (see cvr::typeInfo) 00087 * 00088 * - For int: 65536 00089 * - For ubyte: 255 00090 * - Otherwise: 1.0 00091 * 00092 * @see convolution 00093 * 00094 */ 00095 template<class T> 00096 class separableKernel : public container { 00097 protected: 00098 /** 00099 * A pair of 1D kernels 00100 */ 00101 struct kernelPair { 00102 /** 00103 * Row kernel 00104 */ 00105 kernel1D<T> row; 00106 00107 /** 00108 * Column kernel 00109 */ 00110 kernel1D<T> column; 00111 }; 00112 00113 public: 00114 /** 00115 * Default constructor 00116 */ 00117 separableKernel(); 00118 00119 /** 00120 * Copy constructor 00121 * @param other the kernel to be copied. 00122 */ 00123 separableKernel(const separableKernel& other); 00124 00125 /** 00126 * Construct a separable kernel with one filter pair, all elements 00127 * of the subfilters initialized with the given value. 00128 * @param from first index of the one dimensional filter kernel 00129 * @param to last index of the one dimensional filter kernel 00130 * @param iniValue initial value for the kernel elements 00131 */ 00132 separableKernel(const int from,const int to,const T& iniValue=T()); 00133 00134 /** 00135 * Construct a symmetrical separable kernel 00136 * 00137 * The resulting separable kernel will have just one filter pair, where 00138 * the row and column filters are identical. 00139 * 00140 * @param subkernel the one-dimensional kernel to be used as row and 00141 * column filter. 00142 */ 00143 separableKernel(const kernel1D<T>& subkernel); 00144 00145 /** 00146 * Destructor 00147 */ 00148 virtual ~separableKernel(); 00149 00150 /** 00151 * Copy member 00152 * @param other the kernel to be copied. 00153 * @return a reference to this instance 00154 */ 00155 separableKernel& copy(const separableKernel& other); 00156 00157 /** 00158 * Returns the name of this type 00159 */ 00160 virtual const std::string& name() const; 00161 00162 /** 00163 * Clone member 00164 * @return a pointer to a copy of this instance 00165 */ 00166 virtual separableKernel* clone() const; 00167 00168 00169 /** 00170 * Return a new instance of a separable kernel 00171 * @return a pointer to a new instance 00172 */ 00173 virtual separableKernel* newInstance() const; 00174 00175 /** 00176 * Copy from kernel of another type 00177 * @param other a separable kernel of another type 00178 * @return a reference to this instance 00179 */ 00180 template<class U> 00181 separableKernel& castFrom(const separableKernel<U>& other) { 00182 // implementation needs to be here due to VC++ bug 00183 kernels_.resize(other.getNumberOfPairs()); 00184 for (unsigned int i=0;i<kernels_.size();i++) { 00185 kernels_[i].row.castFrom(other.getRowFilter(i)); 00186 kernels_[i].column.castFrom(other.getColumnFilter(i)); 00187 } 00188 return (*this); 00189 } 00190 00191 /** 00192 * Separate a 2D kernel into 1D kernels 00193 * 00194 * Try to separate the two dimensional kernel \a k. Stop the 00195 * separation if the error between original and separated kernel is less 00196 * than \a maxDev. 00197 * 00198 * @param k the two dimensional filter to be separated 00199 * @param maxDev the maximal deviation per element to be achieved 00200 * @return true if the separation succeeded or false otherwise. 00201 */ 00202 bool separate(const kernel2D<T>& k,const double &maxDev=0.01); 00203 00204 /** 00205 * Number of filter pairs 00206 */ 00207 int getNumberOfPairs() const; 00208 00209 /** 00210 * Set the number of column/row 1D-filters 00211 */ 00212 void setNumberOfPairs(const int numPairs); 00213 00214 /** 00215 * Return a row-kernel 00216 * @param i the index of the row filter. This value must be between 00217 * 0 and getNumberOfPairs() 00218 */ 00219 inline kernel1D<T>& getRowFilter(const int i) { 00220 // check for limits 00221 assert(i<static_cast<int>(kernels_.size())); 00222 return kernels_[i].row; 00223 }; 00224 00225 /** 00226 * Return a column-kernel 00227 * @param i the index of the column filter. This value must be between 00228 * 0 and getNumberOfPairs() 00229 */ 00230 inline kernel1D<T>& getColumnFilter(const int i) { 00231 // check for limits 00232 assert(i<static_cast<int>(kernels_.size())); 00233 return kernels_[i].column; 00234 }; 00235 00236 /** 00237 * Return an unmodifiable row kernel 00238 * @param i the index of the row filter. This value must be between 00239 * 0 and getNumberOfPairs() 00240 */ 00241 inline const kernel1D<T>& getRowFilter(const int i) const { 00242 // check for limits 00243 assert(i<static_cast<int>(kernels_.size())); 00244 return kernels_[i].row; 00245 } 00246 00247 /** 00248 * Return an unmodifiable column kernel 00249 * @param i the index of the column filter. This value must be between 00250 * 0 and getNumberOfPairs() 00251 */ 00252 inline const kernel1D<T>& getColumnFilter(const int i) const { 00253 // check for limits 00254 assert(i<static_cast<int>(kernels_.size())); 00255 return kernels_[i].column; 00256 }; 00257 00258 /** 00259 * Normalize divides all elements by norm and set the norm to 1! 00260 */ 00261 void normalize(); 00262 00263 /** 00264 * Multiply each 1D kernel with a constant value 00265 * @param value the value to be multiplied with 00266 * @return a reference to this object 00267 */ 00268 separableKernel<T>& multiply(const T& value); 00269 00270 /** 00271 * Set the norm of each individual 1D kernel to the given value 00272 * @param newNorm the value to be used as norm 00273 * @return a reference to this object 00274 */ 00275 void setNorm(const T& newNorm); 00276 00277 /** 00278 * Returns the sum of the elements of the resulting 2D kernel 00279 */ 00280 T computeSumOfElements() const; 00281 00282 /** 00283 * Mirror the other kernel and leave the result here, i.e. 00284 * at(y,x) = other.at(-y,-x); 00285 * @param other the kernel to be copied and then mirrored 00286 * @return a reference to this instance 00287 */ 00288 separableKernel<T>& mirror(const separableKernel<T>& other); 00289 00290 /** 00291 * Mirror this kernel, i.e. 00292 * at(y,x) = at(-y,-x); 00293 * @return a reference to this instance 00294 */ 00295 separableKernel<T>& mirror(); 00296 00297 /** 00298 * Write the object in the given ioHandler 00299 */ 00300 virtual bool write(ioHandler& handler,const bool complete = true) const; 00301 00302 /** 00303 * Read the object from the given ioHandler 00304 */ 00305 virtual bool read(ioHandler& handler,const bool complete = true); 00306 00307 /** 00308 * @name Apply Methods 00309 */ 00310 //@{ 00311 00312 /** 00313 * Applies a C-function to each element of the kernel. 00314 * 00315 * In the following example, kernel \a kernel is initialized with 00316 * 4.0. After applying \a sqrt(), all elements of \a kernel are 2.0. 00317 * \code 00318 * separableKernel<float> kern(-2,2,4.0); 00319 * kern.apply(sqrt); 00320 * \endcode 00321 * @param function a pointer to a C-function 00322 * @return a reference to the actual kernel 00323 */ 00324 separableKernel<T>& apply(T (*function)(T)); 00325 00326 /** 00327 * Applies a C-function to each element of the kernel. 00328 * @param function a pointer to a C-function 00329 * @return a reference to the actual kernel 00330 */ 00331 separableKernel<T>& apply(T (*function)(const T&)); 00332 00333 /** 00334 * Applies a C-function to each element of the other kernel and leaves 00335 * the result here. 00336 * @param other the source kernel 00337 * @param function a pointer to a C-function 00338 * @return a reference to the actual kernel 00339 */ 00340 separableKernel<T>& apply(const separableKernel<T>& other, 00341 T (*function)(T)); 00342 00343 00344 /** 00345 * Applies a C-function to each element the other kernel and 00346 * leaves the result here. 00347 * 00348 * @param other the kernel with the source data 00349 * @param function a pointer to a C-function 00350 * @return a reference to the actual kernel 00351 */ 00352 separableKernel<T>& apply(const separableKernel<T>& other, 00353 T (*function)(const T&)); 00354 00355 //@} 00356 00357 protected: 00358 /** 00359 * List of one-dimensional row kernels 00360 */ 00361 std::vector< kernelPair > kernels_; 00362 }; 00363 00364 // ---------------------------------------------------------- 00365 // Typical used types 00366 // ---------------------------------------------------------- 00367 00368 /** 00369 * Separable kernel of integers 00370 */ 00371 typedef separableKernel<int> iseparableKernel; 00372 00373 /** 00374 * Separable kernel of floats 00375 */ 00376 typedef separableKernel<float> fseparableKernel; 00377 00378 /** 00379 * Separable kernel of doubles 00380 */ 00381 typedef separableKernel<double> dseparableKernel; 00382 00383 /** 00384 * Separable kernel of unsigned bytes 00385 */ 00386 typedef separableKernel<ubyte> bseparableKernel; 00387 00388 00389 // ---------------------------------------------------------- 00390 // stream output 00391 // ---------------------------------------------------------- 00392 00393 /** 00394 * outputs the separable kernel \p kern on a stream \p s. The kernel pairs 00395 * are printed in the order they are stored in the separable kernel: 00396 * 00397 * \code 00398 * (((first row kernel) 00399 * (first column kernel)) 00400 * ((second row kernel) 00401 * (second column kernel)) 00402 * ... 00403 * ((last row kernel) 00404 * (last column kerne))) 00405 * \endcode 00406 */ 00407 template <class T> 00408 std::ostream& operator<<(std::ostream& s, const separableKernel<T>& kern); 00409 00410 } 00411 00412 #endif 00413