latest version v1.9 - last update 10 Apr 2010 |
00001 /* 00002 * Copyright (C) 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-Lib: Image Processing and Computer Vision Library 00026 * file .......: ltiGuyMedioniSaliency.h 00027 * authors ....: Pablo Alvarado 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 19.5.2003 00030 * revisions ..: $Id: ltiGuyMedioniSaliency.h,v 1.8 2006/02/08 11:14:08 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_GUY_MEDIONI_SALIENCY_H_ 00034 #define _LTI_GUY_MEDIONI_SALIENCY_H_ 00035 00036 00037 #include "ltiSaliency.h" 00038 #include "ltiBilinearInterpolator.h" 00039 #include "ltiArctanLUT.h" 00040 00041 namespace lti { 00042 /** 00043 * The Guy-Medioni saliency is a procedure for perceptual grouping of 00044 * low level features like points and edges. 00045 * 00046 * For this task it computes first a extension field, an based on it 00047 * a saliency map, where only perceptual relevant features survive, or 00048 * illusory ones appear. 00049 * 00050 * As input it expects the output of an orientation map, with a 00051 * relevance channel and an orientation channel. The relevance can 00052 * be replaced by an edge map. With a threshold-parameter you can 00053 * decide how much relevant a pixel must be in order to be considered in 00054 * the saliency map. 00055 * 00056 * The original theory can be found in: 00057 * 00058 * G. Guy and G. Medioni. 00059 * "Inferring global perceptual contours from local features" 00060 * International Journal of Computer Vision, Vol.20, No.1/2, 1996, 00061 * pp. 113-133 00062 * 00063 * http://citeseer.nj.nec.com/guy96inferring.html 00064 * 00065 * Example: 00066 * \code 00067 * lti::image img; 00068 * lti::channel chnl,rel,ori; 00069 * lti::channel sal,sala; 00070 * lti::channel8 rel8; 00071 * float maxSal; 00072 * 00073 * // load an image (suppose you have one in the directory ../img/ called 00074 * // image1.bmp) 00075 * lti::loadImage loader; 00076 * loader.load("../img/image1.bmp",img); 00077 * chnl.castFrom(img); // convert the color image into a gray valued one 00078 * 00079 * // get the edges and orientation channels 00080 * lti::cannyEdges canny; 00081 * canny.apply(chnl,rel8,ori); 00082 * rel.castFrom(rel8); 00083 * 00084 * // get the Guy-Medioni saliency (sal) and the orientation (sala) 00085 * // and the maximal value found in the sal channel (maxSal). 00086 * lti::guyMedioniSaliency gmSaliency; 00087 * gmSaliency.apply(rel,ori,sal,sala,maxSal); 00088 * \endcode 00089 * 00090 * The saliency channel is somehow blurred. You can use the 00091 * lti::nonMaximaSuppression to get again an edge channel from the saliency: 00092 * 00093 * \code 00094 * lti::channel8 newEdges; 00095 * lti::nonMaximaSuppression suppressor; 00096 * suppressor.apply(sal,sala,newEdges,maxSal); 00097 * \endcode 00098 */ 00099 class guyMedioniSaliency : public saliency { 00100 public: 00101 /** 00102 * the parameters for the class guyMedioniSaliency 00103 */ 00104 class parameters : public saliency::parameters { 00105 public: 00106 /** 00107 * default constructor 00108 */ 00109 parameters(); 00110 00111 /** 00112 * copy constructor 00113 * @param other the parameters object to be copied 00114 */ 00115 parameters(const parameters& other); 00116 00117 /** 00118 * destructor 00119 */ 00120 ~parameters(); 00121 00122 /** 00123 * returns name of this type 00124 */ 00125 const char* getTypeName() const; 00126 00127 /** 00128 * copy the contents of a parameters object 00129 * @param other the parameters object to be copied 00130 * @return a reference to this parameters object 00131 */ 00132 parameters& copy(const parameters& other); 00133 00134 /** 00135 * copy the contents of a parameters object 00136 * @param other the parameters object to be copied 00137 * @return a reference to this parameters object 00138 */ 00139 parameters& operator=(const parameters& other); 00140 00141 00142 /** 00143 * returns a pointer to a clone of the parameters 00144 */ 00145 virtual functor::parameters* clone() const; 00146 00147 /** 00148 * write the parameters in the given ioHandler 00149 * @param handler the ioHandler to be used 00150 * @param complete if true (the default) the enclosing begin/end will 00151 * be also written, otherwise only the data block will be written. 00152 * @return true if write was successful 00153 */ 00154 virtual bool write(ioHandler& handler,const bool complete=true) const; 00155 00156 /** 00157 * read the parameters from the given ioHandler 00158 * @param handler the ioHandler to be used 00159 * @param complete if true (the default) the enclosing begin/end will 00160 * be also written, otherwise only the data block will be written. 00161 * @return true if write was successful 00162 */ 00163 virtual bool read(ioHandler& handler,const bool complete=true); 00164 00165 # ifdef _LTI_MSC_6 00166 /** 00167 * this function is required by MSVC only, as a workaround for a 00168 * very awful bug, which exists since MSVC V.4.0, and still by 00169 * V.6.0 with all bugfixes (so called "service packs") remains 00170 * there... This method is also public due to another bug, so please 00171 * NEVER EVER call this method directly: use read() instead 00172 */ 00173 bool readMS(ioHandler& handler,const bool complete=true); 00174 00175 /** 00176 * this function is required by MSVC only, as a workaround for a 00177 * very awful bug, which exists since MSVC V.4.0, and still by 00178 * V.6.0 with all bugfixes (so called "service packs") remains 00179 * there... This method is also public due to another bug, so please 00180 * NEVER EVER call this method directly: use write() instead 00181 */ 00182 bool writeMS(ioHandler& handler,const bool complete=true) const; 00183 # endif 00184 00185 // ------------------------------------------------ 00186 // the parameters 00187 // ------------------------------------------------ 00188 00189 /** 00190 * Parameter used in the creation of the Extension Field. 00191 * It controls the curvature decay, and was named \c B in the original 00192 * paper. This value must be greater than zero. 00193 * 00194 * Default value: 2.85f 00195 */ 00196 float highCurvatureDecay; 00197 00198 /** 00199 * Parameter used in the creation of the Extension Field. 00200 * It controls the proximity decay, and was named \c A in the original 00201 * paper. This number must be greater than zero. 00202 * 00203 * Default value: 0.003f 00204 */ 00205 float proximityDecay; 00206 00207 /** 00208 * Percentage of the maximum value in the relevance channel that 00209 * a pixel must reach in order to be considered for the saliency 00210 * computation. Values must be between 0.0f and 1.0f. 00211 * 00212 * Default value: 0.1f (i.e. 10% of maximum necessary) 00213 */ 00214 float threshold; 00215 00216 /** 00217 * In case threshold is too low, do not allow the field radius 00218 * become bigger than the given value. 00219 * 00220 * Default value: 128 00221 */ 00222 int maxFieldRadius; 00223 00224 /** 00225 * Field Threshold 00226 * 00227 * The extension field will be computed in a discrete grid. Depending 00228 * on the highCurvatureDecay and proximityDecay values, the size of 00229 * the grid needs to be adapted. This threshold determines which values 00230 * cannot be neglected and therefore controls the size (and indirectly 00231 * speed) of the algorithm. More precisely, this value determinies the 00232 * the minimum valid value of the x-coordinate. 00233 * 00234 * This value must be greater than 0 and less than 1 00235 * 00236 * Default value: 0.1f; (With default values, about 57x57 kernel) 00237 */ 00238 float fieldThreshold; 00239 }; 00240 00241 /** 00242 * default constructor 00243 */ 00244 guyMedioniSaliency(); 00245 00246 /** 00247 * Construct a functor using the given parameters 00248 */ 00249 guyMedioniSaliency(const parameters& par); 00250 00251 /** 00252 * copy constructor 00253 * @param other the object to be copied 00254 */ 00255 guyMedioniSaliency(const guyMedioniSaliency& other); 00256 00257 /** 00258 * destructor 00259 */ 00260 virtual ~guyMedioniSaliency(); 00261 00262 /** 00263 * returns the name of this type ("guyMedioniSaliency") 00264 */ 00265 virtual const char* getTypeName() const; 00266 00267 /** 00268 * Generates the raw saliency and junction saliency maps using 00269 * Guy-Medioni's approach. 00270 * 00271 * To obtain the final saliency it is more efficient to use the alternative 00272 * apply() method than to subtract both lambda channels. 00273 * 00274 * @param edgeRelevance Relevance for each pixel. It can be an edge image. 00275 * @param orientation Orientation of each pixel. Please note that 00276 * the orientation channel expected by this functor 00277 * contains the angle perpendicular to the edgels 00278 * as returned by the gradient or orientationMap 00279 * functors. 00280 * @param saliencyLambdaX resulting major eigenvalue: raw saliency. 00281 * @param saliencyLambdaY resulting minor eigenvalues: junction saliency. 00282 * @return true if apply successful or false otherwise. 00283 */ 00284 bool apply(const channel& edgeRelevance, 00285 const channel& orientation, 00286 channel& saliencyLambdaX, 00287 channel& saliencyLambdaY); 00288 00289 /** 00290 * Generates the enhanced saliency measure. 00291 * 00292 * This method is more efficient than to compute both lambda channels with 00293 * the alternative apply() method and to subtract them. 00294 * 00295 * @param edgeRelevance Relevance for each pixel. It can be an edge image. 00296 * @param orientation Orientation of each pixel. Please note that 00297 * the orientation channel expected by this functor 00298 * contains the angle perpendicular to the edgels 00299 * as returned by the gradient or orientationMap 00300 * functors. 00301 * @param saliency resulting saliency channel. 00302 * @return true if apply successful or false otherwise. 00303 * 00304 * \warning The orientation channel expected differs from the one returned 00305 * by orientation map functors. It must represent the real 00306 * direction of the edgels instead of the direction perpendicular 00307 * to them. 00308 */ 00309 bool apply(const channel& edgeRelevance, 00310 const channel& orientation, 00311 channel& saliency); 00312 00313 00314 /** 00315 * Generates the enhanced saliency measure. 00316 * 00317 * This method is more efficient than to compute both lambda channels with 00318 * the alternative apply() method and to subtract them. 00319 * 00320 * @param edgeRelevance Relevance for each pixel. It can be an edge image. 00321 * @param orientation Orientation of each pixel. Please note that 00322 * the orientation channel expected by this functor 00323 * contains the angle perpendicular to the edgels 00324 * as returned by the gradient or orientationMap 00325 * functors. 00326 * @param saliency resulting saliency channel. 00327 * @param angle resulting direction for each pixel 00328 * @param maxSaliency maximum saliency value. 00329 * @return true if apply successful or false otherwise. 00330 * 00331 * \warning The orientation channel expected differs from the one returned 00332 * by orientation map functors. It must represent the real 00333 * direction of the edgels instead of the direction perpendicular 00334 * to them. 00335 */ 00336 bool apply(const channel& edgeRelevance, 00337 const channel& orientation, 00338 channel& saliency, 00339 channel& angle, 00340 float& maxSaliency); 00341 00342 /** 00343 * Return a read only copy of the x component of the extension field. 00344 * The returned field component will be updated after setParameters(). 00345 */ 00346 const matrix<float>& getExtensionFieldX() const; 00347 00348 /** 00349 * Return a read only copy of the y component of the extension field. 00350 * The returned field component will be updated after setParameters(). 00351 */ 00352 const matrix<float>& getExtensionFieldY() const; 00353 00354 /** 00355 * Return a read only copy of the magnitude of the extension field. 00356 * The returned field component will be updated after setParameters(). 00357 */ 00358 const matrix<float>& getExtensionFieldM() const; 00359 00360 /** 00361 * copy data of "other" functor. 00362 * @param other the functor to be copied 00363 * @return a reference to this functor object 00364 */ 00365 guyMedioniSaliency& copy(const guyMedioniSaliency& other); 00366 00367 /** 00368 * alias for copy member 00369 * @param other the functor to be copied 00370 * @return a reference to this functor object 00371 */ 00372 guyMedioniSaliency& operator=(const guyMedioniSaliency& other); 00373 00374 /** 00375 * returns a pointer to a clone of this functor. 00376 */ 00377 virtual functor* clone() const; 00378 00379 /** 00380 * returns used parameters 00381 */ 00382 const parameters& getParameters() const; 00383 00384 /** 00385 * Update functor's parameters. 00386 * 00387 * This member updates the internal fields according to the values 00388 * set in the parameters. 00389 * 00390 * @return true if successful, false otherwise 00391 */ 00392 virtual bool updateParameters(); 00393 00394 protected: 00395 /** 00396 * @name Extension Field 00397 */ 00398 //@{ 00399 00400 /** 00401 * generate extension field 00402 * 00403 * Based on the parameters object, a "kernel" oriented with 0 degrees 00404 * will be constructed. 00405 * 00406 */ 00407 bool generateExtensionField(); 00408 00409 /** 00410 * Accumulate the extension field components on the saliency map 00411 * considering the given position, angle and weight. 00412 * 00413 * The saliency fields must be previously initialized 00414 */ 00415 void vote(const point p,const float angle,const float weight); 00416 00417 /** 00418 * x component of the extension field currently used 00419 */ 00420 matrix<float> extensionFieldX; 00421 00422 /** 00423 * y component of the extension field currently used 00424 */ 00425 matrix<float> extensionFieldY; 00426 00427 /** 00428 * Magnitude of the extension field currently used 00429 */ 00430 matrix<float> extensionFieldM; 00431 00432 00433 /** 00434 * interpolator for extensionFieldX 00435 */ 00436 bilinearInterpolator<float> ifieldX; 00437 00438 /** 00439 * interpolator for extensionFieldY 00440 */ 00441 bilinearInterpolator<float> ifieldY; 00442 00443 /** 00444 * Center of the extension field 00445 */ 00446 point extFieldCenter; 00447 00448 /** 00449 * Extension field radius 00450 */ 00451 int extFieldRadius; 00452 00453 /** 00454 * Matrix containing the ioPoints of a circle covering the relevant 00455 * extension field 00456 */ 00457 imatrix extFieldCircle; 00458 00459 /** 00460 * Threshold for the extension field magnitude 00461 */ 00462 float fieldThreshold; 00463 00464 //@} 00465 00466 /** 00467 * @name Saliency Accumulators 00468 * 00469 * Six accumulators are necessary to compute the saliency 00470 */ 00471 //@{ 00472 00473 /** 00474 * sum of the x^2 components 00475 */ 00476 matrix<float> sumx2; 00477 00478 /** 00479 * sum of the y^2 components 00480 */ 00481 matrix<float> sumy2; 00482 00483 /** 00484 * sum of the xy components 00485 */ 00486 matrix<float> sumxy; 00487 //@} 00488 00489 /** 00490 * compute the first step of the saliency, accumulating the fields 00491 * of each edge-element. 00492 */ 00493 void accumulate(const channel& edgeRelevance, 00494 const channel& orientation, 00495 const float threshold); 00496 00497 /** 00498 * From the accumulated members compute the saliency components. 00499 */ 00500 void getSaliency(channel& salLambdaMax, 00501 channel& salLambdaMin); 00502 00503 /** 00504 * From the accumulated members compute the saliency components. 00505 */ 00506 void getSaliency(channel& sal); 00507 00508 /** 00509 * From the accumulated members compute the saliency components. 00510 */ 00511 void getSaliency(channel& sal,channel& angle,float& maxSaliency); 00512 00513 /** 00514 * Look up table for sin values 00515 */ 00516 //static const float* sinLUT; 00517 00518 /** 00519 * Look up table for cos values 00520 */ 00521 //static const float* cosLUT; 00522 00523 /** 00524 * LUT to compute the arc tangent 00525 */ 00526 arctanLUT atan2; 00527 00528 }; 00529 } 00530 00531 #endif