00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00147
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
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
00192
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
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
00245
00246 QVIMAGE_INIT_READ(uChar,image);
00247 for (int threshold = 0; threshold < points.size(); threshold++)
00248 {
00249
00250
00251
00252
00253
00254
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
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
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
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
00284 if (actualNodeID == NULL_NODE)
00285 NODE_ID(newPointID) = vecinoNodeID;
00286 else if (vecinoNodeID == NULL_NODE)
00287 NODE_ID(newPointID) = actualNodeID;
00288
00289
00290
00291 else {
00292 Q_ASSERT(actualNodeID != NULL_NODE);
00293 Q_ASSERT(vecinoNodeID != NULL_NODE);
00294
00295
00296
00297
00298 if (!NODE(actualNodeID).inited && NODE(vecinoNodeID).inited)
00299
00300 {
00301 ADD_CHILD(actualNodeID, vecinoNodeID);
00302 NODE_ID(newPointID) = actualNodeID;
00303 }
00304 else if (NODE(actualNodeID).inited && !NODE(vecinoNodeID).inited)
00305
00306 {
00307 ADD_CHILD(vecinoNodeID, actualNodeID);
00308 NODE_ID(newPointID) = vecinoNodeID;
00309 }
00310 else if (NODE(actualNodeID).inited && NODE(vecinoNodeID).inited)
00311
00312
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
00322
00323
00324
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
00352
00353
00354
00355
00356
00357
00358
00359
00360
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
00371
00372
00373
00374
00375
00376
00377
00378 if (actualID == disjointSet.find(actualID))
00379 {
00380 if (NODE_ID(actualID) == NULL_NODE)
00381
00382
00383 {
00384 uInt newNode;
00385 NEW_NODE(newNode, col, row, threshold);
00386 this->valid[actualID] = true;
00387 this->leafNodes++;
00388
00389 }
00390 else
00391
00392 this->freePoints++;
00393 }
00394 else
00395 {
00396 this->freePoints++;
00397
00398
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
00412 this->totalPoints++;
00413 }
00414 }
00415
00416 this->rootNode = NODE_ID(disjointSet.find(0));
00417
00418
00419
00420
00421 Q_ASSERT(NODE(this->rootNode).inited);
00422
00423
00424 #ifndef QT_NO_DEBUG
00425
00426
00427
00428 uInt sumNodes = 0, sumChildNodes = 0, sumLeafNodes = 0;
00429
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
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
00446
00447 Q_ASSERT(image(NODE(node).seedX, NODE(node).seedY) == firstThreshold);
00448
00449
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
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
00495
00496 qDebug() << "getComponentTree() <~ return";
00497 }
00498 }