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