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