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

ltiGuyMedioniSaliency.h

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

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