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

ltiNonMaximaSuppression.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 .......: ltiNonMaximaSuppression.h
00027  * authors ....: Pablo Alvarado, Christian Harte
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 23.5.2003
00030  * revisions ..: $Id: ltiNonMaximaSuppression.h,v 1.11 2006/02/08 11:32:56 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_NON_MAXIMA_SUPPRESSION_H_
00034 #define _LTI_NON_MAXIMA_SUPPRESSION_H_
00035 
00036 #include "ltiTransform.h"
00037 #include "ltiPointList.h"
00038 
00039 namespace lti {
00040   /**
00041    * The non-maxima suppression is usually the last stage of edge
00042    * detectors (the most prominent example is the Canny Edge Detector,
00043    * see lti::cannyEdges), but it can also be employed in other
00044    * similar tasks, like detection of saliency edges from "structural"
00045    * saliency maps (see for example lti::guyMedioniSaliency).
00046    *
00047    * From a sort of "diffuse edge" channel, this functor tries first to find
00048    * all local maxima, and suppresses the rest.  In an optional
00049    * hysteresis stage, neighbor pixels of detected maxima can also
00050    * "survive" the suppression if their value exceeds a lower
00051    * threshold value.
00052    *
00053    * A similar class used in detection of local maxima is the lti::localMaxima.
00054    *
00055    * There are two way to given the thresholds.  The classical way is to give
00056    * them as a percentage of the maximal pixel value found in the image.  This
00057    * is the way usually described in the text-books when describing the last
00058    * stages of the Canny Edge Detection.
00059    *
00060    * This functor provides an additional (sometimes more robust way)
00061    * to select the thresholds.  It is an indirect way that computes
00062    * the threshold such that a given percentage of the total number of
00063    * pixels have a value above it.  It is a way to tell the functor
00064    * your expectation how many pixels in an image will be considered
00065    * edges, instead of telling which value the edges will have. 
00066    *
00067    * Some parameters will allow you to select which way of threshold
00068    * computation you prefer for the low- and high-thresholds.
00069    * 
00070    * @see parameters
00071    * @see localMaxima
00072    */
00073   class nonMaximaSuppression : public transform {
00074   public:
00075     /**
00076      * the parameters for the class nonMaximaSuppression
00077      */
00078     class parameters : public transform::parameters {
00079     public:
00080       /**
00081        * default constructor
00082        */
00083       parameters();
00084 
00085       /**
00086        * copy constructor
00087        * @param other the parameters object to be copied
00088        */
00089       parameters(const parameters& other);
00090 
00091       /**
00092        * destructor
00093        */
00094       ~parameters();
00095 
00096       /**
00097        * returns name of this type
00098        */
00099       const char* getTypeName() const;
00100 
00101       /**
00102        * copy the contents of a parameters object
00103        * @param other the parameters object to be copied
00104        * @return a reference to this parameters object
00105        */
00106       parameters& copy(const parameters& other);
00107 
00108       /**
00109        * copy the contents of a parameters object
00110        * @param other the parameters object to be copied
00111        * @return a reference to this parameters object
00112        */
00113       parameters& operator=(const parameters& other);
00114 
00115 
00116       /**
00117        * returns a pointer to a clone of the parameters
00118        */
00119       virtual functor::parameters* clone() const;
00120 
00121       /**
00122        * write the parameters in the given ioHandler
00123        * @param handler the ioHandler to be used
00124        * @param complete if true (the default) the enclosing begin/end will
00125        *        be also written, otherwise only the data block will be written.
00126        * @return true if write was successful
00127        */
00128       virtual bool write(ioHandler& handler,const bool complete=true) const;
00129 
00130       /**
00131        * read the parameters from the given ioHandler
00132        * @param handler the ioHandler to be used
00133        * @param complete if true (the default) the enclosing begin/end will
00134        *        be also written, otherwise only the data block will be written.
00135        * @return true if write was successful
00136        */
00137       virtual bool read(ioHandler& handler,const bool complete=true);
00138 
00139 #     ifdef _LTI_MSC_6
00140       /**
00141        * this function is required by MSVC only, as a workaround for a
00142        * very awful bug, which exists since MSVC V.4.0, and still by
00143        * V.6.0 with all bugfixes (so called "service packs") remains
00144        * there...  This method is also public due to another bug, so please
00145        * NEVER EVER call this method directly: use read() instead
00146        */
00147       bool readMS(ioHandler& handler,const bool complete=true);
00148 
00149       /**
00150        * this function is required by MSVC only, as a workaround for a
00151        * very awful bug, which exists since MSVC V.4.0, and still by
00152        * V.6.0 with all bugfixes (so called "service packs") remains
00153        * there...  This method is also public due to another bug, so please
00154        * NEVER EVER call this method directly: use write() instead
00155        */
00156       bool writeMS(ioHandler& handler,const bool complete=true) const;
00157 #     endif
00158 
00159       // ------------------------------------------------
00160       // the parameters
00161       // ------------------------------------------------
00162 
00163       /**
00164        * If a pixel is detected as part of an edge (a response higher
00165        * than thresholdMax), its neighbors are consider also edges if their
00166        * values are higher than the given percentage of thresholdMax
00167        * (i.e. higher than thresholdMax*thresholdMin).
00168        *
00169        * If the parameter indirectThresholdMin is \c true, then this value
00170        * means the percentage of pixels with the highest gradient values that
00171        * could be possible edges if they are neighbors of an edge pixel.  Note
00172        * that in this mode, and if indirectThresholdMin is also true, this
00173        * value should be greater than thresholdMax, since there should me
00174        * more possible edges than definitively edges.
00175        *
00176        * This value must be between 0.0f and 1.0f.
00177        *
00178        * Default Value: 0.5f
00179        */
00180       float thresholdMin;
00181 
00182       /**
00183        * If \c true then the real minimum threshold will be internally
00184        * computed considering that possibly \c thresholdMin
00185        * percent of the total number of pixels with the highest gradient
00186        * values are edges.
00187        *
00188        * If \c false, then the given \c thresholdMin will be used as is.
00189        *
00190        * Default value: false
00191        */
00192       bool indirectThresholdMin;
00193 
00194       /**
00195        * The real maximal threshold is computed from the maximum found in
00196        * the input image and this thresholdMax parameter, which is the
00197        * fraction of the maximal value to be considered.
00198        *
00199        * If an edge response is higher than the threshold, those
00200        * pixels will be definitively considered as edge.  This value
00201        * must be between 0.0f and 1.0f.
00202        *
00203        * If the parameter indirectThresholdMax is \c true, then this value
00204        * means the percentage of pixels with the highest gradient values that
00205        * are definitively edges.
00206        *
00207        * Default Value: 0.04f
00208        */
00209       float thresholdMax;
00210       
00211       /**
00212        * If \c true then the real maximum threshold will be internally
00213        * computed considering that \c thresholdMax
00214        * percent of the total number of pixels with the highest gradient
00215        * values are edges.
00216        *
00217        * If \c false, then the given \c thresholdMax will be used as is.
00218        *
00219        * Default value: false
00220        */
00221       bool indirectThresholdMax;
00222 
00223       /**
00224        * Value used for the background of the response
00225        *
00226        * Default value: 0
00227        */
00228       ubyte background;
00229 
00230       /**
00231        * Value used for the detected edges
00232        *
00233        * Default value: 255
00234        */
00235       ubyte edgeValue;
00236 
00237       /**
00238        * The expected angles in the orientation map must be between
00239        * 0.0f and 2*Pi.  If you can ensure this condition previous to
00240        * call the apply method, you can deactivate the check of this
00241        * condition setting this parameter to false.  Of course, checking
00242        * this condition takes its time, therefore it is better if you
00243        * ensure it in the algorithm that generates the orientation channel.
00244        *
00245        * The correction of angle is done in an arithmetical way, so, if the
00246        * magnitude of the values you provide can be much bigger than 2*Pi, you
00247        * need to take care of the conversion, or the check will
00248        * take too long or, in case 2*Pi is negligible compared with your 
00249        * values, it will remain in an infinity loop.
00250        *
00251        * The reason for an arithmetical correction is that in most cases the
00252        * angles will be between -2*Pi and 4*Pi, and an arithmetical check
00253        * is the fastest one.
00254        *
00255        * Default value: true
00256        */
00257       bool checkAngles;
00258 
00259       /**
00260        * Size of the histogram used to compute automatically the thresholds.
00261        * This determines the possible threshold values.  The histogram will
00262        * not be computed, if no threshold is to be computed automatically.
00263        *
00264        * Default value: 256
00265        */
00266       int gradientHistogramSize;
00267       
00268       /**
00269        * @name extensions to the classical algorithm
00270        */
00271       //@{
00272       /**
00273        * If false, the traditional algorithm will be applied, which only
00274        * detects the maxima along the gradient direction followed by 
00275        * hysteresis thresholding.  
00276        * If true, additionally a gap filling algorithm will be applied.
00277        *
00278        * Default value = false;
00279        */
00280       bool fillGaps;
00281 
00282       /**
00283        * value used to mark end points
00284        *
00285        * Default value: 255
00286        */
00287       ubyte endPointValue;
00288 
00289       /**
00290        * value used to mark gap completion
00291        *
00292        * Default value: 255
00293        */
00294       ubyte gapValue;
00295 
00296       /**
00297        * Number of pixels used together with an end point to estimate
00298        * the interpolation of a gap.
00299        * 
00300        * Default value: 5
00301        */
00302       int numGapHints;
00303 
00304       /**
00305        * Maximal allowed gap length
00306        * Default value: 10
00307        */
00308       int maxGapLength;
00309       
00310       //@}
00311     };
00312 
00313     /**
00314      * default constructor
00315      */
00316     nonMaximaSuppression();
00317 
00318     /**
00319      * Construct a functor using the given parameters
00320      */
00321     nonMaximaSuppression(const parameters& par);
00322 
00323     /**
00324      * copy constructor
00325      * @param other the object to be copied
00326      */
00327     nonMaximaSuppression(const nonMaximaSuppression& other);
00328 
00329     /**
00330      * destructor
00331      */
00332     virtual ~nonMaximaSuppression();
00333 
00334     /**
00335      * returns the name of this type ("nonMaximaSuppression")
00336      */
00337     virtual const char* getTypeName() const;
00338 
00339     /**
00340      * operates on a copy of the given %parameters.
00341      * @param preedges channel containing pre-edges, i.e. only some
00342      *                 confidence values are expected, where the 
00343      *                 maxima represent edges.  Only those values
00344      *                 greater than thresholdMax times the maximum
00345      *                 value here will be considered.
00346      * @param orientation channel with the angles.  It is an angle in the
00347      *                 image coordinate system, i.e. a positive angle direction
00348      *                 is clockwise.  The units must be radians and the values
00349      *                 MUST be zero or * positive between 0.0f and 2*Pi.  See
00350      *                 documentation of * parameters::checkAngle for more
00351      *                 information.
00352      * @param edges    After the suppression, only the edges will
00353      *                 be left.
00354      * @param maxPreedge Optional argument.
00355      *                 The algorithm uses as maximum threshold the given
00356      *                 parameters::maxThreshold multiplied by this argument.
00357      *                 It is usally employed to give here the maximum of the
00358      *                 preedges, which may be computed previously.
00359      *                   
00360      * @return true if apply successful or false otherwise.
00361      */
00362     bool apply(const channel& preedges,
00363                const channel& orientation,
00364                      channel8& edges,
00365                const float maxPreedge=1.0f) const;
00366 
00367 
00368     /**
00369      * operates on a copy of the given %parameters.
00370      * @param preedges channel containing pre-edges, i.e. only some
00371      *                 confidence values are expected, where the 
00372      *                 maxima represent edges.  Only those values
00373      *                 greater than thresholdMax times the maximum
00374      *                 value here will be considered.
00375      * @param orientation channel with the angles.  It is an angle in the
00376      *                 image coordinate system, i.e. a positive angle direction
00377      *                 is clockwise.  The units must be radians and the values
00378      *                 MUST be zero or * positive between 0.0f and 2*Pi.  See
00379      *                 documentation of * parameters::checkAngle for more
00380      *                 information.
00381      * @param relevance the thresholds will be computed "dividing" the ones
00382      *                 given in the parameters by the corresponding element
00383      *                 in this channel.
00384      * @param edges    After the suppression, only the edges will
00385      *                 be left.
00386      * @param maxPreedge Optional argument.
00387      *                 The algorithm uses as maximum threshold the given
00388      *                 parameters::maxThreshold multiplied by this argument.
00389      *                 It is usally employed to give here the maximum of the
00390      *                 preedges, which may be computed previously.
00391      *                   
00392      * @return true if apply successful or false otherwise.
00393      */
00394     bool apply(const channel& preedges,
00395                const channel& orientation,
00396                const channel& relevance,
00397                      channel8& edges,
00398                const float maxPreedge=1.0f) const;
00399 
00400     /**
00401      * copy data of "other" functor.
00402      * @param other the functor to be copied
00403      * @return a reference to this functor object
00404      */
00405     nonMaximaSuppression& copy(const nonMaximaSuppression& other);
00406 
00407     /**
00408      * alias for copy member
00409      * @param other the functor to be copied
00410      * @return a reference to this functor object
00411      */
00412     nonMaximaSuppression& operator=(const nonMaximaSuppression& other);
00413 
00414     /**
00415      * returns a pointer to a clone of this functor.
00416      */
00417     virtual functor* clone() const;
00418 
00419     /**
00420      * returns used parameters
00421      */
00422     const parameters& getParameters() const;
00423 
00424   protected:
00425 
00426     /**
00427      * interpolate between two values (bilinear interpolation)
00428      * @param y1 value at x==0
00429      * @param y2 value at x==1
00430      * @param fOffset value in range of 0..1 to beinterpolated at
00431      * @return returns the interpolated value
00432      */
00433     inline float interpolate(const float y1,
00434                              const float y2,
00435                              const float fOffset) const;
00436 
00437     /**
00438      * suppress the maxima.
00439      * This method assumes the edges channel has been adecuatelly resized.
00440      *
00441      * The preedges and orientation channels MUST be connected.
00442      */
00443     void nonMaxSuppression(const channel& preedges,
00444                            const channel& orientation,
00445                            channel8& edges,
00446                            const float thresholdMin) const;
00447 
00448     /**
00449      * hysteresis 
00450      */
00451     void hysteresis(const channel& preedge,
00452                     const channel8& maxima,
00453                     const float thresholdMax,
00454                     channel8& dest) const;
00455 
00456     /**
00457      * compute the real thresholMin and threshodMax values to be used.
00458      *
00459      * @param grad magnitude of the gradient
00460      * @param maxGrad max value in grad
00461      * @param thresholdMin minimum threshold for a pixel to be possible an edge
00462      * @param thresholdMax maximum threshold to be reached by a pixel to be
00463      *                     definitively an edge.
00464      */
00465     void thresholdValues(const channel& grad,
00466                          const float maxGrad,
00467                          float& thresholdMin,
00468                          float& thresholdMax) const;
00469 
00470 
00471 
00472     /**
00473      * ensure that the angles are between 0.0f and 2*Pi.
00474      */
00475     void checkOrientation(const channel& src,channel& dest) const;
00476 
00477     /**
00478      * Find the edge points in the given src and create a new endPts channel
00479      * with only those points.
00480      *
00481      * At the same time a kd-Tree will be build, containing all end-points.
00482      * This allows an efficient way to search for other end points
00483      * in the neighborhood.
00484      *
00485      * @param src edge mask
00486      * @param endPts resulting end-point mask
00487      * @param endPtsList list of end points
00488      *
00489      * @return the number of end-points found
00490      */
00491     int findEndPoints(const channel8& src,
00492                       channel8& endPts,
00493                       pointList& endPtsList) const;
00494 
00495     
00496     /**
00497      * Track points back the given number of pixels
00498      *
00499      * This method is used to track back the end points to get enough
00500      * information about the possible extrapolations.
00501      *
00502      * The result is a list of corresponding delta values to extrapolate
00503      * the line beginning with an end point.
00504      */
00505     bool trackPoints(const channel8& edges,
00506                      const pointList& endPtsList,
00507                      const channel& orientation,
00508                      tpointList<float>& deltas) const;
00509 
00510     /**
00511      * fill the gaps
00512      */
00513     bool fillGaps(const channel8& edges,
00514                   const channel& gradMag,
00515                   const pointList& endPtsList,
00516                   const tpointList<float>& deltas,
00517                   channel8& dest) const;
00518 
00519   private:
00520     /**
00521      * add the points a and b ensuring that they remain in a valid range 
00522      * defined by the size and leave the result in q.  A reference to q
00523      * is returned
00524      */
00525     inline const point& add(const point& a,
00526                             const point& b,
00527                             const point& size,
00528                                   point& q) const;
00529 
00530   };
00531 }
00532 
00533 #endif

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