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 .......: 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