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 #define MIN(X,Y)        (((X)>(Y))?(Y):(X))
00027 #define MAX(X,Y)        (((X)>(Y))?(X):(Y))
00028 
00029 namespace qvdta
00030 {
00031 uInt debug_aux_print_componentTree(const QVComponentTree *componentTree, int node, int numTabs)
00032         {
00033         Q_ASSERT_X(numTabs < 8, "debug_aux_print_componentTree", "Can't show trees deeper than 8 level.");
00034         char tabs[16] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
00035         tabs[numTabs] = '\0';
00036 
00037         uInt    minThreshold = componentTree->nodes[node].firstThreshold,
00038                 maxThreshold = componentTree->nodes[node].lastThreshold;
00039 
00040         qDebug() << "debug_print_componentTree():" << tabs << "* Node" << node;
00041         qDebug() << "debug_print_componentTree():" << tabs << "  Seed at ("
00042                 << componentTree->nodes[node].seedX << componentTree->nodes[node].seedY << ")";
00043         qDebug() << "debug_print_componentTree():" << tabs << "  Areas min/max ["
00044                 << componentTree->nodes[node].area[minThreshold] << ","
00045                 << componentTree->nodes[node].area[maxThreshold] << "]";
00046         qDebug() << "debug_print_componentTree():" << tabs << "  Thresholds min/max ["
00047                 << minThreshold << "," << maxThreshold << "]"; 
00048         qDebug() << "debug_print_componentTree():" << tabs << "  # childs [" << componentTree->nodes[node].numChilds << "]"; 
00049 
00050         uInt sum = 1;
00051         for (   uInt child = componentTree->nodes[node].child, numChilds = 1;
00052                 child != NULL_NODE;
00053                 child = componentTree->nodes[child].brother, numChilds++ )
00054                 {
00055                 Q_ASSERT(child < componentTree->numNodes);
00056                 Q_ASSERT(numChilds <= componentTree->nodes[node].numChilds);
00057                 sum += debug_aux_print_componentTree(componentTree, child, numTabs+1);
00058                 }
00059 
00060         return sum;
00061         }
00062 
00063 uInt debug_print_componentTree(const QVComponentTree *componentTree)
00064         {
00065         qDebug() << "debug_print_componentTree()";
00066         qDebug() << "debug_print_componentTree(): numNodes =" << componentTree->numNodes;
00067         qDebug() << "debug_print_componentTree(): freePoints =" << componentTree->freePoints;
00068         qDebug() << "debug_print_componentTree(): totalPoints =" << componentTree->totalPoints;
00069         qDebug() << "debug_print_componentTree(): leafNodes =" << componentTree->leafNodes;
00070         qDebug() << "debug_print_componentTree(): rootNode =" << componentTree->rootNode;
00071 
00072         uInt numPrintedNodes = debug_aux_print_componentTree(componentTree, componentTree->rootNode, 1);
00073 
00074         qDebug() << "debug_print_componentTree(): numPrintedNodes =" << numPrintedNodes;
00075         qDebug() << "debug_print_componentTree() <~ return";
00076         return numPrintedNodes;
00077         }
00078 
00079 #define NODE_ID(PointID)        ( this->nodeID[PointID] )
00080 #define NODE(NodeID)            ( this->nodes[NodeID] )
00081 
00082 #define NEW_NODE(newNodeID, SeedX, SeedY, Threshold)            \
00083         {                                                       \
00084         newNodeID = this->numNodes++;                   \
00085         NODE_ID(disjointSet.index(SeedX, SeedY)) = newNodeID;   \
00086                                                                 \
00087         NODE(newNodeID).seedX = SeedX;                          \
00088         NODE(newNodeID).seedY = SeedY;                          \
00089         NODE(newNodeID).firstThreshold =                        \
00090         NODE(newNodeID).lastThreshold = Threshold;              \
00091         NODE(newNodeID).child =                                 \
00092         NODE(newNodeID).brother = NULL_NODE;                    \
00093         NODE(newNodeID).numChilds = 0;                          \
00094         NODE(newNodeID).area[Threshold] = 0;                    \
00095         NODE(newNodeID).inited = false;                         \
00096         }
00097 
00098 #define SWAP(Type, Value1, Value2)      \
00099         {                               \
00100         Type temp = Value1;             \
00101         Value1 = Value2;                \
00102         Value2 = temp;                  \
00103         }
00104 
00105 #define ADD_CHILD(ParentNodeID, ChildNodeID)                    \
00106         {                                                       \
00107         NODE(ChildNodeID).brother = NODE(ParentNodeID).child;   \
00108         NODE(ParentNodeID).child = ChildNodeID;                 \
00109         NODE(ParentNodeID).numChilds++;                         \
00110         }
00111 
00112 QVComponentTree::QVComponentTree(uInt cols, uInt rows, const QVImage<uChar,1> image): numNodes(0), freePoints(0)
00113         {
00114         maxNodes = cols*rows;
00115         nodes = new QVComponentTreeNode[maxNodes];
00116         nodeID = new uInt[maxNodes];
00117         valid = new bool[maxNodes];
00118         for(uInt i=0; i<maxNodes; i++)
00119                 {
00120                 nodeID[i] = NULL_NODE;
00121                 valid[i] = false;
00122                 }
00123 
00124         getComponentTree(image);
00125         }
00126 
00127 QVComponentTree::~QVComponentTree()
00128         {
00129         delete nodes;
00130         delete nodeID;
00131         delete valid;
00132         }
00133 
00134 void QVComponentTree::pruneLowComponentTreeAux(QVImage<uChar> &image, uInt minArea, uInt node, uInt validThreshold)
00135         {
00136         int     firstThreshold = NODE(node).firstThreshold,
00137                 lastThreshold = NODE(node).lastThreshold;
00138 
00139         Q_ASSERT(NODE(node).area[firstThreshold] != 0);
00140         Q_ASSERT(NODE(node).area[lastThreshold] != 0);
00141         Q_ASSERT(validThreshold >= lastThreshold);
00142 
00143         bool prune = false;
00144         int lastValidThreshold = validThreshold;
00145 
00146         // Aqui decidimos si podamos directamente el nodo
00147         // O bien si hay algún nivel al que deberíamos podar
00148         for (int threshold = lastThreshold; threshold >= firstThreshold && !prune; threshold--)
00149                 if (NODE(node).area[threshold] > 0)
00150                         {
00151                         if (NODE(node).area[threshold] < minArea)
00152                                 prune = true;
00153                         else
00154                                 lastValidThreshold = threshold;
00155                         }
00156 
00157         // Podamos, o seguimos con los hijos
00158         if (prune)
00159                 myFloodFill(image, NODE(node).seedX, NODE(node).seedY, lastValidThreshold, 0, lastValidThreshold-1);
00160         else
00161                 for (uInt child = NODE(node).child; child != NULL_NODE; child = NODE(child).brother)
00162                         pruneLowComponentTreeAux(image, minArea, child, lastValidThreshold);
00163         }
00164 
00165 void QVComponentTree::pruneLowRegions(QVImage<uChar> &image, uInt minArea)
00166         {
00167         qDebug() << "pruneComponentTree()";
00168 
00169         uInt lastThreshold = NODE(this->rootNode).lastThreshold;
00170 
00171         if(NODE(this->rootNode).area[lastThreshold] <= minArea)
00172                 return;
00173 
00174         pruneLowComponentTreeAux(image, minArea, this->rootNode, lastThreshold);
00175         qDebug() << "pruneComponentTree() <~ return";
00176         }
00177 
00179 void QVComponentTree::pruneHighComponentTreeAux(QVImage<uChar> &image, uInt minArea, uInt node, uInt validThreshold)
00180         {
00181         int     firstThreshold = NODE(node).firstThreshold,
00182                 lastThreshold = NODE(node).lastThreshold;
00183 
00184         Q_ASSERT(NODE(node).area[firstThreshold] != 0);
00185         Q_ASSERT(NODE(node).area[lastThreshold] != 0);
00186         Q_ASSERT(validThreshold >= lastThreshold);
00187 
00188         bool prune = false;
00189         int lastValidThreshold = validThreshold;
00190 
00191         // Aqui decidimos si podamos directamente el nodo
00192         // O bien si hay algún nivel al que deberíamos podar
00193         for (int threshold = lastThreshold; threshold >= firstThreshold && !prune; threshold--)
00194                 if (NODE(node).area[threshold] > 0)
00195                         {
00196                         if (NODE(node).area[threshold] < minArea)
00197                                 prune = true;
00198                         else
00199                                 lastValidThreshold = threshold;
00200                         }
00201 
00202         // Podamos, o seguimos con los hijos
00203         if (prune)
00204                 myFloodFill(image, NODE(node).seedX, NODE(node).seedY, 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00205         else
00206                 for (uInt child = NODE(node).child; child != NULL_NODE; child = NODE(child).brother)
00207                         pruneHighComponentTreeAux(image, minArea, child, lastValidThreshold);
00208         }
00209 
00210 void QVComponentTree::pruneHighRegions(QVImage<uChar> &image, uInt minArea)
00211         {
00212         qDebug() << "pruneComponentTree()";
00213 
00214         uInt lastThreshold = NODE(this->rootNode).lastThreshold;
00215 
00216         if(NODE(this->rootNode).area[lastThreshold] <= minArea)
00217                 return;
00218 
00219         pruneHighComponentTreeAux(image, minArea, this->rootNode, lastThreshold);
00220         qDebug() << "pruneComponentTree() <~ return";
00221         }
00222 
00228 void QVComponentTree::getComponentTree(const QVImage<uChar> &image)
00229         {
00230         qDebug() << "getComponentTree()";
00231         uInt cols = image.getCols(), rows = image.getRows();
00232 
00233         QVector< QVector< QPoint > > points = qvdta::CountingSort(image);
00234         qvdta::QVDisjointSet disjointSet(cols, rows);
00235 
00236         this->numNodes = 0;
00237         this->leafNodes = 0;
00238         this->freePoints = 0;
00239         this->totalPoints = 0;
00240 
00241         for (uInt i=0; i< cols*rows; i++)
00242                 Q_ASSERT(NODE_ID(i) == NULL_NODE);
00243 
00244         // Este bucle organiza la estructura del arbol de componentes, apoyandose en el disjoint set, y recorriendo los píxeles
00245         // en orden según su valor de gris gracias al conjunto de puntos 'points', obtenido mediante la función 'CountingSort'.
00246         QVIMAGE_INIT_READ(uChar,image);
00247         for (int threshold = 0; threshold < points.size(); threshold++)
00248                 {
00249                 // Actualizamos conjuntos sobre el disjoint set.
00250                 // Unimos en el disjoint set los pixels cuyo valor de gris es igual al threshold, con las regiones, o
00251                 // puntos colindantes, cuyo valor sea igual o menor que el threshold. Esto se hace a priori sólo sobre el disjoint
00252                 // set.
00253                 //
00254                 // También aqui se unen los nodos del arbol de componentes tales que tengan en común uno de los puntos procesados.
00255                 //
00256                 for (int n=0; n< points[threshold].size(); n++)
00257                         {
00258                         QPoint p = points[threshold][n];
00259                         uInt col = p.x(), row = p.y();
00260                         uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00261 
00262                         // recorremos la vecindad en busca de puntos cercanos para unir con el actual...
00263                         for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00264                                 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00265                                         if ((col != i) || (row != j))
00266                                         {
00267                                         //uInt  vecinoID = disjointSet.index(i, j);
00268                                         uInt    vecinoSet = disjointSet.find(i,j), actualSet = disjointSet.find(col, row);
00269                                         uChar   vecinoPixel = QVIMAGE_PIXEL(image, i, j,0);
00270 
00271                                         if ( (vecinoPixel <= actualPixel) && (vecinoSet != actualSet) )
00272                                                 {
00273                                                 // Tenemos un pixel al que debemos añadir al grupo del vecino
00274                                                 uInt    newPointID = disjointSet.unify(col, row, i, j);
00275                                                         
00276                                                 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00277 
00278                                                 Q_ASSERT( (actualSet == newPointID) || (vecinoSet == newPointID) );
00279 
00280                                                 uInt    actualNodeID = NODE_ID(actualSet),
00281                                                         vecinoNodeID = NODE_ID(vecinoSet);
00282 
00283                                                 // Si el nuevo es NULL_POINTER, le asignamos el punto q no es NULL_POINTER 
00284                                                 if (actualNodeID == NULL_NODE)
00285                                                         NODE_ID(newPointID) = vecinoNodeID;
00286                                                 else if (vecinoNodeID == NULL_NODE)
00287                                                         NODE_ID(newPointID) = actualNodeID;
00288                                                 // En caso contrario, tenemos que actual y vecino tienen nodos asociados.
00289                                                 // Procedemos a crear un nuevo nodo, y a añadir los otros dos nodos a dicho
00290                                                 // nuevo nodo.
00291                                                 else    {
00292                                                         Q_ASSERT(actualNodeID != NULL_NODE);
00293                                                         Q_ASSERT(vecinoNodeID != NULL_NODE);
00294 
00295                                                         // Hay que comprobar que entre los dos nodos, no haya uno recién creado
00296                                                         // (area[threshold] == 0)
00297                                                         // en cuyo caso, ese será el nodo padre, al que añadir el otro.
00298                                                         if (!NODE(actualNodeID).inited && NODE(vecinoNodeID).inited)
00299                                                                 // Directamente añadimos el otro nodo 
00300                                                                 {
00301                                                                 ADD_CHILD(actualNodeID, vecinoNodeID);
00302                                                                 NODE_ID(newPointID) = actualNodeID;
00303                                                                 }
00304                                                         else if (NODE(actualNodeID).inited && !NODE(vecinoNodeID).inited)
00305                                                                 // Directamente añadimos el otro nodo 
00306                                                                 {
00307                                                                 ADD_CHILD(vecinoNodeID, actualNodeID);
00308                                                                 NODE_ID(newPointID) = vecinoNodeID;
00309                                                                 }
00310                                                         else if (NODE(actualNodeID).inited && NODE(vecinoNodeID).inited)
00311                                                                 // Tenemos dos nodos antiguos, y creamos un nodo padre para
00312                                                                 // unificarlos
00313                                                                 {
00314                                                                 uInt newNodeID;
00315                                                                 NEW_NODE(newNodeID, col, row, threshold);
00316 
00317                                                                 ADD_CHILD(newNodeID, actualNodeID);
00318                                                                 ADD_CHILD(newNodeID, vecinoNodeID);
00319                                                                 NODE_ID(newPointID) = newNodeID;
00320                                                                 }
00321                                                         else // caso !NODE(actualNodeID).inited y !NODE(vecinoNodeID).inited
00322                                                                 // Tenemos dos nodos padre. Dejamos las cosas como están.
00323                                                                 // ¡No!, hay que unificar ambos, pasando los hijos de uno
00324                                                                 // al otro!
00325                                                                 {
00326                                                                 Q_ASSERT(NODE(actualNodeID).inited == false);
00327                                                                 Q_ASSERT(NODE(vecinoNodeID).inited == false);
00328                                                                 Q_ASSERT(NODE(actualNodeID).numChilds > 0);
00329                                                                 Q_ASSERT(NODE(vecinoNodeID).numChilds > 0);
00330 
00331                                                                 uInt child;
00332                                                                 for (   child = NODE(actualNodeID).child;
00333                                                                         NODE(child).brother != NULL_NODE;
00334                                                                         child = NODE(child).brother);
00335 
00336                                                                 uInt lastActualChildNodeID = NODE(actualNodeID).child;
00337                                                                 while (NODE(lastActualChildNodeID).brother != NULL_NODE)
00338                                                                         lastActualChildNodeID =
00339                                                                                 NODE(lastActualChildNodeID).brother;
00340 
00341                                                                 NODE(actualNodeID).numChilds += NODE(vecinoNodeID).numChilds;
00342                                                                 NODE(lastActualChildNodeID).brother = NODE(vecinoNodeID).child;
00343                                                                 NODE_ID(newPointID) = actualNodeID;
00344                                                                 }
00345                                                         }
00346                                                 Q_ASSERT(NODE_ID(disjointSet.find(disjointSet.index(col, row))) == NODE_ID(disjointSet.find(disjointSet.index(i, j))));
00347                                                 }
00348                                         }
00349                         }
00350 
00351                 // En este bucle actualizamos las areas para el corte de nivel threshold de los nodos antiguos, y creamos nodos
00352                 // nuevos, caso de encontrar un conjunto de uno o varios píxeles de valor de gris igual al valor threshold,
00353                 // que no estén unidos a ninguna región representada ya por un nodo en la estructura del arbol de componentes.
00354                 //
00355                 // En este punto, hemos procesado todos los píxeles de una misma intensidad de color, o menor.
00356                 // Todos los píxeles están agrupados, bien con píxeles de un color igual, en cuyo caso tenemos el vértice de
00357                 // una región, o bien anexos a una región cuyo vértice tiene una intensidad de color menor.
00358                 //
00359                 // Recorremos los puntos de intensidad igual, para bien actualizar áreas de las regiones a las que se han añadido,
00360                 // para el threshold dado, o bien crear un nuevo nodo en el arbol de componentes y agruparlas en él.
00361                 for (int n=0; n< points[threshold].size(); n++)
00362                         {
00363                         Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00364                         QPoint p = points[threshold][n];
00365                         int col = p.x(), row = p.y();
00366                         uInt    actualID = disjointSet.index(col, row);
00367 
00368                         Q_ASSERT_X(actualID < cols * rows, "getComponentTree", "out of bounds 5");
00369 
00370                         // Tenemos un pixel que si bien tiene un valor de gris igual al threshold, su identificador dentro del
00371                         // disjoint set es el mismo que el del grupo en el que está. Esto significa, o bien que es un píxel
00372                         // aislado, rodeado de píxeles con valores de gris mayor a él, o bien que está en un grupo conexo de
00373                         // píxeles con un valor de gris igual al suyo, rodeado a su vez por un conjunto de píxeles cuyo valor de
00374                         // gris es mayor al suyo, y que ha sido elegido por el disjoint set como 'cabecera de grupo'.
00375                         //
00376                         // Crearemos un nodo a partir de él, cuya semilla será sus coordenadas, y no tendrá hijos, a priori.
00377                         //
00378                         if (actualID == disjointSet.find(actualID))
00379                                 {
00380                                 if (NODE_ID(actualID) == NULL_NODE)
00381                                         // Tenemos un punto que será cabecera en un nuevo nodo del arbol de componentes.
00382                                         // Inicializamos los valores de su nodo.
00383                                         {
00384                                         uInt newNode;
00385                                         NEW_NODE(newNode, col, row, threshold);
00386                                         this->valid[actualID] = true;
00387                                         this->leafNodes++;
00388                                         //qDebug() << "getComponentTree(): new node" << newNode << "Seed (" << col << row << ")";
00389                                         }
00390                                 else    // El pixel actual está ya asociado a un nodo, pero este nodo se ha creado en otro píxel.
00391                                         // Contamos como píxel libre aquel en que se creó el nodo que contiene el pixel actual.
00392                                         this->freePoints++;
00393                                 }
00394                         else    // El pixel actual no es cabecera de su grupo.
00395                                 {
00396                                 this->freePoints++;
00397                                 // ¿Porque no?
00398                                 //Q_ASSERT(this->nodeID[actualID] == NULL_NODE);
00399                                 }
00400                         uInt actualNodeID = NODE_ID(disjointSet.find(actualID));
00401 
00402                         if (actualNodeID != NULL_NODE)
00403                                 {
00404                                 Q_ASSERT(NODE(actualNodeID).area[NODE(actualNodeID).lastThreshold]
00405                                                 <= disjointSet.getSetCardinality(actualID));
00406                                 NODE(actualNodeID).lastThreshold = threshold;
00407                                 NODE(actualNodeID).area[threshold] = disjointSet.getSetCardinality(actualID);
00408                                 NODE(actualNodeID).inited = true;
00409                                 }
00410 
00411                         // Actualizamos número total de puntos
00412                         this->totalPoints++;
00413                         }
00414                 }
00415 
00416         this->rootNode = NODE_ID(disjointSet.find(0));
00417 
00418         // COMPONENT TREE FINISHED. STARTING TESTS...
00419 
00420         // At this point we have component tree constructed.
00421         Q_ASSERT(NODE(this->rootNode).inited);
00422 
00423         // TEST /////////////////////////////////////////////
00424         #ifndef QT_NO_DEBUG
00425 
00426         // Checking that actually number of nodes, and number of nodes with ID != NULL_NODE equals the
00427         // value holded in this->numNodes.
00428         uInt sumNodes = 0, sumChildNodes = 0, sumLeafNodes = 0;
00429         // Checking some basic tree structure and values
00430         for (uInt node = 0; node < this->numNodes; node++)
00431                 if (NODE(node).inited)
00432                         {
00433                         uInt    firstThreshold = NODE(node).firstThreshold,
00434                                 lastThreshold = NODE(node).lastThreshold;
00435 
00436                         if (NODE(node).numChilds == 0)
00437                                 sumLeafNodes++;
00438 
00439                         sumNodes++;
00440                         // Comprobamos que las áreas son correctas
00441                         Q_ASSERT(NODE(node).area[firstThreshold] <= NODE(node).area[lastThreshold] != 0);
00442                         Q_ASSERT(NODE(node).area[firstThreshold] != 0);
00443                         Q_ASSERT(NODE(node).area[lastThreshold] != 0);
00444 
00445                         // Comprobamos que el píxel de la imagen situado en la semilla, se
00446                         // corresponde con el primer threshold
00447                         Q_ASSERT(image(NODE(node).seedX, NODE(node).seedY) == firstThreshold);
00448 
00449                         // Comprobamos que las áreas van de menor tamaño a mayor tamaño.
00450                         uInt lastArea = NODE(node).area[firstThreshold];
00451                         for (uInt threshold = firstThreshold+1; threshold <= lastThreshold; threshold++)
00452                                 if (NODE(node).area[threshold] != 0)
00453                                         {
00454                                         uInt actualArea = NODE(node).area[threshold];
00455                                         Q_ASSERT(actualArea >= lastArea);
00456                                         lastArea = actualArea;
00457                                         }
00458 
00459                         uInt maxAreasChilds = 0;
00460                         uInt numChilds = 0;
00461                         for (   uint child = NODE(node).child;
00462                                 child != NULL_NODE;
00463                                 child = NODE(child).brother, numChilds++)
00464                                 {
00465                                 Q_ASSERT(numChilds < NODE(node).numChilds);
00466                                 Q_ASSERT(child < this->numNodes);
00467                                 Q_ASSERT(child != this->rootNode);
00468                                 Q_ASSERT(NODE(child).inited);
00469                                 maxAreasChilds += NODE(child).area[NODE(child).lastThreshold];
00470                                 }
00471 
00472                         Q_ASSERT(NODE(node).area[NODE(node).firstThreshold] > maxAreasChilds);
00473                         Q_ASSERT(numChilds == NODE(node).numChilds);
00474                         // TODO: comprobar que la suma total de hijos más uno es exactamente el número de nodos.
00475                         sumChildNodes += NODE(node).numChilds;
00476                 }
00477         qDebug() << "getComponentTree(): /////// estadisticos";
00478         qDebug() << "getComponentTree(): sumNodes = " << sumNodes << sumChildNodes;
00479         Q_ASSERT( sumNodes == (sumChildNodes+1) );
00480         Q_ASSERT( this->leafNodes == sumLeafNodes );
00481 
00482         qDebug() << "getComponentTree(): this->numNodes = " << this->numNodes;
00483         qDebug() << "getComponentTree(): this->freePoints = "<< this->freePoints;
00484         qDebug() << "getComponentTree(): this->totalPoints = "<< this->totalPoints;
00485         qDebug() << "getComponentTree(): this->leafNodes + this->freePoints = "
00486                         << this->leafNodes + this->freePoints;
00487 
00488         Q_ASSERT(disjointSet.numberOfSets() == 1);
00489         Q_ASSERT(disjointSet.getSetCardinality(this->rootNode) == (image.getCols() * image.getRows()));
00490         Q_ASSERT(this->totalPoints == (image.getCols() * image.getRows()));
00491         Q_ASSERT(this->totalPoints == this->leafNodes + this->freePoints);
00492 
00493         #endif
00494         // TEST /////////////////////////////////////////////
00495 
00496         qDebug() << "getComponentTree() <~ return";
00497         }
00498 }

Generated on Fri Dec 7 12:20:59 2007 for QVision by  doxygen 1.5.3