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

ltiRegionGraphFunctor.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 .......: ltiRegionGraphFunctor.h
00027  * authors ....: Pablo Alvarado
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 25.10.2003
00030  * revisions ..: $Id: ltiRegionGraphFunctor.h,v 1.3 2006/02/08 11:44:16 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_REGION_GRAPH_FUNCTOR_H_
00034 #define _LTI_REGION_GRAPH_FUNCTOR_H_
00035 
00036 #include "ltiMacroSymbols.h"
00037 
00038 // only for compilers different than VC++ 6.0 available
00039 #ifdef _LTI_MSC_6
00040 
00041 #pragma message("Insufficient C++ Template Support for lti::regionGraphMeans.")
00042 #pragma message("You need a newer compiler")
00043 
00044 #else
00045 
00046 #include "ltiImage.h"
00047 #include "ltiAdjacencyGraph.h"
00048 #include "ltiFunctor.h"
00049 #include <string>
00050 
00051 namespace lti {
00052   /**
00053    * Functor to manipulate graphs of adjacent image regions.
00054    *
00055    * This class provides some functionality to create and manipulate
00056    * lti::adjacencyGraph data structures in the context of image region 
00057    * analysis.
00058    *
00059    * It is a template class with template parameter \c G, which is expected
00060    * to be a valid lti::adjacencyGraph type.
00061    *
00062    * The class is "almost" abstract, since the real useful instances belong to
00063    * derived classes that implement specific graph generation and merging
00064    * strategies.  However, it can be used as a standalone class for simple
00065    * graph operations where only the topology of the graph is of interest.
00066    *
00067    * Derived classes should reimplement following protected methods:
00068    * - bool checkInternalData(const point&,const int) which should check
00069    *   the sizes of internal data structures necessary to compute the graph.
00070    *   This could be for example the size of color channels or gradient
00071    *   channels, or the size of vectors containing statistics for each
00072    *   region.
00073    * - considerForEdgeData(const point&,const point&,edge_data_type&)
00074    *   called while computing the graph topology each time two neighbor pixels
00075    *   belonging to two different regions are found.  You can use it to 
00076    *   accumulate in the third argument some values that can be later used
00077    *   to compute further statistics, like border length, mean color or
00078    *   gradient value at the border, etc.
00079    * - considerForNodeData(const point&,const int,node_type&) 
00080    *   called for each pixel of each region when generating the graph topology.
00081    *   It can serve to precompute some statistics while visiting the labels
00082    *   mask.  This way you can save traversing the image several times to
00083    *   compute different statistics, if you accumulate everything that is
00084    *   required for that task here.
00085    * - collectEdgeAndNodeData(graph_type&) allows to compute some additional
00086    *   information from the data accumulated in the graph as its topology
00087    *   was determined and before the weights for the edges are computed
00088    *   (see generate() method for more information).
00089    *
00090    * An important constraint to the graph is that the data (not the weights)
00091    * associated to an edge (a,b) is always the same data associated to edge
00092    * (b,a).
00093    * 
00094    */
00095   template<class G>
00096   class regionGraphFunctor : public functor {
00097   public:
00098 
00099     /**
00100      * Graph type
00101      */
00102     typedef G graph_type;
00103 
00104     /**
00105      * Edge traits
00106      */
00107     typedef typename graph_type::edge_traits edge_traits;
00108 
00109     /**
00110      * Type used for the weights.  They should usually be float or double, but
00111      * any type supported by the lti::vector can be used.
00112      */
00113     typedef typename graph_type::weight_type weight_type;
00114     
00115     /**
00116      * Edge denotation with the pair of node ids
00117      */
00118     typedef typename graph_type::node_pair node_pair;
00119 
00120     /**
00121      * Edge denotation with the pair of node ids
00122      */
00123     typedef typename graph_type::node_type node_type;
00124 
00125     /**
00126      * Edge data type
00127      */
00128     typedef typename graph_type::edge_data_type edge_data_type;
00129 
00130     /**
00131      * the parameters for the class regionGraphFunctor
00132      */
00133     class parameters : public functor::parameters {
00134     public:
00135       /**
00136        * Type used to specify how to merge regions
00137        */
00138       enum eMergeMode {
00139         Fast,    /**< Fast method, which does not recompute distances.  Only
00140                     the initial values are used.*/
00141         Optimal  /**< Slower method, which recomputes distances when two
00142                     regions are merged.*/
00143       };
00144 
00145 
00146       /**
00147        * default constructor
00148        */
00149       parameters(const eMergeMode& mode = Fast,
00150                  const weight_type& threshold = weight_type() ) 
00151         : functor::parameters() {
00152         mergeMode = mode;
00153         mergeThreshold = threshold;
00154         minRegionNumber = 1;
00155       };
00156 
00157       /**
00158        * copy constructor
00159        * @param other the parameters object to be copied
00160        */
00161       parameters(const parameters& other) : functor::parameters() {
00162         copy(other);
00163       }
00164       
00165       /**
00166        * destructor
00167        */
00168       ~parameters() {
00169       };
00170 
00171       /**
00172        * returns name of this type
00173        */
00174       const char* getTypeName() const {
00175         return "regionGraphFunctor::parameters";
00176       };
00177 
00178       /**
00179        * copy the contents of a parameters object
00180        * @param other the parameters object to be copied
00181        * @return a reference to this parameters object
00182        */
00183       parameters& copy(const parameters& other) {
00184 #     ifndef _LTI_MSC_6
00185         // MS Visual C++ 6 is not able to compile this...
00186         functor::parameters::copy(other);
00187 #     else
00188         // ...so we have to use this workaround.
00189         // Conditional on that, copy may not be virtual.
00190         functor::parameters& (functor::parameters::* p_copy)
00191                             (const functor::parameters&) =
00192                             functor::parameters::copy;
00193         (this->*p_copy)(other);
00194 #     endif
00195         
00196         mergeMode = other.mergeMode;
00197         mergeThreshold = other.mergeThreshold;
00198         minRegionNumber = other.minRegionNumber;
00199 
00200         return *this;
00201       };
00202 
00203       /**
00204        * copy the contents of a parameters object
00205        * @param other the parameters object to be copied
00206        * @return a reference to this parameters object
00207        */
00208       parameters& operator=(const parameters& other) {
00209         return copy(other);
00210       };
00211 
00212       /**
00213        * returns a pointer to a clone of the parameters
00214        */
00215       virtual functor::parameters* clone() const {
00216         return new parameters(*this);
00217       };
00218 
00219 #     ifndef _LTI_MSC_6
00220       /**
00221        * write the parameters in the given ioHandler
00222        * @param handler the ioHandler to be used
00223        * @param complete if true (the default) the enclosing begin/end will
00224        *        be also written, otherwise only the data block will be written.
00225        * @return true if write was successful
00226        */
00227       virtual bool write(ioHandler& handler,const bool complete=true) const
00228 #     else
00229       /**
00230        * this function is required by MSVC only, as a workaround for a
00231        * very awful bug, which exists since MSVC V.4.0, and still by
00232        * V.6.0 with all bugfixes (so called "service packs") remains
00233        * there...  This method is also public due to another bug, so please
00234        * NEVER EVER call this method directly: use write() instead
00235        */
00236       bool writeMS(ioHandler& handler,const bool complete=true) const
00237 #     endif
00238       {
00239         bool b = true;
00240         if (complete) {
00241           b = handler.writeBegin();
00242         }
00243         
00244         if (b) {
00245           switch(mergeMode) {
00246             case Optimal:
00247               lti::write(handler,"mergeMode","Optimal");
00248               break;
00249             case Fast:
00250               lti::write(handler,"mergeMode","Fast");
00251               break;
00252             default:
00253               lti::write(handler,"mergeMode","Optimal");
00254           }
00255 
00256           lti::write(handler,"mergeThreshold",mergeThreshold);
00257           lti::write(handler,"minRegionNumber",minRegionNumber);
00258         }
00259 
00260 #     ifndef _LTI_MSC_6
00261         // This is the standard C++ code, which MS Visual C++ 6 is not able to
00262         // compile...
00263         b = b && functor::parameters::write(handler,false);
00264 #     else
00265         bool (functor::parameters::* p_writeMS)(ioHandler&,
00266                                                          const bool) const =
00267           functor::parameters::writeMS;
00268         b = b && (this->*p_writeMS)(handler,false);
00269 #     endif
00270 
00271         if (complete) {
00272           b = b && handler.writeEnd();
00273         }
00274 
00275         return b;
00276       }
00277 
00278 #     ifdef _LTI_MSC_6
00279       /**
00280        * write the parameters in the given ioHandler
00281        * @param handler the ioHandler to be used
00282        * @param complete if true (the default) the enclosing begin/end will
00283        *        be also written, otherwise only the data block will be written.
00284        * @return true if write was successful
00285        */
00286       bool write(ioHandler& handler,
00287                  const bool complete=true) const {
00288         // ...we need this workaround to cope with another really
00289         // awful MSVC bug.
00290         return writeMS(handler,complete);
00291       }
00292 #     endif
00293 
00294 
00295 #     ifndef _LTI_MSC_6
00296       /**
00297        * read the parameters from the given ioHandler
00298        * @param handler the ioHandler to be used
00299        * @param complete if true (the default) the enclosing begin/end will
00300        *        be also written, otherwise only the data block will be written.
00301        * @return true if write was successful
00302        */
00303       virtual bool read(ioHandler& handler,const bool complete=true)
00304 #     else
00305       /**
00306        * this function is required by MSVC only, as a workaround for a
00307        * very awful bug, which exists since MSVC V.4.0, and still by
00308        * V.6.0 with all bugfixes (so called "service packs") remains
00309        * there...  This method is also public due to another bug, so please
00310        * NEVER EVER call this method directly: use read() instead
00311        */
00312       bool readMS(ioHandler& handler,const bool complete=true)
00313 #     endif
00314       {
00315         bool b = true;
00316         if (complete) {
00317           b = handler.readBegin();
00318         }
00319         
00320         if (b) {
00321           std::string str;
00322           lti::read(handler,"mergeMode",str);
00323           if (str == "Optimal") {
00324             mergeMode = Optimal;
00325           } else {
00326             mergeMode = Fast;
00327           }
00328 
00329           lti::read(handler,"mergeThreshold",mergeThreshold);
00330           lti::read(handler,"minRegionNumber",minRegionNumber);
00331         }
00332 
00333 #       ifndef _LTI_MSC_6
00334         // This is the standard C++ code, which MS Visual C++ 6 is not
00335         // able to compile...
00336         b = b && functor::parameters::read(handler,false);
00337 #       else
00338         bool (functor::parameters::* p_readMS)(ioHandler&,
00339                                                         const bool) =
00340           functor::parameters::readMS;
00341         b = b && (this->*p_readMS)(handler,false);
00342 #       endif
00343 
00344         if (complete) {
00345           b = b && handler.readEnd();
00346         }
00347         
00348         return b;
00349       }
00350 
00351 #     ifdef _LTI_MSC_6
00352       /**
00353        * read the parameters from the given ioHandler
00354        * @param handler the ioHandler to be used
00355        * @param complete if true (the default) the enclosing begin/end will
00356        *        be also written, otherwise only the data block will be written.
00357        * @return true if write was successful
00358        */
00359       bool read(ioHandler& handler,const bool complete=true) {
00360         // ...we need this workaround to cope with another really awful MSVC
00361         // bug.
00362         return readMS(handler,complete);
00363       }
00364 #     endif
00365 
00366       // ------------------------------------------------
00367       // the parameters
00368       // ------------------------------------------------
00369 
00370       /**
00371        * Merge strategy to be used:
00372        * - Fast: freezes the graph weights, recomputing them only if
00373        *         necessary (when you merge A and B, and both had edges to
00374        *         an edge C, the new edge will be computed automatically using
00375        *         the method += of the G::edge_data_type::operator+=).
00376        *         No distances between nodes will be recomputed, saving lots of
00377        *         time.  Additionally, the merge order of nodes is 
00378        * - Optimal: When two nodes are merged, their data and the weights of
00379        *            the edges to all neighbors will be recomputed.  This will
00380        *            change the merge order, which always chooses to merge
00381        *            the nodes with the smallest distance.
00382        */
00383       eMergeMode mergeMode;
00384 
00385       /**
00386        * For the merge methods, this is the maximal weight between two
00387        * nodes allowed.  This means, edges with weights larger than this
00388        * value won't be merged.
00389        *
00390        * Very low values will produce an oversegmentation, larger values
00391        * produce undersegmentations.
00392        *
00393        *
00394        * Default value: weight_type()
00395        */
00396       weight_type mergeThreshold;
00397 
00398       /**
00399        * Minimum number of regions.
00400        *
00401        * The merge operation can be controled by the merge-threshold, but
00402        * if it is set too large, the final result would contain just one
00403        * node.  This parameter allows you to specify the minimal number of
00404        * nodes the graph has to retain after merging.  Of course, if the
00405        * input graph has already less nodes than the number specified here,
00406        * then nothing will be done.
00407        *
00408        * Default value: 1
00409        */
00410       int minRegionNumber;
00411 
00412     };
00413 
00414     /**
00415      * default constructor
00416      */
00417     regionGraphFunctor(const bool initParams=true);
00418 
00419     /**
00420      * default constructor
00421      */
00422     regionGraphFunctor(const typename parameters::eMergeMode& mode,
00423                        const weight_type& threshold = weight_type());
00424     
00425 
00426     /**
00427      * Construct a functor using the given parameters
00428      */
00429     regionGraphFunctor(const parameters& par);
00430 
00431     /**
00432      * copy constructor
00433      * @param other the object to be copied
00434      */
00435     regionGraphFunctor(const regionGraphFunctor& other);
00436 
00437     /**
00438      * destructor
00439      */
00440     virtual ~regionGraphFunctor();
00441 
00442     /**
00443      * returns the name of this type ("regionGraphFunctor")
00444      */
00445     virtual const char* getTypeName() const;
00446 
00447     /**
00448      * copy data of "other" functor.
00449      * @param other the functor to be copied
00450      * @return a reference to this functor object
00451      */
00452     regionGraphFunctor& copy(const regionGraphFunctor& other);
00453 
00454     /**
00455      * alias for copy member
00456      * @param other the functor to be copied
00457      * @return a reference to this functor object
00458      */
00459     regionGraphFunctor& operator=(const regionGraphFunctor& other);
00460 
00461     /**
00462      * returns a pointer to a clone of this functor.
00463      */
00464     virtual functor* clone() const;
00465 
00466     /**
00467      * returns used parameters
00468      */
00469     const parameters& getParameters() const;
00470 
00471     /**
00472      * Alias for generate()
00473      */
00474     bool apply(const matrix<int>& regions,
00475                const int minLabel,
00476                graph_type& graph);
00477 
00478     /**
00479      * Alias for merge()
00480      */
00481     bool apply(const weight_type& threshold,
00482                graph_type& graph,
00483                ivector& equivalences);
00484 
00485     /**
00486      * Alias for merge() taking the threshold from the parameters
00487      */
00488     bool apply(graph_type& graph,
00489                ivector& equivalences);
00490 
00491     /**
00492      * Alias for merge()
00493      */
00494     bool apply(const weight_type& threshold,
00495                const int minLabel,
00496                graph_type& graph,
00497                ivector& equivalences);
00498 
00499     /**
00500      * Alias for merge() taking the threshold from the parameters
00501      */
00502     bool apply(const int minLabel,
00503                graph_type& graph,               
00504                ivector& equivalences);
00505 
00506     /**
00507      * Generate the adjacency graph for the given labeled mask \a regions.
00508      *
00509      * The generation of a graph consists of three phases:
00510      * -# Topology creation.  Here the graph topology is determined traversing
00511      *    the given regions mask and detecting adjacent pixels.  While 
00512      *    traversing, edge and node data can be accumulated or computed using
00513      *    the virtual methods considerForEdgeData() and considerForNodeData().
00514      * -# Data preparation. Once some data in the nodes and edges has been 
00515      *    collected, you can prepare it for the computation of weights.  This
00516      *    means, you can compute histograms, maxima and minima, etc. which
00517      *    can be used to control the range where the weights will be.
00518      * -# Edge weight computation.  The method in the edge_type of the
00519      *    graph "weight()" will be used to compute the weights of all edges
00520      *    at once.
00521      *
00522      * This method ensures that the node ids corresponds to the region labels.
00523      *
00524      * @param regions the labeled mask to be analyzed
00525      * @param minLabel only the adjacency between region-labels greater or
00526      *                 equal this value will be fully analyzed.  No graph edges
00527      *                 between regions with labels lower than \a minLabel will
00528      *                 be detected.
00529      * @param graph the adjacency graph to be generated
00530      * @return true if successful, false otherwise.
00531      */
00532     bool generate(const matrix<int>& regions,
00533                   const int minLabel,
00534                         graph_type& graph);
00535     
00536     /**
00537      * Generate the adjacency graph for the given labeled mask \a regions,
00538      * using for each region-node the data contained in the given \a data
00539      * vector.  However, the method \a considerForNodeData() has priority,
00540      * i.e. if this method can change the node's data.
00541      *
00542      * This will ensure that the node id corresponds to the region label.
00543      *
00544      * @param regions the labeled mask to be analyzed
00545      * @param minLabel only the adjacency between region-labels greater or
00546      *                 equal this value will be fully analyzed.  No graph edges
00547      *                 between regions with labels lower than \a minLabel will
00548      *                 be detected.
00549      * @param data vector containing at the element index \a i data for the
00550      *             node representing region \a i.
00551      * @param graph the adjacency graph to be generated
00552      * @return true if successful, false otherwise.
00553      */
00554     bool generate(const matrix<int>& regions,
00555                   const int minLabel,
00556                   const std::vector<node_type>& data,
00557                         graph_type& graph);
00558 
00559 
00560     /**
00561      * Compute the affinity matrix and degree vector for the given graph.
00562      *
00563      * The affinity matrix containts the weights of the edges.  The degree
00564      * vector the sum of the outgoing edges for each node.
00565      *
00566      * Several functors can require this sort of data structures.  One
00567      * prominent example is the functor lti::multiclassNormalizedCuts.
00568      */
00569     virtual bool affinityMatrix(const graph_type& graph,
00570                                 matrix<weight_type>& affinity,
00571                                 const weight_type noEdgeValue=weight_type()
00572                                 ) const;
00573     
00574     /**
00575      * Merge all nodes whose edges have a weight smaller or equal than the
00576      * given threshold.
00577      *
00578      * The output will be not only the new graph with the merged data, but
00579      * an equivalences vector, where for each node id in the original graph
00580      * a new id is determined.
00581      */
00582     virtual bool merge(const weight_type& threshold,
00583                        graph_type& graph,
00584                        ivector& equivalences) const;
00585 
00586     /**
00587      * Merge all nodes whose edges have a weight smaller or equal than the
00588      * given threshold and one or both nodes have a label above or equal
00589      * the given minLabel.
00590      *
00591      * The output will be not only the new graph with the merged data, but
00592      * an equivalences vector, where for each node id in the original graph
00593      * a new id is determined.
00594      */
00595     virtual bool merge(const weight_type& threshold,
00596                        const int minLabel,
00597                        graph_type& graph,
00598                        ivector& equivalences) const;
00599 
00600     /**
00601      * Simple helper method to reassign the labels used in the given labeled
00602      * mask using an equivalences vector, as computed by merge.
00603      *
00604      * You must ensure that the equivalences vector has enough elements to
00605      * avoid an improper memory access, i.e. equivalences.size() >
00606      * regions.maximum().
00607      *
00608      * @param equivalences vector containing for each label \a i the new
00609      *                     label.
00610      * @param regions matrix with the source input labels.  The result will
00611      *                be left here too.
00612      * @param compact flag to indicate if the equivalences should be use
00613      *                as they are (false), or if a new labels set should
00614      *                be computed which lies between 0 and n-1, with n
00615      *                the total number of different labels used in the
00616      *                equivalences vector.
00617      * @return true if successful, false otherwise.
00618      */
00619     bool reassignLabels(const ivector& equivalences,
00620                               imatrix& regions,
00621                         const bool compact = false) const;
00622                         
00623 
00624     /**
00625      * Simple helper method to reassign the labels used in the given labeled
00626      * mask using an equivalences vector, as computed by merge.
00627      *
00628      * You must ensure that the equivalences vector has enough elements to
00629      * avoid an improper memory access, i.e. equivalences.size() >
00630      * regions.maximum().
00631      *
00632      * @param equivalences vector containing for each label \a i the new
00633      *                     label.
00634      * @param regions matrix with the source input labels. 
00635      * @param newRegions the new labels mask will be left here.
00636      * @param compact flag to indicate if the equivalences should be use
00637      *                as they are (false), or if a new labels set should
00638      *                be computed which lies between 0 and n-1, with n
00639      *                the total number of different labels used in the
00640      *                equivalences vector.
00641      * @return true if successful, false otherwise.
00642      */
00643     bool reassignLabels(const ivector& equivalences,
00644                         const imatrix& regions,
00645                               imatrix& newRegions,
00646                         const bool compact = false) const;
00647 
00648 
00649     /**
00650      * Simple helper method to reassign the labels used in the given labeled
00651      * mask using an equivalences vector, as computed by merge.
00652      *
00653      * You must ensure that the equivalences vector has enough elements to
00654      * avoid an improper memory access, i.e. equivalences.size() >
00655      * regions.maximum().
00656      *
00657      * @param equivalences vector containing for each label \a i the new
00658      *                     label.
00659      * @param regions matrix with the source input labels. 
00660      * @param newRegions the new labels mask will be left here.
00661      * @param regionSizes recompute the number of pixels per eventually
00662      *        new region label.
00663      * @param compact flag to indicate if the equivalences should be use
00664      *                as they are (false), or if a new labels set should
00665      *                be computed which lies between 0 and n-1, with n
00666      *                the total number of different labels used in the
00667      *                equivalences vector.
00668      * @return true if successful, false otherwise.
00669      */
00670     bool reassignLabels(const ivector& equivalences,
00671                         const imatrix& regions,
00672                               imatrix& newRegions,
00673                               ivector& regionSizes,
00674                         const bool compact = false) const;
00675     
00676     /**
00677      * Simple helper method to reassign the labels used in the given labeled
00678      * mask using an equivalences vector, as computed by merge.
00679      *
00680      * You must ensure that the equivalences vector has enough elements to
00681      * avoid an improper memory access, i.e. equivalences.size() >
00682      * regions.maximum().
00683      *
00684      * @param equivalences vector containing for each label \a i the new
00685      *                     label.
00686      * @param regions matrix with the source input labels, the resulting
00687      *                labels will be left here too. 
00688      * @param regionSizes recompute the number of pixels per eventually
00689      *        new region label.
00690      * @param compact flag to indicate if the equivalences should be use
00691      *                as they are (false), or if a new labels set should
00692      *                be computed which lies between 0 and n-1, with n
00693      *                the total number of different labels used in the
00694      *                equivalences vector.
00695      * @return true if successful, false otherwise.
00696      */
00697     bool reassignLabels(const ivector& equivalences,
00698                               imatrix& regions,
00699                               ivector& regionSizes,
00700                         const bool compact = false) const;
00701 
00702     /**
00703      * Compact labels
00704      *
00705      * Recompute the equivalences vector to use a compact set of labels.
00706      * @param equivalences equivalences vector as returned by merge()
00707      * @param newEquivalences new compact equivalences vector, where only
00708      *        a compact set of labels is used.
00709      * @return the total number of labels now being used.
00710      */
00711     int compactLabels(const ivector& equivalences,
00712                             ivector& newEquivalences) const;
00713     
00714   protected:
00715     /**
00716      * @name Methods to be reimplemented
00717      */
00718     //@{
00719 
00720     /**
00721      * Check if the internal data is compatible with the region mask.
00722      *
00723      * The weights between region nodes can be computed from very different
00724      * information sources.  Usually, this information is coded in images and
00725      * channels also extracted from the same image from which the regions map
00726      * was computed.  Therefore, it is important to provide a way to check if
00727      * the internal data is compatible with the regions map, since both must
00728      * be provided by the user at different times.
00729      *
00730      * @param regionsSize size of the original image and region mask.
00731      *                    This allows to check for channels and other data 
00732      *                    in the original image size format.
00733      * @param maxRegionIndex maximum region index employed.  This is used
00734      *                       to check if the vectors with information per
00735      *                       region have the appropriate size.
00736      * @return true if the internal data is compatible, false if there 
00737      *         are problems.
00738      */
00739     virtual bool checkInternalData(const point& regionsSize,
00740                                    const int maxRegionIndex) const;
00741 
00742     /**
00743      * For each two neighbor pixels that belong to different regions, this
00744      * method is called to compute the edge data value in a sequential manner.
00745      * It will be assumed, that the default constructor of the
00746      * graph_type::edge_type::data_type "resets" correctly the data of the
00747      * edge.
00748      *
00749      * @param p1 coordinates of pixel belonging to one region
00750      * @param p2 coordinates of pixel belonging to another region
00751      * @param edgeData reference to data structure of the edge, where
00752      *        some values can be accumulated or set.
00753      * @return true if successful, false otherwise.
00754      */
00755     virtual bool considerForEdgeData(const point& p1,
00756                                      const point& p2,
00757                                      edge_data_type& edgeData);
00758 
00759     /**
00760      * For each pixel in each region, this method is called once to 
00761      * compute statistics or other data for each node.
00762      *
00763      * @param p1 coordinates of the current pixel
00764      * @param label identification label for the region to which the pixel
00765      *              belongs.
00766      * @param nodeData reference to the data structure of the node, where
00767      *                 some values can be accumulated or set.
00768      * @return true if successful, false otherwise.
00769      */
00770     virtual bool considerForNodeData(const point& p1,
00771                                      const int label,
00772                                      node_type& nodeData);
00773 
00774     /**
00775      * This method is called just after the topological graph has been
00776      * build and all data of edges and nodes has been considered, and
00777      * before the weights are computed.
00778      *
00779      * You can overload this method to, for example, compute mean values
00780      * per region, compute the min an max values of the means, to adaptivelly
00781      * assign the weights to predefined ranges, etc.
00782      *
00783      * \warning: only the data for the edges(a,b) with a<b contain valid data.
00784      */
00785     virtual bool prepareEdgeAndNodeData(graph_type& graph);
00786     
00787     //@}
00788 
00789     // Protected stuff
00790     
00791     /**
00792      * Copy the bottom left diagonal matrix into the upper left.
00793      * This is used if a symmetric graph has been used, for which at first
00794      * only the data in the bottom matrix is computed.
00795      */
00796     bool mirrorEdgeData(graph_type& graph) const;
00797 
00798     /**
00799      * Generate the adjacency graph for the given labeled mask \a regions.
00800      *
00801      * It is assumed that the nodes of the graph have been already initialized.
00802      *
00803      * @param regions the labeled mask to be analyzed
00804      * @param minLabel only the adjacency between region-labels greater or
00805      *                 equal this value will be fully analyzed.  No graph edges
00806      *                 between regions with labels lower than \a minLabel will
00807      *                 be detected.
00808      * @param graph the adjacency graph to be generated
00809      * @return true if successful, false otherwise.
00810      */
00811     bool generateWorker(const matrix<int>& regions,
00812                         const int minLabel,
00813                               graph_type& graph);
00814 
00815 
00816   };
00817 }
00818 
00819 #include "ltiRegionGraphFunctor_template.h"
00820 #endif
00821 #endif

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