src/qvdta/qvcomponenttree.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      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 QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <qvdta/qvcomponenttree.h>
00026 
00027 #define MIN(X,Y)        (((X)>(Y))?(Y):(X))
00028 #define MAX(X,Y)        (((X)>(Y))?(X):(Y))
00029 
00030 namespace qvdta
00031 {
00032 void pruneLowComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00033         {
00034         Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00035         Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00036         Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00037 
00038         bool prune = false;
00039         int lastValidThreshold = validThreshold;
00040 
00041         // Here we decide if this node should be directly pruned
00042         // or if there's any sub-node we should prune
00043         for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00044                 if (componentTree.area(node)[threshold] > 0)
00045                         {
00046                         if (componentTree.area(node)[threshold] < minArea)
00047                                 prune = true;
00048                         else
00049                                 lastValidThreshold = threshold;
00050                         }
00051 
00052         // We prune node, or get on with it's childrens
00053         if (prune)
00054                 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), lastValidThreshold, 0, lastValidThreshold-1);
00055         else
00056                 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00057                         pruneLowComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00058         }
00059 
00060 void pruneHighComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00061         {
00062         Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00063         Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00064         Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00065 
00066         bool prune = false;
00067         int lastValidThreshold = validThreshold;
00068 
00069         // Here we decide if this node should be directly pruned
00070         // or if there's any sub-node we should prune
00071         for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00072                 if (componentTree.area(node)[threshold] > 0)
00073                         {
00074                         if (componentTree.area(node)[threshold] < minArea)
00075                                 prune = true;
00076                         else
00077                                 lastValidThreshold = threshold;
00078                         }
00079 
00080         // We prune node, or get on with it's childrens
00081         if (prune)
00082                 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00083         else
00084                 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00085                         pruneHighComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00086         }
00087 
00088 void FilterComponentTreeSmallRegions(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea)
00089         {
00090         qDebug() << "pruneRegions()";
00091         if (componentTree.isInverseTree())
00092                 {
00093                 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00094                         pruneHighComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00095                 }
00096         else    {
00097                 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00098                         pruneLowComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00099                 }
00100 
00101         qDebug() << "pruneRegions() <~ return";
00102         }
00103 
00105 
00106 QVComponentTree::QVComponentTree(const QVImage<uChar,1> &image, bool inverseTree, bool useAlternative): numNodes(0), freePoints(0), inverseTree(inverseTree)
00107         {
00108         const uInt cols = image.getCols(), rows = image.getRows();
00109         maxNodes = cols * rows;
00110 
00111         // 10 factor is an heuristic value, estimated from several tries.
00112         nodes.resize(maxNodes/10);
00113 
00114         if (inverseTree)
00115                 {
00116                 QVImage<uChar> notImage(cols, rows);
00117 
00118                 QVIMAGE_INIT_READ(uChar,image);
00119                 QVIMAGE_INIT_WRITE(uChar,notImage);
00120                 for (uInt col = 0; col < cols; col++)
00121                         for (uInt row = 0; row < rows; row++)
00122                                 QVIMAGE_PIXEL(notImage, col, row,0) = 255 - QVIMAGE_PIXEL(image, col, row,0);
00123 
00124                 if (useAlternative)
00125                         getComponentTree2(notImage);
00126                 else
00127                         getComponentTree(notImage);
00128                 }
00129         else    {
00130                 if (useAlternative)
00131                         getComponentTree2(image);
00132                 else
00133                         getComponentTree(image);
00134                 }
00135         }
00136 
00137 QVComponentTree::~QVComponentTree()
00138         {
00139         //delete nodes;
00140         }
00141 
00142 void QVComponentTree::getComponentTree(const QVImage<uChar> &image)
00143         {
00144         qDebug() << "getComponentTree()";
00145         const uInt cols = image.getCols(), rows = image.getRows();
00146         const QVector< QVector< QPoint > > points = qvdta::CountingSort(image);
00147 
00148         uInt *nodeID = new uInt[maxNodes];
00149         for(uInt i=0; i<maxNodes; i++)
00150                 nodeID[i] = NULL_NODE;
00151 
00152         qvdta::QVDisjointSet disjointSet(cols, rows);
00153 
00154         this->numNodes = 0;
00155         this->leafNodes = 0;
00156         this->freePoints = 0;
00157         this->totalPoints = 0;
00158 
00159         for (uInt i=0; i< cols*rows; i++)
00160                 Q_ASSERT(nodeID[i] == NULL_NODE);
00161 
00162         // This loop creates the structure of the component tree, using the disjoint set, transversiong the pixels of the image
00163         // ordered by their gray-scale value, sorted thanks to 'CountingSort' function.
00164         QVIMAGE_INIT_READ(uChar,image);
00165 
00166         for (int threshold = 0; threshold < points.size(); threshold++)
00167                 {
00168                 // We join in the disjoint set pixels with gray-scale equal to threshold, with adjacent regions, or pixels, with
00169                 // a gray-scale value equal or lesser than threshold. This is done here only for the disjoint set.
00170                 //
00171                 // Also, here are also joined component tree nodes which have in common one of the processed points.
00172                 for (int n=0; n< points[threshold].size(); n++)
00173                         {
00174                         const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00175                         const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00176 
00177                         // Transverse neighbourhood of a pixel looking for close pixels to join with
00178                         // (those with gray-scale level lower or equal to that of the actual pixel)
00179                         for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00180                                 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00181                                         if ((col != i) || (row != j))
00182                                         {
00183                                         const uInt vecinoSet = disjointSet.find(i,j), actualSet = disjointSet.find(col, row);
00184                                         const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j,0);
00185 
00186                                         if ( (vecinoPixel <= actualPixel) && (vecinoSet != actualSet) )
00187                                                 {
00188                                                 // We should join this pixel to the set of the neighbour
00189                                                 const uInt      newPointID = disjointSet.unify(col, row, i, j),
00190                                                                 actualNodeID = nodeID[actualSet],
00191                                                                 vecinoNodeID = nodeID[vecinoSet];
00192 
00193                                                 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00194                                                 Q_ASSERT( (actualSet == newPointID) || (vecinoSet == newPointID) );
00195 
00196                                                 // If new is not in a node already, we associate it with the point that is associated to a node.
00197                                                 if (actualNodeID == NULL_NODE)
00198                                                         nodeID[newPointID] = vecinoNodeID;
00199                                                 else if (vecinoNodeID == NULL_NODE)
00200                                                         nodeID[newPointID] = actualNodeID;
00201 
00202                                                 // Otherwise, both actual and neighbour are associated to a node already.
00203                                                 // We create a new node, and join both nodes of actual and neighbour pixels to
00204                                                 // that one.
00205                                                 else    {
00206                                                         Q_ASSERT(actualNodeID != NULL_NODE);
00207                                                         Q_ASSERT(vecinoNodeID != NULL_NODE);
00208 
00209                                                         // We check that no one of the nodes of actual and neighbour pixels
00210                                                         // is new. In that case it will be parent node.
00211                                                         if (!validNode(actualNodeID) && validNode(vecinoNodeID))
00212                                                                 // We just add the node...
00213                                                                 {
00214                                                                 addChild(actualNodeID, vecinoNodeID);
00215                                                                 nodeID[newPointID] = actualNodeID;
00216                                                                 }
00217                                                         else if (validNode(actualNodeID) && !validNode(vecinoNodeID))
00218                                                                 // We just add the other node...
00219                                                                 {
00220                                                                 addChild(vecinoNodeID, actualNodeID);
00221                                                                 nodeID[newPointID] = vecinoNodeID;
00222                                                                 }
00223                                                         else if (validNode(actualNodeID) && validNode(vecinoNodeID))
00224                                                                 // We have two old nodes, and creaate a parent to unify them.
00225                                                                 {
00226                                                                 const uInt newNodeID = newNode(col, row, threshold);;
00227                                                                 nodeID[disjointSet.index(col, row)] = newNodeID;
00228 
00229                                                                 addChild(newNodeID, actualNodeID);
00230                                                                 addChild(newNodeID, vecinoNodeID);
00231                                                                 nodeID[newPointID] = newNodeID;
00232                                                                 }
00233                                                         else // if ( !NODE(actualNodeID).inited and !NODE(vecinoNodeID).inited )
00234                                                                 // We have two parent nodes, we leave things as they are.
00235                                                                 // No, we should unify both, passing childs of one of them to the
00236                                                                 // other.
00237                                                                 {
00238                                                                 Q_ASSERT(validNode(actualNodeID) == false);
00239                                                                 Q_ASSERT(validNode(vecinoNodeID) == false);
00240                                                                 Q_ASSERT(numChilds(actualNodeID) > 0);
00241                                                                 Q_ASSERT(numChilds(vecinoNodeID) > 0);
00242 
00243                                                                 uInt child;
00244                                                                 for (   child = firstChild(actualNodeID);
00245                                                                         nextSibling(child) != NULL_NODE;
00246                                                                         child = nextSibling(child));
00247 
00248                                                                 uInt lastActualChildNodeID = firstChild(actualNodeID);
00249                                                                 while (nextSibling(lastActualChildNodeID) != NULL_NODE)
00250                                                                         lastActualChildNodeID =
00251                                                                                 nextSibling(lastActualChildNodeID);
00252 
00253                                                                 numChilds(actualNodeID) += numChilds(vecinoNodeID);
00254                                                                 nextSibling(lastActualChildNodeID) = firstChild(vecinoNodeID);
00255                                                                 nodeID[newPointID] = actualNodeID;
00256                                                                 }
00257                                                         }
00258                                                 Q_ASSERT(nodeID[disjointSet.find(disjointSet.index(col, row))] == nodeID[disjointSet.find(disjointSet.index(i, j))]);
00259                                                 }
00260                                         }
00261                         }
00262 
00263                 // In this loop we actualize areas for the gray-level of the threshold of the two old nodes, and create new nodes, 
00264                 // case we find a set of one or several pixels of gray-scale value equal to threshold value, which are not joined
00265                 // to any connected set represented already in a node of the component tree.
00266                 //
00267                 // In this point, we have processed all pixels with gray-scale value equal or lesser to threshold. All of them are
00268                 // grouped to a group of pixels with same gray-scale level, in which case we have the vertex of a node, or well
00269                 // or well joined to a previously created node.
00270                 //
00271                 // Then we creater for the former case new nodes, and in any case we actualize areas for nodes with new points
00272                 // in them.
00273                 for (int n=0; n< points[threshold].size(); n++)
00274                         {
00275                         Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00276                         const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00277                         const uInt actualID = disjointSet.index(col, row);
00278 
00279                         Q_ASSERT_X(actualID < cols * rows, "getComponentTree", "out of bounds 5");
00280 
00281                         // We have a pixel with gray-scale level equal to threshold, and disjoint set identificator equal to himself.
00282                         // This means either it is an isolated pixel, surrounded by pixels of gray-scale level higher than his, or
00283                         // that he is in a connected set of pixels, all of them with exactly gray-scale level value of threshold
00284                         // (and we hill be the only one of that set, with disjoint set identificator equal to himself).
00285                         // Either case we create a new node, with seed point equal to this node.
00286                         if (actualID == disjointSet.find(actualID))
00287                                 {
00288                                 if (nodeID[actualID] == NULL_NODE)
00289                                         // We have a header point for the new component tree node.
00290                                         // We initialize the values for his node.
00291                                         {
00292                                         nodeID[disjointSet.index(col, row)] = newNode(col, row, threshold);
00293                                         this->leafNodes++;
00294                                         }
00295                                 else    // Actual pixel is associated to a node, but this one was created for other pixel.
00296                                         // We count as a free pixel the one that created the node that contains actual pixel.
00297                                         this->freePoints++;
00298                                 }
00299                         else    // Actual pixel is not group heading
00300                                 {
00301                                 this->freePoints++;
00302                                 // Why this isn't generally true?
00303                                 //Q_ASSERT(this->nodeID[actualID] == NULL_NODE);
00304                                 }
00305 
00306                         const uInt actualNodeID = nodeID[disjointSet.find(actualID)];
00307                         if (actualNodeID != NULL_NODE)
00308                                 {
00309                                 Q_ASSERT(area(actualNodeID)[lastThreshold(actualNodeID)] <= disjointSet.getSetCardinality(actualID));
00310                                 lastThreshold(actualNodeID) = threshold;
00311                                 area(actualNodeID)[threshold] = disjointSet.getSetCardinality(actualID);
00312                                 validNode(actualNodeID) = true;
00313                                 }
00314                         // Actualize total number of points
00315                         this->totalPoints++;
00316                         }
00317                 }
00318 
00319         rootNode() = nodeID[disjointSet.find(0)];
00320 
00321         // COMPONENT TREE FINISHED. STARTING TESTS...
00322         #ifndef QT_NO_DEBUG     // TEST 
00323         Q_ASSERT(validNode(this->rootNodeID));
00324 
00325         // Checking that actually number of nodes, and number of nodes with ID != NULL_NODE equals the
00326         // value holded in this->numNodes.
00327         uInt sumNodes = 0, sumChildNodes = 0, sumLeafNodes = 0;
00328 
00329         // Checking some basic tree structure and values
00330         for (uInt node = 0; node < this->numNodes; node++)
00331                 if (validNode(node))
00332                         {
00333                         const uInt fThreshold = firstThreshold(node), lThreshold = lastThreshold(node);
00334 
00335                         if (numChilds(node) == 0)
00336                                 sumLeafNodes++;
00337 
00338                         sumNodes++;
00339                         // Checking areas correctness
00340                         Q_ASSERT(area(node)[fThreshold] <= area(node)[lThreshold] != 0);
00341                         Q_ASSERT(area(node)[fThreshold] != 0);
00342                         Q_ASSERT(area(node)[lThreshold] != 0);
00343 
00344                         // Check that seed pixel correspond with first threshold
00345                         Q_ASSERT(image(seedX(node), seedY(node)) == fThreshold);
00346 
00347                         // Check areas go from lesser size to bigger
00348                         uInt lastArea = area(node)[fThreshold];
00349                         for (uInt threshold = fThreshold+1; threshold <= lThreshold; threshold++)
00350                                 if (area(node)[threshold] != 0)
00351                                         {
00352                                         const uInt actualArea = area(node)[threshold];
00353                                         Q_ASSERT(actualArea >= lastArea);
00354                                         lastArea = actualArea;
00355                                         }
00356 
00357                         uInt maxAreasChilds = 0;
00358                         uInt childs = 0;
00359                         for (   uint child = firstChild(node);
00360                                 child != NULL_NODE;
00361                                 child = nextSibling(child), childs++)
00362                                 {
00363                                 Q_ASSERT(childs < numChilds(node));
00364                                 Q_ASSERT(child < this->numNodes);
00365                                 Q_ASSERT(child != rootNode());
00366                                 Q_ASSERT(validNode(child));
00367                                 maxAreasChilds += area(child)[lastThreshold(child)];
00368                                 }
00369 
00370                         Q_ASSERT(area(node)[firstThreshold(node)] > maxAreasChilds);
00371                         Q_ASSERT(childs == numChilds(node));
00372 
00373                         sumChildNodes += numChilds(node);
00374                 }
00375         qDebug() << "getComponentTree(): /////// estadisticos";
00376         qDebug() << "getComponentTree(): sumNodes = " << sumNodes << sumChildNodes;
00377         Q_ASSERT( sumNodes == (sumChildNodes+1) );
00378         Q_ASSERT( this->leafNodes == sumLeafNodes );
00379 
00380         qDebug() << "getComponentTree(): this->numNodes = " << this->numNodes;
00381         qDebug() << "getComponentTree(): this->freePoints = "<< this->freePoints;
00382         qDebug() << "getComponentTree(): this->totalPoints = "<< this->totalPoints;
00383         qDebug() << "getComponentTree(): this->leafNodes + this->freePoints = "
00384                         << this->leafNodes + this->freePoints;
00385 
00386         Q_ASSERT(disjointSet.numberOfSets() == 1);
00387         Q_ASSERT(disjointSet.getSetCardinality(rootNode()) == (image.getCols() * image.getRows()));
00388         Q_ASSERT(this->totalPoints == (image.getCols() * image.getRows()));
00389         Q_ASSERT(this->totalPoints == this->leafNodes + this->freePoints);
00390 
00391         #endif // END TEST 
00392 
00393         delete nodeID;
00394 
00395         qDebug() << "getComponentTree() <~ return";
00396         }
00397 
00398 
00404 
00405 void QVComponentTree::getComponentTree2(const QVImage<uChar> &image)
00406         {
00407         qDebug() << "getComponentTree()";
00408         const uInt cols = image.getCols(), rows = image.getRows();
00409         const QVector< QVector< QPoint > > points = qvdta::CountingSort(image);
00410 
00411         uInt *nodeID = new uInt[maxNodes];
00412         for(uInt i=0; i<maxNodes; i++)
00413                 nodeID[i] = NULL_NODE;
00414 
00415         qvdta::QVDisjointSet disjointSet(cols, rows);
00416 
00417         this->numNodes = 0;
00418         this->leafNodes = 0;
00419         this->freePoints = 0;
00420         this->totalPoints = 0;
00421 
00422         for (uInt i=0; i< cols*rows; i++)
00423                 Q_ASSERT(nodeID[i] == NULL_NODE);
00424 
00425         // This loop creates the structure of the component tree, using the disjoint set, transversiong the pixels of the image
00426         // ordered by their gray-scale value, sorted thanks to 'CountingSort' function.
00427         QVIMAGE_INIT_READ(uChar,image);
00428 
00429         for (int threshold = 0; threshold < points.size(); threshold++)
00430                 {
00431                 // We join in the disjoint set pixels with gray-scale equal to threshold, with adjacent regions, or pixels, with
00432                 // a gray-scale value equal or lesser than threshold. This is done here only for the disjoint set.
00433                 //
00434                 // Also, here are also joined component tree nodes which have in common one of the processed points.
00435                 for (int n=0; n< points[threshold].size(); n++)
00436                         {
00437                         const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00438                         const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00439 
00440                         // Transverse neighbourhood of a pixel looking for close pixels to join with
00441                         // (those with gray-scale level lower or equal to that of the actual pixel)
00442                         for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00443                                 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00444                                         if ((col != i) || (row != j))
00445                                         {
00446                                         const uInt vecinoSet = disjointSet.find(i,j), actualSet = disjointSet.find(col, row);
00447                                         const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j,0);
00448 
00449                                         if ( (vecinoPixel <= actualPixel) && (vecinoSet != actualSet) )
00450                                                 {
00451                                                 // We should join this pixel to the set of the neighbour
00452                                                 const uInt      newPointID = disjointSet.unify(col, row, i, j),
00453                                                                 actualNodeID = nodeID[actualSet],
00454                                                                 vecinoNodeID = nodeID[vecinoSet];
00455 
00456                                                 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00457                                                 Q_ASSERT( (actualSet == newPointID) || (vecinoSet == newPointID) );
00458 
00459                                                 // If new is not in a node already, we associate it with the point that is associated to a node.
00460                                                 if (actualNodeID == NULL_NODE)
00461                                                         nodeID[newPointID] = vecinoNodeID;
00462                                                 else if (vecinoNodeID == NULL_NODE)
00463                                                         nodeID[newPointID] = actualNodeID;
00464 
00465                                                 // Otherwise, both actual and neighbour are associated to a node already.
00466                                                 // We create a new node, and join both nodes of actual and neighbour pixels to
00467                                                 // that one.
00468                                                 else    {
00469                                                         Q_ASSERT(actualNodeID != NULL_NODE);
00470                                                         Q_ASSERT(vecinoNodeID != NULL_NODE);
00471 
00472                                                         // We check that no one of the nodes of actual and neighbour pixels
00473                                                         // is new. In that case it will be parent node.
00474                                                         if (!validNode(actualNodeID) && validNode(vecinoNodeID))
00475                                                                 // We just add the node...
00476                                                                 {
00477                                                                 addChild(actualNodeID, vecinoNodeID);
00478                                                                 nodeID[newPointID] = actualNodeID;
00479                                                                 }
00480                                                         else if (validNode(actualNodeID) && !validNode(vecinoNodeID))
00481                                                                 // We just add the other node...
00482                                                                 {
00483                                                                 addChild(vecinoNodeID, actualNodeID);
00484                                                                 nodeID[newPointID] = vecinoNodeID;
00485                                                                 }
00486                                                         else if (validNode(actualNodeID) && validNode(vecinoNodeID))
00487                                                                 // We have two old nodes, and creaate a parent to unify them.
00488                                                                 {
00489                                                                 const uInt newNodeID = newNode(col, row, threshold);;
00490                                                                 nodeID[disjointSet.index(col, row)] = newNodeID;
00491 
00492                                                                 addChild(newNodeID, actualNodeID);
00493                                                                 addChild(newNodeID, vecinoNodeID);
00494                                                                 nodeID[newPointID] = newNodeID;
00495                                                                 }
00496                                                         else // if ( !NODE(actualNodeID).inited and !NODE(vecinoNodeID).inited )
00497                                                                 // We have two parent nodes, we leave things as they are.
00498                                                                 // No, we should unify both, passing childs of one of them to the
00499                                                                 // other.
00500                                                                 {
00501                                                                 Q_ASSERT(validNode(actualNodeID) == false);
00502                                                                 Q_ASSERT(validNode(vecinoNodeID) == false);
00503                                                                 Q_ASSERT(numChilds(actualNodeID) > 0);
00504                                                                 Q_ASSERT(numChilds(vecinoNodeID) > 0);
00505 
00506                                                                 uInt child;
00507                                                                 for (   child = firstChild(actualNodeID);
00508                                                                         nextSibling(child) != NULL_NODE;
00509                                                                         child = nextSibling(child));
00510 
00511                                                                 uInt lastActualChildNodeID = firstChild(actualNodeID);
00512                                                                 while (nextSibling(lastActualChildNodeID) != NULL_NODE)
00513                                                                         lastActualChildNodeID =
00514                                                                                 nextSibling(lastActualChildNodeID);
00515 
00516                                                                 numChilds(actualNodeID) += numChilds(vecinoNodeID);
00517                                                                 nextSibling(lastActualChildNodeID) = firstChild(vecinoNodeID);
00518                                                                 nodeID[newPointID] = actualNodeID;
00519                                                                 }
00520                                                         }
00521                                                 Q_ASSERT(nodeID[disjointSet.find(disjointSet.index(col, row))] == nodeID[disjointSet.find(disjointSet.index(i, j))]);
00522                                                 }
00523                                         }
00524                         }
00525 
00526                 // In this loop we actualize areas for the gray-level of the threshold of the two old nodes, and create new nodes, 
00527                 // case we find a set of one or several pixels of gray-scale value equal to threshold value, which are not joined
00528                 // to any connected set represented already in a node of the component tree.
00529                 //
00530                 // In this point, we have processed all pixels with gray-scale value equal or lesser to threshold. All of them are
00531                 // grouped to a group of pixels with same gray-scale level, in which case we have the vertex of a node, or well
00532                 // or well joined to a previously created node.
00533                 //
00534                 // Then we creater for the former case new nodes, and in any case we actualize areas for nodes with new points
00535                 // in them.
00536                 for (int n=0; n< points[threshold].size(); n++)
00537                         {
00538                         Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00539                         const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00540                         const uInt actualID = disjointSet.index(col, row);
00541 
00542                         Q_ASSERT_X(actualID < cols * rows, "getComponentTree", "out of bounds 5");
00543 
00544                         // We have a pixel with gray-scale level equal to threshold, and disjoint set identificator equal to himself.
00545                         // This means either it is an isolated pixel, surrounded by pixels of gray-scale level higher than his, or
00546                         // that he is in a connected set of pixels, all of them with exactly gray-scale level value of threshold
00547                         // (and we hill be the only one of that set, with disjoint set identificator equal to himself).
00548                         // Either case we create a new node, with seed point equal to this node.
00549                         if (actualID == disjointSet.find(actualID))
00550                                 {
00551                                 if (nodeID[actualID] == NULL_NODE)
00552                                         // We have a header point for the new component tree node.
00553                                         // We initialize the values for his node.
00554                                         {
00555                                         nodeID[disjointSet.index(col, row)] = newNode(col, row, threshold);
00556                                         this->leafNodes++;
00557                                         }
00558                                 else    // Actual pixel is associated to a node, but this one was created for other pixel.
00559                                         // We count as a free pixel the one that created the node that contains actual pixel.
00560                                         this->freePoints++;
00561                                 }
00562                         else    // Actual pixel is not group heading
00563                                 {
00564                                 this->freePoints++;
00565                                 // Why this isn't generally true?
00566                                 //Q_ASSERT(this->nodeID[actualID] == NULL_NODE);
00567                                 }
00568 
00569                         const uInt actualNodeID = nodeID[disjointSet.find(actualID)];
00570                         if (actualNodeID != NULL_NODE)
00571                                 {
00572                                 Q_ASSERT(area(actualNodeID)[lastThreshold(actualNodeID)] <= disjointSet.getSetCardinality(actualID));
00573                                 lastThreshold(actualNodeID) = threshold;
00574                                 area(actualNodeID)[threshold] = disjointSet.getSetCardinality(actualID);
00575                                 validNode(actualNodeID) = true;
00576                                 }
00577                         // Actualize total number of points
00578                         this->totalPoints++;
00579                         }
00580                 }
00581 
00582         rootNode() = nodeID[disjointSet.find(0)];
00583 
00584         // COMPONENT TREE FINISHED. STARTING TESTS...
00585         #ifndef QT_NO_DEBUG     // TEST 
00586         Q_ASSERT(validNode(this->rootNodeID));
00587 
00588         // Checking that actually number of nodes, and number of nodes with ID != NULL_NODE equals the
00589         // value holded in this->numNodes.
00590         uInt sumNodes = 0, sumChildNodes = 0, sumLeafNodes = 0;
00591 
00592         // Checking some basic tree structure and values
00593         for (uInt node = 0; node < this->numNodes; node++)
00594                 if (validNode(node))
00595                         {
00596                         const uInt fThreshold = firstThreshold(node), lThreshold = lastThreshold(node);
00597 
00598                         if (numChilds(node) == 0)
00599                                 sumLeafNodes++;
00600 
00601                         sumNodes++;
00602                         // Checking areas correctness
00603                         Q_ASSERT(area(node)[fThreshold] <= area(node)[lThreshold] != 0);
00604                         Q_ASSERT(area(node)[fThreshold] != 0);
00605                         Q_ASSERT(area(node)[lThreshold] != 0);
00606 
00607                         // Check that seed pixel correspond with first threshold
00608                         Q_ASSERT(image(seedX(node), seedY(node)) == fThreshold);
00609 
00610                         // Check areas go from lesser size to bigger
00611                         uInt lastArea = area(node)[fThreshold];
00612                         for (uInt threshold = fThreshold+1; threshold <= lThreshold; threshold++)
00613                                 if (area(node)[threshold] != 0)
00614                                         {
00615                                         const uInt actualArea = area(node)[threshold];
00616                                         Q_ASSERT(actualArea >= lastArea);
00617                                         lastArea = actualArea;
00618                                         }
00619 
00620                         uInt maxAreasChilds = 0;
00621                         uInt childs = 0;
00622                         for (   uint child = firstChild(node);
00623                                 child != NULL_NODE;
00624                                 child = nextSibling(child), childs++)
00625                                 {
00626                                 Q_ASSERT(childs < numChilds(node));
00627                                 Q_ASSERT(child < this->numNodes);
00628                                 Q_ASSERT(child != rootNode());
00629                                 Q_ASSERT(validNode(child));
00630                                 maxAreasChilds += area(child)[lastThreshold(child)];
00631                                 }
00632 
00633                         Q_ASSERT(area(node)[firstThreshold(node)] > maxAreasChilds);
00634                         Q_ASSERT(childs == numChilds(node));
00635 
00636                         sumChildNodes += numChilds(node);
00637                 }
00638         qDebug() << "getComponentTree(): /////// estadisticos";
00639         qDebug() << "getComponentTree(): sumNodes = " << sumNodes << sumChildNodes;
00640         Q_ASSERT( sumNodes == (sumChildNodes+1) );
00641         Q_ASSERT( this->leafNodes == sumLeafNodes );
00642 
00643         qDebug() << "getComponentTree(): this->numNodes = " << this->numNodes;
00644         qDebug() << "getComponentTree(): this->freePoints = "<< this->freePoints;
00645         qDebug() << "getComponentTree(): this->totalPoints = "<< this->totalPoints;
00646         qDebug() << "getComponentTree(): this->leafNodes + this->freePoints = "
00647                         << this->leafNodes + this->freePoints;
00648 
00649         Q_ASSERT(disjointSet.numberOfSets() == 1);
00650         Q_ASSERT(disjointSet.getSetCardinality(rootNode()) == (image.getCols() * image.getRows()));
00651         Q_ASSERT(this->totalPoints == (image.getCols() * image.getRows()));
00652         Q_ASSERT(this->totalPoints == this->leafNodes + this->freePoints);
00653 
00654         #endif // END TEST 
00655 
00656         delete nodeID;
00657 
00658         qDebug() << "getComponentTree() <~ return";
00659         }
00660 
00661 
00662 }

Generated on Wed Jan 16 18:41:28 2008 for QVision by  doxygen 1.5.3