latest version v1.9 - last update 10 Apr 2010 |
00001 /* 00002 * Copyright (C) 2001, 2002, 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 Digital Image/Signal Processing Library 00026 * file .......: ltiWatershedSegmentation.h 00027 * authors ....: Benjamin Winkler, Axel Berner 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 11.1.2001 00030 * revisions ..: $Id: ltiWatershedSegmentation.h,v 1.11 2006/02/08 11:59:31 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_WATERSHED_SEGMENTATION_H_ 00034 #define _LTI_WATERSHED_SEGMENTATION_H_ 00035 00036 #include "ltiSegmentation.h" 00037 #include "ltiPointList.h" 00038 #include "ltiImage.h" 00039 00040 #include <queue> 00041 #include <vector> // lti::vector doesn't work here 00042 #include <list> 00043 00044 namespace lti { 00045 00046 /** 00047 * Watershed segmentation of a channel8 00048 * 00049 * Algorithms: 00050 * 00051 * Luc Vincent and Pierre Soille. 00052 * "Watersheds in Digital Spaces: An Efficient Algorithm Based on Immersion 00053 * Simulations". 00054 * IEEE transactions on pattern analysis and machine intelligence, 00055 * vol. 13, No. 6, June 1991, pp. 583-598 00056 * 00057 * and 00058 * 00059 * Patrick De Smet and Rui Luis V.P.M. Pires 00060 * "Implementation and analysis of an optimized rainfalling watershed 00061 * algorithm". 00062 * IS\&T\/SPIE's 12th Annual Symposium Electronic Imaging 2000, 00063 * January 2000, pp. 759-766 00064 * 00065 * Watershed segmentation is a morphological operator used to segment gray 00066 * valued images, based on viewing the gray image as a topographical map. 00067 * Valleys will be flooded with water until the water surpasses the sheds 00068 * separating them. At the contact lines the "watershed lines" are created 00069 * and constitute the limits between the image regions. 00070 * 00071 * The topological map is usually a gradient map (the magnitude of the 00072 * gradient) that can be obtained with the lti::orientationMap functor or 00073 * with the lti::colorContrastGradient, or directly using the 00074 * lti::gradientKernelX and lti::gradientKernelY and the lti::convolution 00075 * operator. 00076 * 00077 * Two kinds of apply() methods are provided: 00078 * 00079 * - Two methods returning a channel8 will compute only two values: 00080 * watershed or the catchment basin. The specific values for each class 00081 * are indicated in the parameters object. 00082 * 00083 * - The apply() method returning a matrix<int> return a labeled mask, where 00084 * each catchment basin get its own id. This method is more typical for a 00085 * segmentation algorithm. 00086 */ 00087 class watershedSegmentation : public segmentation { 00088 public: 00089 /** 00090 * the parameters for the class watershedSegmentation 00091 */ 00092 class parameters : public segmentation::parameters { 00093 public: 00094 /** 00095 * default constructor 00096 */ 00097 parameters(); 00098 00099 /** 00100 * copy constructor 00101 * @param other the parameters object to be copied 00102 */ 00103 parameters(const parameters& other); 00104 00105 /** 00106 * destructor 00107 */ 00108 ~parameters(); 00109 00110 /** 00111 * returns name of this type 00112 */ 00113 const char* getTypeName() const; 00114 00115 /** 00116 * copy the contents of a parameters object 00117 * @param other the parameters object to be copied 00118 * @return a reference to this parameters object 00119 */ 00120 parameters& copy(const parameters& other); 00121 00122 /** 00123 * copy the contents of a parameters object 00124 * @param other the parameters object to be copied 00125 * @return a reference to this parameters object 00126 */ 00127 parameters& operator=(const parameters& other); 00128 00129 00130 /** 00131 * returns a pointer to a clone of the parameters 00132 */ 00133 virtual functor::parameters* clone() const; 00134 00135 /** 00136 * write the parameters in the given ioHandler 00137 * @param handler the ioHandler to be used 00138 * @param complete if true (the default) the enclosing begin/end will 00139 * be also written, otherwise only the data block will be written. 00140 * @return true if write was successful 00141 */ 00142 virtual bool write(ioHandler& handler,const bool complete=true) const; 00143 00144 /** 00145 * write the parameters in the given ioHandler 00146 * @param handler the ioHandler to be used 00147 * @param complete if true (the default) the enclosing begin/end will 00148 * be also written, otherwise only the data block will be written. 00149 * @return true if write was successful 00150 */ 00151 virtual bool read(ioHandler& handler,const bool complete=true); 00152 00153 # ifdef _LTI_MSC_6 00154 /** 00155 * this function is required by MSVC only, as a workaround for a 00156 * very awful bug, which exists since MSVC V.4.0, and still by 00157 * V.6.0 with all bugfixes (so called "service packs") remains 00158 * there... This method is also public due to another bug, so please 00159 * NEVER EVER call this method directly: use read() instead 00160 */ 00161 bool readMS(ioHandler& handler,const bool complete=true); 00162 00163 /** 00164 * this function is required by MSVC only, as a workaround for a 00165 * very awful bug, which exists since MSVC V.4.0, and still by 00166 * V.6.0 with all bugfixes (so called "service packs") remains 00167 * there... This method is also public due to another bug, so please 00168 * NEVER EVER call this method directly: use write() instead 00169 */ 00170 bool writeMS(ioHandler& handler,const bool complete=true) const; 00171 # endif 00172 00173 00174 // ------------------------------------------------ 00175 // the parameters 00176 // ------------------------------------------------ 00177 00178 /** 00179 * defines the neighborhood of a pixel. 00180 * 00181 * if set to false (default), only the pixels horizontally and 00182 * vertically bordering are considered to be neighbors. 00183 * 00184 * if set to true, the four diagonally adjoining pixels are also taken 00185 * into account. 00186 */ 00187 bool neighborhood8; 00188 00189 /** 00190 * gray value to be used for watersheds in the resulting channel8 00191 */ 00192 int watershedValue; 00193 00194 /** 00195 * gray value to be used for basins in the resulting channel8 00196 */ 00197 int basinValue; 00198 00199 /** 00200 * Rainfalling Watersheds or Standard-Waterfall 00201 * 00202 * Default: true (Rainfall-Watersheds, they are much faster) 00203 */ 00204 bool rainfall; 00205 00206 /** 00207 * Threshold to eliminate noise in the src-image. 00208 * 00209 * Default value: 0 00210 * 00211 * To avoid oversegmentation, try higher values (for example 4). 00212 * Another usual measure to reduce oversegmentation is also to denoise 00213 * the input image, using median-filters, SUSAN denoiser or mean-shift 00214 * denoisers, among many other possibilities. 00215 */ 00216 ubyte threshold; 00217 }; 00218 00219 /** 00220 * default constructor 00221 */ 00222 watershedSegmentation(); 00223 00224 /** 00225 * constructor with parameters 00226 */ 00227 watershedSegmentation(const parameters& par); 00228 00229 /** 00230 * copy constructor 00231 * @param other the object to be copied 00232 */ 00233 watershedSegmentation(const watershedSegmentation& other); 00234 00235 /** 00236 * destructor 00237 */ 00238 virtual ~watershedSegmentation(); 00239 00240 /** 00241 * returns the name of this type ("watershedSegmentation") 00242 */ 00243 virtual const char* getTypeName() const; 00244 00245 /** 00246 * creates a watershed mask on the given channel8 00247 * @param srcdest channel8 with the source data. This is usually the 00248 * gradient of an intensity image or a color contrast gradient. The 00249 * resulting watershed lines will be left here too. 00250 * @result true if successful, false otherwise 00251 */ 00252 bool apply(channel8& srcdest); 00253 00254 /** 00255 * saves a watershed mask of src in dest 00256 * @param src channel8 with the source data. This is usually the gradient 00257 * of an intensity image or a color contrast gradient. 00258 * @param dest channel8 where the watershed lines will be written. 00259 */ 00260 bool apply(const channel8& src,channel8& dest); 00261 00262 /** 00263 * creates a region mask on the given matrix 00264 * only exact watersheds are marked 0, regions are numbered 1,2,... 00265 * @param src channel8 with the source data. This is usually the gradient 00266 * of an intensity image or a color contrast gradient. 00267 * @param result matrix<int> with the resulting region information, with 00268 * a label per basin. 00269 */ 00270 bool apply(const channel8& src, matrix<int>& result); 00271 00272 /** 00273 * copy data of "other" functor. 00274 * @param other the functor to be copied 00275 * @return a reference to this functor object 00276 */ 00277 watershedSegmentation& copy(const watershedSegmentation& other); 00278 00279 /** 00280 * returns a pointer to a clone of this functor. 00281 */ 00282 virtual functor* clone() const; 00283 00284 /** 00285 * returns used parameters 00286 */ 00287 const parameters& getParameters() const; 00288 00289 private: 00290 00291 // for both -------------------------------------------------------- 00292 /** 00293 * fill neighborhood pointlist according to parameter neighborhood8. 00294 * if set to true, the full 8-neighborhood will be generated 00295 * otherwise, only the 4 horizontally and vertically neighboring pixels 00296 * will be taken into account. 00297 */ 00298 void createNeighborhood(const int colms,const bool neigh8); 00299 00300 /** 00301 * converts the resulting matrix to the given channel8 00302 * by using watershedValue and basinValue 00303 */ 00304 void copyMatrixToChannel8(const matrix<int>& src, 00305 channel8& dest); 00306 /** 00307 * list of neighborhood points (relative). Is an 4 or 8 length vector 00308 * containing the offsets to get the neighbor pixels from the current one. 00309 */ 00310 vector<int> neigh; 00311 00312 /** 00313 * stores the size of the image in pixels 00314 */ 00315 int imgSize; 00316 00317 /** 00318 * border LUT contains 0 for all non-border pixel and 255 for 00319 * all border pixels. It is used to accelerate detection of a border 00320 * position. 00321 */ 00322 channel8 borderLUT; 00323 00324 /** 00325 * return true if the given point corresponds to a valid neighbor point 00326 * of the given current point 00327 */ 00328 inline bool invalidNeighbor(const int currentPoint, 00329 const int currentNeighbor) const { 00330 return (currentNeighbor<0 || currentNeighbor>=imgSize || 00331 ((borderLUT.at(currentPoint)!=0) && 00332 (abs((currentPoint%borderLUT.columns()) - 00333 (currentNeighbor%borderLUT.columns())) > 1))); 00334 } 00335 00336 /** 00337 * return true if the given point corresponds to a valid neighbor point 00338 * of the given current point 00339 */ 00340 inline bool validNeighbor(const int currentPoint, 00341 const int currentNeighbor) const { 00342 return (currentNeighbor>=0 && currentNeighbor<imgSize && 00343 ((borderLUT.at(currentPoint)==0) || 00344 (abs((currentPoint%borderLUT.columns()) - 00345 (currentNeighbor%borderLUT.columns())) <= 1))); 00346 } 00347 00348 00349 private: 00350 // rainfalling------------------------------------------------------- 00351 /** 00352 * find for all points(if there is) a neigh, which have a lower level 00353 */ 00354 void findLowerNeigh(const channel8& src, 00355 matrix<int>& downPos, 00356 channel8& thresSrc8); 00357 00358 /** 00359 * number serialy all minimas (lakes,or only points), 00360 */ 00361 void markMinimas(const matrix<int>& downPos, 00362 const channel8& src, 00363 matrix<int>& dest); 00364 00365 /** 00366 * look in which minima a raindrop would flow 00367 */ 00368 void letsRain(const matrix<int>& downPos, matrix<int>& dest); 00369 00370 private: 00371 /** 00372 * following type can be replaced for a faster list for small objects 00373 * in the near future 00374 */ 00375 typedef std::list<int> list_type; 00376 00377 // standard----------------------------------------------------------- 00378 00379 /** 00380 * Initialize a border LUT to save time detecting if a pixel is in 00381 * the border. 00382 */ 00383 void initBorderLUT(const point& size, 00384 channel8& borderLUT) const; 00385 00386 /** 00387 * creates a kind of histogram and stores all points, belonging to 00388 * a grayvalue in a list. 00389 * 00390 * It assumes that \a sortedPoints is empty! 00391 */ 00392 void sortPixels(const channel8& src, 00393 std::vector<list_type>& sortedPoints) const; 00394 00395 /** 00396 * set all new pixel (caused by waterlevel raising) MASK 00397 */ 00398 void maskCurrLevelPoints (const list_type& currentPointList, 00399 vector<int>& distance, 00400 std::queue<int>& fifoQueue, 00401 matrix<int>& result) const; 00402 /** 00403 * find out to which minima(lake) the MASK-pixel belog to 00404 */ 00405 void assignCurrLevelPoints(vector<int>& distance, 00406 std::queue<int>& fifoQueue, 00407 matrix<int>& result) const; 00408 00409 /** 00410 * define all pixel, which are not assigned to a minima, as a new minima 00411 */ 00412 void checkForMins (const list_type& currentPointList, 00413 vector<int>& distance, 00414 std::queue<int>& fifoQueue, 00415 matrix<int>& result, 00416 int& currentLabel) const; 00417 /** 00418 * raise the waterlevel, and look what happen 00419 */ 00420 void raiseWaterLevel(const std::vector<list_type>& sortedPoints, 00421 matrix<int>& result) const; 00422 00423 }; 00424 00425 } 00426 00427 #endif