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

ltiWatershedSegmentation.h

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

Generated on Sat Apr 10 15:26:23 2010 for LTI-Lib by Doxygen 1.6.1