Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ConnectedComponentsImpl.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------+
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the Free Software Foundation.  |
00008  |                                                                     |
00009  | This library is distributed in the hope that it will be useful,     |
00010  | but WITHOUT ANY WARRANTY; without even the implied warranty of      |
00011  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 /**
00029  * @file   ConnectedComponentsImpl.C
00030  * @brief  Implementation of class qgar::ConnectedComponentsImpl.
00031  *
00032  *         See file ConnectedComponentsImpl.H for the interface.
00033  *
00034  * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Gérald Masini">Gérald Masini</a>
00035  * @date   May 28, 2004  17:51
00036  * @since  Qgar 2.1.1
00037  */
00038 
00039 
00040 // STL
00041 #include <deque>
00042 #include <iostream>
00043 #include <limits>
00044 #include <list>
00045 #include <string>
00046 #include <vector>
00047 // QGAR
00048 #include <qgarlib/Component.H>
00049 #include <qgarlib/ConnectedComponents.H>
00050 #include <qgarlib/ConnectedComponentsImpl.H>
00051 #include <qgarlib/GenImage.H>
00052 #include <qgarlib/GenTree.H>
00053 #include <qgarlib/QgarErrorAlgorithm.H>
00054 
00055 
00056 namespace qgar
00057 {
00058 
00059 
00060 // -------------------------------------------------------------------
00061 // -------------------------------------------------------------------
00062 // C O N S T R U C T O R
00063 // -------------------------------------------------------------------
00064 // -------------------------------------------------------------------
00065 
00066 
00067 // INITIALIZE DATA TO CONSTRUCT CONNECTED COMPONENTS
00068 
00069 ConnectedComponentsImpl::ConnectedComponentsImpl
00070   (const BinaryImage& aBinImg,
00071    ConnectedComponents::image_type* aPCompImg,
00072    ConnectedComponents::tree_type& aRCompTree,
00073    std::vector<ConnectedComponents::node_type*>& aRCompTab)
00074 
00075   : _width         (aBinImg.width()),      // width of initial binary image
00076     _height        (aBinImg.height()),     // height of initial binary image
00077     _ptRow         (aBinImg.pPixMap()),    // pointer to pixel map of binary image
00078     _labelCnt      (0),                    // label counter
00079     _finalLabelCnt (0),                    // integer final label count
00080     _pCompImg      (aPCompImg),            // pointer to component image
00081     _pMapCCImg     (aPCompImg->pPixMap()), // pointer to pixel map of component image
00082     _rCompTree     (aRCompTree),           // reference to the component tree
00083     _rCompTab      (aRCompTab)             // reference to the component table
00084 
00085 {
00086   // Index of last column of CC image
00087   _colEndIdx = _width - 1;
00088   // Index of last row of CC image
00089   _rowEndIdx = _height - 1;
00090 
00091   // Allocate space for run and label rows
00092   _runRowsTab.reserve(aBinImg.height());
00093   _labelRowsTab.reserve(aBinImg.height());
00094 }
00095 
00096 
00097 // -------------------------------------------------------------------
00098 // -------------------------------------------------------------------
00099 // RUN  THE  CONSTRUCTION  OF  CONNECTED  COMPONENTS
00100 // -------------------------------------------------------------------
00101 // -------------------------------------------------------------------
00102 
00103 
00104 // ALGORITHM TO BUILD CONNECTED COMPONENTS FROM A BINARY IMAGE
00105 
00106 void
00107 ConnectedComponentsImpl::run()
00108   throw(QgarErrorAlgorithm)
00109 {
00110   // =====================================================================
00111   // BEGIN run construction of connected components
00112   // =====================================================================
00113 
00114 
00115   // =====================================================================
00116   // (1) FIRST ROW
00117   // =====================================================================
00118 
00119   // WARNING: First row (like last row) is considered as WHITE
00120   // and belongs to component 0 representing the background
00121 
00122   _equivLabelTab.push_back(Component::_NO_LABEL);  // no equivalent label
00123 
00124   // First component
00125 
00126   _inLabel.push_back(0);           // 0 is conventionally included in 0
00127   _color.push_back(QGE_BW_WHITE);  // color
00128   _xTopLeftPix.push_back(0);       // top left pixel
00129   _yTopLeftPix.push_back(0);
00130   _xTopLeft.push_back(0);          // bounding box
00131   _yTopLeft.push_back(0);
00132   _xBottomRight.push_back(_colEndIdx);
00133   _yBottomRight.push_back(0);
00134   _areaPixels.push_back(_width);   // area
00135 
00136   // First run row and first label row
00137   _runRowsTab.push_back(std::vector<int>(1, _width));
00138   _labelRowsTab.push_back(std::vector<Component::label_type>(1, 0));
00139 
00140   // Run count for this first row,
00141   // to get correct data when processing next row
00142   _currRunIdx = 0;
00143 
00144 
00145   // =====================================================================
00146   // (2) PROCESS NEXT ROWS OF THE BINARY IMAGE
00147   // =====================================================================
00148 
00149   // Initialize pointer to the current row (in the pixel map of the given
00150   // image) to beginning of the 2nd row
00151   _ptRow += _width;
00152 
00153 
00154   for (_rowIdx = 1 ; _rowIdx < _height ; ++_rowIdx )
00155     // FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
00156     // BLOCK-FOR
00157     // for each row of the given image
00158     // FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
00159     {
00160 
00161       // Next row
00162       // WARNING: Rows are supposed to be consecutively stored
00163       //          in the pixel map
00164       _ptRowEnd = _ptRow + _colEndIdx;
00165 
00166       // Index of previous row
00167       _prevRowIdx = _rowIdx - 1;
00168 
00169       // To save current run row and current label row
00170       _runRowsTab.push_back(std::vector<int>());
00171       _labelRowsTab.push_back(std::vector<Component::label_type>());
00172 
00173       // Current run in previous iteration becomes previous run
00174       // in this iteration
00175       _prevRunCnt  = _currRunIdx;
00176 
00177       // Initializations to get correct data from function nextPrevRun()
00178       _prevColor   = QGE_BW_BLACK; // => first run will be WHITE
00179       _prevRunIdx  = -1;
00180       _prevRunEndX = -1;
00181 
00182       // pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
00183       // Get first previous run
00184       // pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
00185 
00186        // Initializations to get correct data from function nextPrevRun()
00187       _prevColor   = QGE_BW_BLACK; // => first run will be WHITE
00188       _prevRunIdx  = -1;
00189       _prevRunEndX = -1;
00190 
00191       nextPrevRun(); // Get first run
00192       // pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
00193 
00194 
00195       // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
00196       // Get first current run
00197       // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
00198       if (_rowIdx == _rowEndIdx)
00199         {
00200           // Processing last row
00201           // WARNING: Last row (like first row) is considered as WHITE
00202           // and belongs to component 0 representing the background
00203           // => last row features are known
00204 
00205           _currRunBeginX = 0;
00206           _currRunEndX   = _colEndIdx;
00207           _currColor     = QGE_BW_WHITE;           // white run
00208           _currLabel     = Component::_NO_LABEL;   // not yet labelled
00209         }
00210       else
00211         {
00212           // Processing any row but the last one
00213 
00214           // Initializations to get correct data from function nextCurrRun()
00215           _currColor   = QGE_BW_BLACK;  // => first run will be WHITE
00216           _currRunEndX = -1;
00217           _currRunIdx  = -1;
00218           _currLabel   = Component::_NO_LABEL;  // not yet labelled
00219           
00220           // WARNING: First pixel is considered as WHITE
00221           // => skip first pixel, whatever its color is
00222           ++_ptRow;
00223 
00224           nextCurrRun(); // Get next current run
00225 
00226           // Increment run end index to take first pixel into account
00227           ++_currRunEndX;
00228         }
00229       // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
00230 
00231 
00232       // Current row is not processed
00233       _moreCurrentRuns = true;
00234 
00235       while (_moreCurrentRuns)
00236         // WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
00237         // WHILE-BLOCK 1
00238         // while all runs in current row are not processed
00239         //
00240         // PREVIOUS RUN AND CURRENT RUN ARE ALWAYS ADJACENT
00241         // WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
00242         {
00243 
00244           if (_currColor == _prevColor)
00245             {
00246               //____________________________________________________________
00247               //
00248               // PREVIOUS RUN AND CURRENT RUN HAVE THE SAME COLOR
00249               // => current run belongs to the same component as previous run
00250               
00251               mergePrevAndCurrComponents();
00252               //____________________________________________________________
00253             }
00254 
00255 
00256           if (_prevRunEndX < _currRunEndX)
00257             {
00258               //____________________________________________________________
00259               //
00260               // (i) CURRENT RUN OVERLAPS PREVIOUS RUN
00261               //     => get next previous run
00262 
00263               nextPrevRun();
00264               //____________________________________________________________
00265             }
00266 
00267           else
00268 
00269             {
00270               // (ii) END OF PREVIOUS AND CURRENT RUNS COINCIDE,
00271               //      OR PREVIOUS RUN OVERLAPS CURRENT RUN
00272               // => if current run is not labelled, it starts a new component 
00273 
00274               if (_currLabel == Component::_NO_LABEL)
00275                 {
00276                   // Get a new label
00277                   if (_labelCnt == Component::_MAX_LABEL)
00278                     {
00279                       std::ostringstream os;
00280                       os << "Cannot deal with more than " << _labelCnt << " labels!";
00281                       throw QgarErrorAlgorithm(__FILE__, __LINE__,
00282                                                "void qgar::ConnectedComponentsImpl::run()",
00283                                                os.str());
00284                     }
00285                   else
00286                     {
00287                       ++_labelCnt;
00288                     }
00289 
00290                   _currLabel = _labelCnt;
00291                   // Label of the comprising component:
00292                   // As previous run has a different color, it always belongs
00293                   // to the component that surrounds the new component
00294                   _inLabel.push_back(_prevLabel);
00295 
00296                   _equivLabelTab.push_back(Component::_NO_LABEL); // no equivalent label
00297                   _xTopLeftPix.push_back(_currRunBeginX);         // top left pixel
00298                   _yTopLeftPix.push_back(_rowIdx);                //
00299                   _xTopLeft.push_back(_currRunBeginX);            // bounding box
00300                   _yTopLeft.push_back(_rowIdx);                   //
00301                   _xBottomRight.push_back(_currRunEndX);          //
00302                   _yBottomRight.push_back(_rowIdx);               //
00303                   _color.push_back(_currColor);                   // color
00304                   _areaPixels.push_back(_currRunEndX - _currRunBeginX + 1); // area
00305 
00306                   // SAVE current run and its label
00307                   _runRowsTab[_rowIdx].push_back(_currRunEndX - _currRunBeginX + 1);
00308                   _labelRowsTab[_rowIdx].push_back(_currLabel);
00309                 }
00310 
00311 
00312               if (_prevRunEndX > _currRunEndX)
00313                 {
00314                 //__________________________________________________________
00315                 //
00316                 // PREVIOUS RUN OVERLAPS CURRENT RUN
00317                 // => get next current run
00318 
00319                   nextCurrRun();
00320                 //__________________________________________________________
00321                 }
00322 
00323               else
00324 
00325                 {
00326                 //__________________________________________________________
00327                 //
00328                 // ENDS OF PREVIOUS RUN AND CURRENT RUN COINCIDE
00329 
00330                   if (_currRunEndX == _colEndIdx)
00331                     {
00332                       // END OF ROW IS REACHED
00333                       _moreCurrentRuns = false;
00334                     }
00335                   else
00336                     {
00337                       prevAndCurrRunsCoincide();
00338                     }
00339                 //__________________________________________________________
00340                 }
00341 
00342             } // END (ii) else part of if(current run overlaps previous run)
00343 
00344         }
00345         // WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
00346         // END BLOCK-WHILE
00347         // all runs in current row are processed
00348         // WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
00349 
00350     }
00351     // FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
00352     // END BLOCK-FOR
00353     // each row of the given image is processed
00354     // FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
00355 
00356 
00357   // ============================================================================
00358   // (3) GET THE FINAL COMPONENTS AND THEIR VALID LABELS
00359   // ============================================================================
00360 
00361   // At this point:
00362   //
00363   //   0  1  2  3  4...  <- component labels (<= _labelCnt)
00364   //  +--+--+--+--+--+-
00365   //  |NO|L1|NO|NO|L4|   _equivLabelTab : equivalent labels
00366   //  +--+--+--+--+--+-
00367   //
00368   //  +--+--+--+--+--+-                                                  --+  C
00369   //  |i0|**|i2|i3|**|   _inLabel      : label of the comprising component |  O
00370   //  +--+--+--+--+--+-                                                    |  M
00371   //  |c0|**|c2|c3|**|   _color        : color                             |  P
00372   //  +--+--+--+--+--+-                                                    |  O
00373   //  |p0|**|p2|p3|**|   _xTopLeftPix  : X of top left pixel               |  N
00374   //  +--+--+--+--+--+-                                                    |  E
00375   //  |P0|**|P2|P3|**|   _yTopLeftPix  : Y of top left pixel               |  N
00376   //  +--+--+--+--+--+-                                                    |  T
00377   //  |t0|**|t2|t3|**|   _xTopLeft     : X of top left corner              >
00378   //  +--+--+--+--+--+-                                                    |
00379   //  |T0|**|T2|T3|**|   _yTopLeft     : Y of top left corner              |  F
00380   //  +--+--+--+--+--+-                                                    |  E
00381   //  |b0|**|b2|b3|**|   _xBottomRight : X of bottom right corner          |  A
00382   //  +--+--+--+--+--+-                                                    |  T
00383   //  |B0|**|B2|B3|**|   _yBottomRight : Y of bottom right corner          |  U
00384   //  +--+--+--+--+--+-                                                    |  R
00385   //  |a0|**|a2|a3|**|   _areaPixels   : area                              |  E
00386   //  +--+--+--+--+--+-                                                  --+  S
00387   //
00388   //
00389   // In _equivLabelTab:
00390   //
00391   // - 'NO LABEL' (qgar::Component::_NO_LABEL) means that the corresponding
00392   //   index in the table represents a valid label, thus corresponds to
00393   //   a valid component. BY CONSTRUCTION, THIS LABEL IS THE SMALLEST OF ALL
00394   //   THE LABELS (TRANSITIVELY) EQUIVALENT TO IT.
00395   //   The component features are available in tables _inLabel, _color,
00396   //    etc. at the same corresponding index.
00397   // - 'Li' means that the corresponding index does not represent a valid
00398   //   label, thus corresponds to a component that has been merged into
00399   //   another one. The features of such a component (**) have no use in
00400   //   the construction of the final component tree.
00401 
00402   // PURPOSE OF THIS SECTION:
00403   //
00404   // - Construct table _finalLabelTab that gives the final labels of the
00405   //   valid components. New labelling is computed so as to get a consecutive
00406   //   final numbering.
00407   //   _finalLabelTab[i] gives the final label of component initially labelled
00408   //   'i', whose features are still available in _inLabel[i], _color[i], etc.
00409   // - Update labels in table _inLabel by substituting the final valid
00410   //   label (given by table _finalLabelTab) for each label (see 3.2 below).
00411   // - Construct list _validCompIdxList that records the indexes
00412   //   of the valid components.
00413   //   Such an index provides a direct access to the features of the
00414   //   corresponding component in tables _inLabel, _color, etc. In table
00415   //   _equivLabelTab, the value at such an index always is "NO LABEL"
00416   //   (see 3.1 below).
00417   //   Index 0, that always corresponds to the component representing the
00418   //   background, is not registered in this list (see 3.3 below).
00419   //
00420   //        +---+---+---
00421   //        | | | | |...  _validCompIdxList
00422   //        +-|-+-|-+---
00423   //          |   |
00424   //          |   |
00425   //          v   v
00426   //    0  1  2   3  4 ...
00427   //   +--+--+--+--+--+-
00428   //   |NO|L1|NO|NO|L4|   _equivLabelTab
00429   //   +--+--+--+--+--+-
00430   //
00431   //   +--+--+--+--+--+-
00432   //   |I0|**|I2|I3|**|   _inLabel (updated)
00433   //   +--+--+--+--+--+-
00434   //   |c0|**|c2|c3|**|   _color
00435   //   +--+--+--+--+--+-
00436   //   |  |**|  |  |**|   etc.
00437   //   +--+--+--+--+--+-
00438   //
00439   //   +--+--+--+--+--+-
00440   //   |l0|l1|l2|l3|  |   _finalLabelTab : final labels
00441   //   +--+--+--+--+--+-
00442   //
00443   // NOTE: Once the required information is computed, table _equivLabelTab
00444   //       becomes useless...
00445 
00446   // Allocate space for the table of final labels 
00447   _finalLabelTab.reserve((unsigned int) _labelCnt);
00448 
00449   // By construction, final label of component 0 (background) is 0
00450   _finalLabelTab.push_back(0);
00451 
00452   // Free labels from the initial equivalence table
00453   std::deque<Component::label_type> freeLabels;
00454 
00455   // For each initial label, excepting 0
00456   for (int lab = 1 ; lab <= _labelCnt ; ++lab)
00457     {
00458       if (_equivLabelTab[lab] == Component::_NO_LABEL)  // **** (3.1) ****
00459         {
00460           // ____________________________________________________________________
00461           //
00462           // CURRENT LABEL IS VALID
00463           // => it corresponds to a valid component
00464           // => give this component a new label when possible
00465 
00466           if (freeLabels.empty())
00467             {
00468               // No free label
00469               // => the current label number remains unchanged
00470               _finalLabelTab.push_back(lab);
00471             }
00472           else
00473             {
00474               // Free labels are available
00475 
00476               // Use first free label
00477               _finalLabelTab.push_back(freeLabels.back());
00478               freeLabels.pop_back();
00479 
00480               // Current label is now free
00481               freeLabels.push_front(lab);
00482             }
00483 
00484           // Update final label count
00485           // (by construction, it can never exceed the maximum label count)
00486           ++_finalLabelCnt;
00487 
00488           // (3.2) Update label of comprising component
00489           // By construction, the corresponding valid label is already known
00490           // (the valid label of a set of equivalent labels is the smallest one)
00491           _inLabel[lab] = _finalLabelTab[_inLabel[lab]];
00492 
00493           // (3.3) Component corresponding to current label is valid
00494           // => save its index
00495           _validCompIdxList.push_back(lab);
00496           // ____________________________________________________________________
00497         }
00498 
00499       else
00500 
00501         {
00502           // ____________________________________________________________________
00503           //
00504           // CURRENT LABEL IS NOT VALID
00505           // => get the corresponding valid label and set equivalence
00506           // By construction, the valid label is not greater than the current label
00507 
00508           _finalLabelTab.push_back(_finalLabelTab[validLabel(lab)]);
00509 
00510           // Current label is now free
00511           freeLabels.push_front(lab);
00512           // ____________________________________________________________________
00513         }
00514 
00515     } // END for
00516 
00517 
00518   // ============================================================================
00519   // (4) CONSTRUCTION OF THE FINAL IMAGE OF LABELS
00520   // ============================================================================
00521 
00522   // For each row rdx of the given binary image
00523   // - _runRowsTab[rdx] gives the successive run lengths
00524   // - _labelRowsTab[rdx] gives the corresponding labels
00525   //   These labels have not been updated and must be substituted by their
00526   //   final equivalent label, given by table _finalLabelTab
00527   
00528   // Pointer to the current pixel in the related pixel map
00529   Component::label_type* pMap = _pMapCCImg;
00530 
00531   // For each row
00532   for (int rdx = 0 ; rdx < _height ; ++rdx)
00533     {
00534       int size = (int) (_labelRowsTab[rdx]).size();
00535 
00536       // for each run
00537       for (int ldx = 0 ; ldx < size ; ++ldx)
00538         {
00539           // Get current run length
00540           int lg = _runRowsTab[rdx][ldx];
00541           // Get corresponding label and update it
00542           Component::label_type lab = _finalLabelTab[_labelRowsTab[rdx][ldx]];
00543 
00544           // Copy the labelled run into the pixel map
00545           for (int idx = 0 ; idx < lg ; ++idx, ++pMap)
00546             {
00547               (*pMap) = lab;
00548             }
00549         }
00550     } // END for each row
00551 
00552 
00553   // ============================================================================
00554   // (5) CONSTRUCT THE COMPONENT TREE
00555   // ============================================================================
00556 
00557   //                     _rCompTree
00558   //                  ________________
00559   //                 |                |    0     j     k
00560   //  +----------+   |      +--+      |   +--+--+--+--+--+- -+--+
00561   //  |COMPONENT |<----------C0|<----------- |  |  |  |  |   |  |  _rCompTab
00562   //  |LABELLED 0|   |      +--+      |   +--+--+|-+--+|-+- -+--+
00563   //  +----------+   |       /\       |          |     |
00564   //                 |      /  \      |          |     |
00565   //  +----------+   |  +--+    +--+  |          |     |
00566   //  |COMPONENT |<------Ci|    |Cj|<------------+     |
00567   //  |LABELLED i|   |  +--+    +--+  |                |
00568   //  +----------+   |    |     /||\  |                |
00569   //  +----------+   |  +--+          |                |
00570   //  |COMPONENT |<------Ck|<--------------------------+
00571   //  |LABELLED k|   |  +--+          |
00572   //  +----------+   |________________|
00573   //
00574   // Each component is associated with a label, which is an integer number.
00575   // In the resulting image, the value of the pixels of the component is this
00576   // same number. See class qgar::Component for the way a component
00577   // is represented.
00578   //
00579   // The set of components is hierarchically organized as a tree. Each node
00580   // represents a component (in fact, the data associated with the node is a
00581   // pointer to the component, 'Ci' in the figure above), and its children
00582   // represent the components which are directly included into (i.e. has a
00583   // common border with) the component.
00584   //
00585   // The so-called component table provides a direct access to the nodes
00586   // representing the components, using their labels to index the table.
00587   // In other words, an element of this table is a pointer to the node of the
00588   // tree representing the component having the same label as the element index.
00589   //
00590   // Indexes of valid components are given by list _validCompIdxList.
00591   // By construction, index 0 (background) is not included in this list.
00592   // (see section 3)
00593 
00594 
00595   // Allocate space for the component table, and initialize it.
00596   // Each element of this table will be a pointer to the component having
00597   // the same label as the index of the element.
00598 
00599   _rCompTab.reserve((unsigned int) _finalLabelCnt);
00600   _rCompTab.insert(_rCompTab.begin(),
00601                    (unsigned int) _finalLabelCnt + 1,
00602                    0);
00603 
00604   // Create component 0 (background)
00605   // and insert it as root of the component tree (initially empty)
00606 
00607   _rCompTree.insertParent
00608     (new Component(_pCompImg,        // pointer to component image
00609                    0,                // label
00610                    0,                // conventional self-inclusion
00611                    QGE_BW_WHITE,     // color
00612                    0,                // X top left pixel
00613                    0,                // Y top left pixel
00614                    0,                // X top left corner (bounding box)
00615                    0,                // Y top left corner (bounding box)
00616                    _colEndIdx,       // X bottom right corner (bounding box)
00617                    _rowEndIdx ,      // Y bottom right corner (bounding box)
00618                    _areaPixels[0])); // area
00619 
00620   // Update component table
00621   _rCompTab[0] = _rCompTree.pRoot();
00622 
00623   // Insert other components
00624   constructComponentTree(_rCompTree, _rCompTree.pRoot(), _rCompTab);
00625 
00626   // Set root as current node of the resulting tree
00627   _rCompTree.gotoRoot();
00628 
00629   // ============================================================================
00630   // END run construction of connected components
00631   // ============================================================================
00632 }
00633 
00634 
00635 // -------------------------------------------------------------------
00636 // -------------------------------------------------------------------
00637 // D E S T R U C T O R
00638 // -------------------------------------------------------------------
00639 // -------------------------------------------------------------------
00640 
00641 
00642 ConnectedComponentsImpl::~ConnectedComponentsImpl()
00643 {
00644   // VOID
00645 }
00646 
00647 
00648 // -------------------------------------------------------------------
00649 // -------------------------------------------------------------------
00650 // F U N C T I O N S   W O R K I N G   O N   L A B E L S
00651 // -------------------------------------------------------------------
00652 // -------------------------------------------------------------------
00653 
00654 
00655 // GET THE VALID LABEL OF (I.E. EQUIVALENT TO) A GIVEN LABEL
00656 
00657 int
00658 ConnectedComponentsImpl::validLabel(Component::label_type aLabel)
00659 {
00660   Component::label_type l = aLabel;
00661 
00662   // The valid label is the smallest equivalent label
00663   // => just follow the equivalent links until finding no link
00664 
00665   while (_equivLabelTab[l] != Component::_NO_LABEL)
00666     {
00667       l = _equivLabelTab[l];
00668     }
00669 
00670   return l;
00671 }
00672 
00673 
00674 // -------------------------------------------------------------------
00675 // -------------------------------------------------------------------
00676 // F U N C T I O N S   W O R K I N G   O N   C O M P O N E N T S 
00677 // -------------------------------------------------------------------
00678 // -------------------------------------------------------------------
00679 
00680 // MERGE COMPONENT INCLUDING PREVIOUS RUN
00681 // AND COMPONENT INCLUDING CURRENT RUN
00682 //
00683 // WARNING: By construction, component with the greatest label must be
00684 // merged into component with the smallest label
00685 
00686 void
00687 ConnectedComponentsImpl::mergePrevAndCurrComponents()
00688 {
00689   if (_currLabel == Component::_NO_LABEL)
00690 
00691     // ______________________________________________________________
00692     {
00693       // CURRENT RUN IS NOT YET LABELLED
00694       // => merge current run into previous valid component
00695 
00696       // The valid label of the previous run becomes the current label
00697       _currLabel = validLabel(_prevLabel);
00698 
00699       // The top left pixel of the component should not change
00700       // No update necessary
00701 
00702       // Update bounding box
00703       if (_currRunBeginX < _xTopLeft[_currLabel])
00704         {
00705           _xTopLeft[_currLabel] = _currRunBeginX;
00706         }
00707       if (_currRunEndX > _xBottomRight[_currLabel])
00708         {
00709           _xBottomRight[_currLabel] = _currRunEndX;
00710         }
00711       _yBottomRight[_currLabel] = _rowIdx;
00712 
00713       // Update area
00714       _areaPixels[_currLabel] += _currRunEndX - _currRunBeginX + 1;
00715 
00716       // SAVE current run and its label
00717       _runRowsTab[_rowIdx].push_back(_currRunEndX - _currRunBeginX + 1);
00718       _labelRowsTab[_rowIdx].push_back(_currLabel);
00719     }
00720     // ______________________________________________________________
00721 
00722   else
00723 
00724     {
00725       // Valid labels of previous and current runs
00726       Component::label_type prevValidLabel = validLabel(_prevLabel);
00727       Component::label_type currValidLabel = validLabel(_currLabel);
00728 
00729       if (prevValidLabel == currValidLabel)
00730         // __________________________________________________________
00731         {
00732           // PREVIOUS AND CURRENT RUNS
00733           // ALREADY BELONG TO THE SAME COMPONENT
00734           // => nothing to do
00735           return;
00736         }
00737         // __________________________________________________________
00738 
00739       if (prevValidLabel < currValidLabel)
00740 
00741         // __________________________________________________________
00742         {
00743           // THE VALID LABEL OF THE PREVIOUS RUN
00744           // IS SMALLER THAN THE VALID LABEL OF THE CURRENT RUN
00745           // => merge component of the current run
00746           //    into component of the previous run
00747 
00748           // Update top left pixel
00749           if (_yTopLeftPix[currValidLabel] < _yTopLeftPix[prevValidLabel])
00750             {
00751               _xTopLeftPix[prevValidLabel] = _xTopLeftPix[currValidLabel];
00752               _yTopLeftPix[prevValidLabel] = _yTopLeftPix[currValidLabel];
00753             }
00754 
00755           // Update bounding box
00756           if (_xTopLeft[currValidLabel] < _xTopLeft[prevValidLabel])
00757             {
00758               _xTopLeft[prevValidLabel] = _xTopLeft[currValidLabel];
00759             }
00760           if (_yTopLeft[currValidLabel] < _yTopLeft[prevValidLabel])
00761             {
00762               _yTopLeft[prevValidLabel] = _yTopLeft[currValidLabel];
00763             }
00764           if (_xBottomRight[currValidLabel] > _xBottomRight[prevValidLabel])
00765             {
00766               _xBottomRight[prevValidLabel] = _xBottomRight[currValidLabel];
00767             }
00768           if (_yBottomRight[currValidLabel] > _yBottomRight[prevValidLabel])
00769             {
00770               _yBottomRight[prevValidLabel] = _yBottomRight[currValidLabel];
00771             }
00772 
00773           // Update area
00774           _areaPixels[prevValidLabel] += _areaPixels[currValidLabel];
00775           
00776           // Update table of equivalent labels
00777           _equivLabelTab[_currLabel]      = prevValidLabel;
00778           _equivLabelTab[currValidLabel] = prevValidLabel;
00779 
00780           // Update labels
00781           _prevLabel = prevValidLabel;
00782           _currLabel = prevValidLabel;
00783         }
00784         // __________________________________________________________
00785 
00786       else
00787 
00788         // __________________________________________________________
00789         {
00790           // THE VALID LABEL OF THE CURRENT RUN
00791           // IS SMALLER THAN THE VALID LABEL OF THE PREVIOUS RUN
00792           // => merge component of the previous run
00793           //    into component of the current run
00794 
00795           // Update top left pixel
00796           if (_yTopLeftPix[prevValidLabel] < _yTopLeftPix[currValidLabel])
00797             {
00798               _xTopLeftPix[currValidLabel] = _xTopLeftPix[prevValidLabel];
00799               _yTopLeftPix[currValidLabel] = _yTopLeftPix[prevValidLabel];
00800             }
00801 
00802           // Update bounding box
00803           if (_xTopLeft[prevValidLabel] < _xTopLeft[currValidLabel])
00804             {
00805               _xTopLeft[currValidLabel] = _xTopLeft[prevValidLabel];
00806             }
00807           if (_yTopLeft[prevValidLabel] < _yTopLeft[currValidLabel])
00808             {
00809               _yTopLeft[currValidLabel] = _yTopLeft[prevValidLabel];
00810             }
00811           if (_xBottomRight[prevValidLabel] > _xBottomRight[currValidLabel])
00812             {
00813               _xBottomRight[currValidLabel] = _xBottomRight[prevValidLabel];
00814             }
00815           if (_yBottomRight[prevValidLabel] > _yBottomRight[currValidLabel])
00816             {
00817               _yBottomRight[currValidLabel] = _yBottomRight[prevValidLabel];
00818             }
00819 
00820           // Update area
00821           _areaPixels[currValidLabel] += _areaPixels[prevValidLabel];
00822 
00823           // Update equivalent labels
00824           _equivLabelTab[_prevLabel]      = currValidLabel;
00825           _equivLabelTab[prevValidLabel] = currValidLabel;
00826           
00827           // Update labels
00828           _prevLabel = currValidLabel;
00829           _currLabel = currValidLabel;
00830         }
00831         // __________________________________________________________
00832     }
00833 
00834 }
00835 
00836 
00837 // -------------------------------------------------------------------
00838 // -------------------------------------------------------------------
00839 // F U N C T I O N S   W O R K I N G   O N   R U N S
00840 // -------------------------------------------------------------------
00841 // -------------------------------------------------------------------
00842 
00843 // MOVE TO NEXT RUN IN PREVIOUS ROW
00844 
00845 void
00846 ConnectedComponentsImpl::nextPrevRun()
00847 {
00848   // Increment previous run index
00849   ++_prevRunIdx;
00850 
00851   // New current run label
00852   _prevLabel = _labelRowsTab[_prevRowIdx][_prevRunIdx];
00853 
00854   // New current run indexes
00855   _prevRunBeginX = _prevRunEndX + 1;
00856   _prevRunEndX   = _prevRunBeginX + _runRowsTab[_prevRowIdx][_prevRunIdx] - 1;
00857 
00858   // New current run color
00859   _prevColor = qgBWswitch(_prevColor);
00860 }
00861 
00862 
00863 // MOVE TO NEXT RUN IN CURRENT ROW
00864 
00865 void
00866 ConnectedComponentsImpl::nextCurrRun()
00867 {
00868   if (_ptRow != _ptRowEnd)
00869     {
00870       // _____________________________________________________________
00871       //
00872       // End of current row is not yet reached
00873 
00874       _currRunBeginX = _currRunEndX + 1;    // new run beginning index
00875       _currColor = qgBWswitch(_currColor);  // new current color
00876 
00877       // Look for index of new run end (while pixels have the current color)
00878 
00879       while ((*_ptRow == _currColor) && (_ptRow < _ptRowEnd))
00880         //                               ^^^^^^^^^^^^^^^^^^
00881         // WARNING: The last pixel pixel is not taken into account
00882         //          as it is always considered as WHITE
00883         {
00884           ++_ptRow;
00885           ++_currRunEndX;
00886         }
00887       
00888       // WARNING: Last pixel considered as WHITE
00889       // => If row end is reached and new run is WHITE,
00890       //    add last pixel to new run
00891 
00892       if ((_ptRow == _ptRowEnd) && (_currColor == QGE_BW_WHITE))
00893         {
00894           ++_ptRow;
00895           ++_currRunEndX;
00896         }
00897       // _____________________________________________________________
00898     }
00899   else
00900     {
00901       // _____________________________________________________________
00902       //
00903       // End of current row is reached: Whatever the color
00904       // of the last pixel is, it is considered as WHITE
00905       // By construction, current run is BLACK before this point
00906       // (see above): The last pixel determines a one-pixel WHITE run.
00907 
00908       ++_ptRow;
00909 
00910       // New run includes only 1 pixel and is WHITE
00911       _currRunEndX += 1;
00912       _currRunBeginX = _currRunEndX;
00913       _currColor = QGE_BW_WHITE;
00914       // _____________________________________________________________
00915     }
00916 
00917   ++_currRunIdx;                      // New current run index
00918   _currLabel = Component::_NO_LABEL;  // New run has is not yet labelled
00919 }
00920 
00921 
00922 // END OF PREVIOUS RUN AND END OF CURRENT RUN COINCIDE
00923 // => PERFORM MOVES ACCORDING TO BLACK- AND WHITE-CONNEXITY
00924 //
00925 // WARNING
00926 // End of current row must be tested before calling this function
00927 
00928 void
00929 ConnectedComponentsImpl::prevAndCurrRunsCoincide()
00930 {
00931   if (_currColor == _prevColor)
00932     {
00933       // PREVIOUS RUN AND CURRENT HAVE THE SAME COLOR
00934       //
00935       //  end of previous run
00936       //            v 
00937       //  -+-+-+-+-+-+-+-+-+-+-
00938       //   |x|x|x|x|x|y|y|y|y|
00939       //  -+-+-+-+-+-+-+-+-+-+-
00940       //   |x|x|x|x|x|y|y|y|y|
00941       //  -+-+-+-+-+-+-+-+-+-+-
00942       //            ^
00943       //  end of current run
00944       //
00945       // => just move to next run in previous and current rows
00946 
00947       nextPrevRun();
00948       nextCurrRun();
00949     }
00950 
00951   //      b b b               w
00952   //      b * b             w * w
00953   //      b b b               w
00954   //
00955   //   8-connexity       4-connexity
00956   //    for BLACK         for WHITE
00957 
00958   else if (_currColor == QGE_BW_WHITE)
00959     {
00960       // PREVIOUS RUN IS BLACK AND CURRENT RUN IS WHITE
00961       //
00962       //  end of previous run
00963       //            v 
00964       //  -+-+-+-+-+-+-+-+-+-+-
00965       //   |b|b|b|b|b|w|w|w|w|        previous run
00966       //  -+-+-+-+-+-+-+-+-+-+-       is connex to
00967       //   |w|w|w|w|w|b|b|b|b|        next current run
00968       //  -+-+-+-+-+-+-+-+-+-+-
00969       //            ^
00970       //  end of current run
00971       //
00972       // => move to next run in current row
00973   
00974       nextCurrRun();
00975     }
00976   else
00977     {
00978       // PREVIOUS RUN IS WHITE AND CURRENT RUN IS BLACK
00979       //
00980       //  end of previous run
00981       //            v 
00982       //  -+-+-+-+-+-+-+-+-+-+-
00983       //   |w|w|w|w|w|b|b|b|b|        next previous run
00984       //  -+-+-+-+-+-+-+-+-+-+-       is connex to
00985       //   |b|b|b|b|b|w|w|w|w|        current run
00986       //  -+-+-+-+-+-+-+-+-+-+-
00987       //            ^
00988       //  end of current run
00989       //
00990       // => move to next run in previous row
00991       
00992       nextPrevRun();
00993     }
00994 }
00995 
00996 
00997 // -------------------------------------------------------------------
00998 // -------------------------------------------------------------------
00999 // FUNCTIONS  WORKING  ON  THE  COMPONENT  TREE
01000 // -------------------------------------------------------------------
01001 // -------------------------------------------------------------------
01002 
01003 // CONSTRUCT THE COMPONENT TREE
01004 
01005 // Each node represents a component
01006 // Components represented by children nodes are included
01007 // in the component represented by their parent node
01008 
01009 // aTree  : reference to the tree being constructed
01010 // aPNode : pointer to a node representing a component
01011 //          which has not yet children
01012 // aCCTab : reference to the table containing pointers to components
01013 //          aCCTab[lab] gives a pointer to the component labelled 'lab'
01014 //          (lab is final valid label)
01015 
01016 // _validCompIdxList provides components which are not yet included
01017 // in the tree: Each of its elements is an index of a valid component
01018 // in tables storing component features.
01019 
01020 void
01021 ConnectedComponentsImpl::constructComponentTree
01022   (ConnectedComponents::tree_type& aTree,
01023    ConnectedComponents::node_type* aPNode,
01024    std::vector<ConnectedComponents::node_type*>& aCCTab)
01025 {
01026   // No more component to insert in the tree
01027   if (_validCompIdxList.size() == 0)
01028     {
01029       return;
01030     }
01031 
01032   // Label of the given component
01033   Component::label_type parentLabel = (aPNode->accessData())->label();
01034   
01035   std::list<int>::iterator itCC = _validCompIdxList.begin();
01036 
01037   while (itCC != _validCompIdxList.end())
01038     {
01039 
01040     // While there are components
01041     // ______________________________________________________________
01042     //
01043       // Index of the current component
01044       int ccIdx = *itCC;
01045       // Valid label of the current component
01046       Component::label_type lab = _finalLabelTab[ccIdx];
01047 
01048       if (_inLabel[ccIdx] == parentLabel)
01049         {
01050           // CURRENT COMPONENT IS INCLUDED IN GIVEN COMPONENT (NODE)
01051           // => it becomes a child of the given component
01052 
01053           // Instantiation of a new component
01054           // and insertion in the component tree
01055           aTree.insertFirstChild
01056             (new Component(_pCompImg,            // pointer component image
01057                            lab,                  // label
01058                            _inLabel[ccIdx],      // comprising component label
01059                            _color[ccIdx],        // color
01060                            _xTopLeftPix[ccIdx],  // top left pixel
01061                            _yTopLeftPix[ccIdx],  //
01062                            _xTopLeft[ccIdx],     // bounding box
01063                            _yTopLeft[ccIdx],     //
01064                            _xBottomRight[ccIdx], //
01065                            _yBottomRight[ccIdx], //
01066                            _areaPixels[ccIdx]),  // area
01067              aPNode);
01068 
01069           // Update component table
01070           aCCTab[lab] = aPNode->pFirstChild();
01071 
01072           // Remove index of current component from available indexes
01073           // WARNING: Removal invalidates the iterator that points
01074           //          to the removed element
01075 
01076           // Save iterator
01077           std::list<int>::iterator itCCaux = itCC;
01078           // Increment iterator to get next component index
01079           ++itCC;
01080           // Delete used index
01081           _validCompIdxList.erase(itCCaux);
01082         }
01083       else
01084         {
01085           // CURRENT COMPONENT IS NOT INCLUDED IN GIVEN COMPONENT (NODE)
01086           // => just increment iterator to get next component index
01087           ++itCC;
01088         }
01089 
01090     } // END while
01091     // ______________________________________________________________
01092 
01093   
01094   // Look for children of each new included component
01095 
01096   ConnectedComponents::node_type* pChild = aPNode->pFirstChild();
01097 
01098   while (pChild != 0)
01099     {
01100       constructComponentTree(aTree, pChild, aCCTab);
01101       pChild = pChild->pRSibling();
01102     }
01103 }
01104 
01105 // -------------------------------------------------------------------
01106 // -------------------------------------------------------------------
01107 
01108 } // namespace qgar