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
00027 #define MIN(X,Y) (((X)>(Y))?(Y):(X))
00028 #define MAX(X,Y) (((X)>(Y))?(X):(Y))
00029
00030 void pruneLowComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00031 {
00032 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00033 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00034 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00035
00036 bool prune = false;
00037 int lastValidThreshold = validThreshold;
00038
00039
00040
00041 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00042 if (componentTree.area(node)[threshold] > 0)
00043 {
00044 if (componentTree.area(node)[threshold] < minArea)
00045 prune = true;
00046 else
00047 lastValidThreshold = threshold;
00048 }
00049
00050
00051 if (prune)
00052 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), lastValidThreshold, 0, lastValidThreshold-1);
00053 else
00054 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00055 pruneLowComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00056 }
00057
00058 void pruneHighComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00059 {
00060 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00061 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00062 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00063
00064 bool prune = false;
00065 int lastValidThreshold = validThreshold;
00066
00067
00068
00069 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00070 if (componentTree.area(node)[threshold] > 0)
00071 {
00072 if (componentTree.area(node)[threshold] < minArea)
00073 prune = true;
00074 else
00075 lastValidThreshold = threshold;
00076 }
00077
00078
00079 if (prune)
00080 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00081 else
00082 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00083 pruneHighComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00084 }
00085
00086 void FilterComponentTreeSmallRegions(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea)
00087 {
00088 qDebug() << "pruneRegions()";
00089 if (componentTree.isInverseTree())
00090 {
00091 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00092 pruneHighComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00093 }
00094 else {
00095 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00096 pruneLowComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00097 }
00098
00099 qDebug() << "pruneRegions() <~ return";
00100 }
00101
00103
00104 QVComponentTree::QVComponentTree(const QVImage<uChar,1> &image, bool inverseTree, bool useAlternative): numNodes(0), freePoints(0), inverseTree(inverseTree)
00105 {
00106 const uInt cols = image.getCols(), rows = image.getRows();
00107
00108 this->numNodes = 0;
00109 this->leafNodes = 0;
00110 this->freePoints = 0;
00111 this->totalPoints = 0;
00112 this->maxNodes = cols * rows;
00113 this->nodes.resize(maxNodes/10);
00114
00115 if (inverseTree)
00116 {
00117 QVImage<uChar> notImage(cols, rows);
00118
00119 QVIMAGE_INIT_READ(uChar,image);
00120 QVIMAGE_INIT_WRITE(uChar,notImage);
00121 for (uInt col = 0; col < cols; col++)
00122 for (uInt row = 0; row < rows; row++)
00123 QVIMAGE_PIXEL(notImage, col, row,0) = 255 - QVIMAGE_PIXEL(image, col, row,0);
00124
00125 if (useAlternative)
00126 getComponentTree2(notImage);
00127 else
00128 getComponentTree(notImage);
00129 }
00130 else {
00131 if (useAlternative)
00132 getComponentTree2(image);
00133 else
00134 getComponentTree(image);
00135 }
00136 }
00137
00138 void QVComponentTree::testComponentTree(const QVImage<uChar,1> &image, QVDisjointSet &disjointSet)
00139 {
00140 Q_ASSERT(closedNode(this->rootNodeID));
00141
00142
00143
00144 uInt sumNodes = 0, sumChildNodes = 0, sumLeafNodes = 0;
00145
00146
00147 for (uInt node = 0; node < this->numNodes; node++)
00148 if (closedNode(node))
00149 {
00150 const uInt fThreshold = firstThreshold(node), lThreshold = lastThreshold(node);
00151
00152 if (numChilds(node) == 0)
00153 sumLeafNodes++;
00154
00155 sumNodes++;
00156
00157 Q_ASSERT(area(node)[fThreshold] <= area(node)[lThreshold] != 0);
00158 Q_ASSERT(area(node)[fThreshold] != 0);
00159 Q_ASSERT(area(node)[lThreshold] != 0);
00160
00161
00162 Q_ASSERT(image(seedX(node), seedY(node)) == fThreshold);
00163
00164
00165 uInt lastArea = area(node)[fThreshold];
00166 for (uInt threshold = fThreshold+1; threshold <= lThreshold; threshold++)
00167 if (area(node)[threshold] != 0)
00168 {
00169 const uInt actualArea = area(node)[threshold];
00170 Q_ASSERT(actualArea >= lastArea);
00171 lastArea = actualArea;
00172 }
00173
00174 uInt maxAreasChilds = 0;
00175 uInt childs = 0;
00176 for ( uint child = firstChild(node);
00177 child != NULL_NODE;
00178 child = nextSibling(child), childs++)
00179 {
00180 Q_ASSERT(childs < numChilds(node));
00181 Q_ASSERT(child < this->numNodes);
00182 Q_ASSERT(child != rootNode());
00183 Q_ASSERT(closedNode(child));
00184 maxAreasChilds += area(child)[lastThreshold(child)];
00185 }
00186
00187 Q_ASSERT(area(node)[firstThreshold(node)] > maxAreasChilds);
00188 Q_ASSERT(childs == numChilds(node));
00189
00190 sumChildNodes += numChilds(node);
00191 }
00192 qDebug() << "getComponentTree(): /////// estadisticos";
00193 qDebug() << "getComponentTree(): sumNodes = " << sumNodes << sumChildNodes;
00194 Q_ASSERT( sumNodes == (sumChildNodes+1) );
00195 Q_ASSERT( this->leafNodes == sumLeafNodes );
00196
00197 qDebug() << "getComponentTree(): this->numNodes = " << this->numNodes;
00198 qDebug() << "getComponentTree(): this->freePoints = "<< this->freePoints;
00199 qDebug() << "getComponentTree(): this->totalPoints = "<< this->totalPoints;
00200 qDebug() << "getComponentTree(): this->leafNodes + this->freePoints = "
00201 << this->leafNodes + this->freePoints;
00202
00203 Q_ASSERT(disjointSet.numberOfSets() == 1);
00204 Q_ASSERT(disjointSet.getSetCardinality(rootNode()) == (image.getCols() * image.getRows()));
00205 Q_ASSERT(this->totalPoints == (image.getCols() * image.getRows()));
00206 Q_ASSERT(this->totalPoints == this->leafNodes + this->freePoints);
00207 }
00208
00211
00212 void QVComponentTree::getComponentTree(const QVImage<uChar> &image)
00213 {
00214 qDebug() << "getComponentTree()";
00215 const uInt cols = image.getCols(), rows = image.getRows();
00216
00217 QVIMAGE_INIT_READ(uChar,image);
00218
00219 const QVector< QVector< QPoint > > points = CountingSort(image);
00220 QVDisjointSet disjointSet(cols, rows);
00221
00222 uInt *nodeID = new uInt[maxNodes];
00223 for(uInt i=0; i<maxNodes; i++)
00224 nodeID[i] = NULL_NODE;
00225
00226
00227
00228 for (int threshold = 0; threshold < points.size(); threshold++)
00229 {
00230
00231
00232
00233
00234 for (int n=0; n< points[threshold].size(); n++)
00235 {
00236 const uInt col = points[threshold][n].x(),
00237 row = points[threshold][n].y(),
00238 actualIndex = disjointSet.index(col, row);
00239 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00240 uInt actualSet = disjointSet.find(col, row);
00241
00242
00243
00244 for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00245 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00246 if ((col != i) || (row != j))
00247 {
00248 const uInt vecinoSet = disjointSet.find(i,j);
00249 const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j, 0);
00250
00251 if ( (vecinoPixel <= actualPixel) && (vecinoSet != actualSet) )
00252 {
00253
00254 const uInt actualNodeID = nodeID[actualSet], vecinoNodeID = nodeID[vecinoSet];
00255
00256 actualSet = disjointSet.unify(col, row, i, j);
00257
00258 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00259
00260
00261
00262 if (vecinoNodeID == NULL_NODE)
00263 nodeID[actualSet] = actualNodeID;
00264 else if (actualNodeID == NULL_NODE)
00265 nodeID[actualSet] = vecinoNodeID;
00266 else
00267
00268
00269 {
00270
00271
00272 if (!closedNode(actualNodeID) && closedNode(vecinoNodeID))
00273
00274 {
00275 addChild(actualNodeID, vecinoNodeID);
00276 nodeID[actualSet] = actualNodeID;
00277 }
00278 else if (closedNode(actualNodeID) && !closedNode(vecinoNodeID))
00279
00280 {
00281 addChild(vecinoNodeID, actualNodeID);
00282 nodeID[actualSet] = vecinoNodeID;
00283 }
00284 else if (closedNode(actualNodeID) && closedNode(vecinoNodeID))
00285
00286 {
00287 const uInt newNodeID = newNode(col, row, threshold);
00288 addChild(newNodeID, actualNodeID);
00289 addChild(newNodeID, vecinoNodeID);
00290
00291
00292 nodeID[actualSet] = newNodeID;
00293 }
00294 else
00295
00296
00297
00298 {
00299 Q_ASSERT(closedNode(actualNodeID) == false);
00300 Q_ASSERT(closedNode(vecinoNodeID) == false);
00301 Q_ASSERT(numChilds(actualNodeID) > 0);
00302 Q_ASSERT(numChilds(vecinoNodeID) > 0);
00303
00304 mergeNodes(actualNodeID, vecinoNodeID);
00305 nodeID[actualSet] = actualNodeID;
00306 }
00307 }
00308
00309
00310 if (nodeID[actualSet] != NULL_NODE)
00311 {
00312 Q_ASSERT(area(actualNodeID)[lastThreshold(actualNodeID)] <= disjointSet.getSetCardinality(actualIndex));
00313 lastThreshold(nodeID[actualSet]) = threshold;
00314 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00315 }
00316
00317 Q_ASSERT(nodeID[disjointSet.find(disjointSet.index(col, row))] == nodeID[disjointSet.find(disjointSet.index(i, j))]);
00318 }
00319 }
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 for (int n=0; n< points[threshold].size(); n++)
00333 {
00334 const uInt col = points[threshold][n].x(),
00335 row = points[threshold][n].y(),
00336 actualIndex = disjointSet.index(col, row),
00337 actualSet = disjointSet.find(actualIndex);
00338
00339 Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00340 Q_ASSERT_X(actualIndex < cols * rows, "getComponentTree", "out of bounds 5");
00341
00342
00343
00344
00345
00346
00347
00348 if (actualIndex == actualSet)
00349 {
00350 if (nodeID[actualIndex] == NULL_NODE)
00351
00352
00353 {
00354 nodeID[actualSet] = newNode(col, row, threshold);
00355 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00356
00357 this->leafNodes++;
00358 }
00359 else
00360
00361 this->freePoints++;
00362 }
00363 else
00364 this->freePoints++;
00365
00366 const uInt actualNodeID = nodeID[actualSet];
00367
00368 if (actualNodeID != NULL_NODE)
00369 {
00370
00371
00372
00373
00374
00375 closedNode(actualNodeID) = true;
00376 }
00377
00378
00379 this->totalPoints++;
00380 }
00381 }
00382
00383 rootNode() = nodeID[disjointSet.find(0)];
00384
00385
00386 #ifndef QT_NO_DEBUG
00387
00388 #endif
00389
00390 delete nodeID;
00391
00392 qDebug() << "getComponentTree() <~ return";
00393 }
00394
00400
00401
00402
00403 #define TEST_JOIN_PIXELS(col1, row1, col2,row2) \
00404 { \
00405 const uChar actualPixel = QVIMAGE_PIXEL(image, col1, row1,0); \
00406 const uChar neigbourPixel = QVIMAGE_PIXEL(image, col2, row2,0); \
00407 uInt actualSet = disjointSet.find(col1,row1), neighbourSet = disjointSet.find(col2,row2); \
00408 \
00409 if (neigbourPixel == actualPixel) \
00410 \
00411 { \
00412 uInt destinationSet = disjointSet.unify(actualSet, neighbourSet); \
00413 isLeafNode[destinationSet] = isLeafNode[actualSet] && isLeafNode[neighbourSet]; \
00414 } \
00415 else if (neigbourPixel < actualPixel) \
00416 \
00417 { \
00418 borderPixel[disjointSet.index(col1,row1)] = true; \
00419 isLeafNode[actualSet] = false; \
00420 } \
00421 else \
00422 \
00423 { \
00424 borderPixel[disjointSet.index(col2,row2)] = true; \
00425 isLeafNode[neighbourSet] = false; \
00426 } \
00427 }
00428
00429 void QVComponentTree::getComponentTree2(const QVImage<uChar> &image)
00430 {
00431 qDebug() << "getComponentTree()";
00432 const uInt cols = image.getCols(), rows = image.getRows();
00433
00434 this->maxNodes = cols * rows;
00435
00436 this->numNodes = 0;
00437 this->leafNodes = 0;
00438 this->freePoints = 0;
00439 this->totalPoints = 0;
00440
00441 QVIMAGE_INIT_READ(uChar,image);
00442
00443 QVDisjointSet disjointSet(cols, rows);
00444
00446
00447
00448 bool *isLeafNode = new bool[maxNodes],
00449 *borderPixel = new bool[maxNodes];
00450 uInt *nodeID = new uInt[maxNodes],
00451 *setID = new uInt[maxNodes];
00452
00453 for(uInt i=0; i<maxNodes; i++)
00454 {
00455 isLeafNode[i] = true;
00456 borderPixel[i] = false;
00457 nodeID[i] = NULL_NODE;
00458 setID[i] = 0;
00459 }
00460
00461
00462 for (int col =0; col < cols-1; col++)
00463 for (int row =0; row < rows-1; row++)
00464 {
00465 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00466 for (int i = col; i< col+2; i++)
00467 for (int j = row; j < row + 2; j++)
00468 if ((i != col) || (j != row))
00469 TEST_JOIN_PIXELS(col, row, i,j);
00470
00471
00472 if (row != 0)
00473 TEST_JOIN_PIXELS(col, row, col+1, row-1);
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00486
00487
00488
00489 for (uInt col =0 ; col < cols; col++)
00490 for (uInt row =0 ; row < rows; row++)
00491 {
00492 uInt actualIndex = disjointSet.index(col, row), actualSet = disjointSet.find(col, row);
00493
00494 setID[actualIndex] = actualSet;
00495
00496 if ((actualSet == actualIndex) && isLeafNode[actualIndex])
00497 this->leafNodes++;
00498
00499
00500
00501 }
00502
00503
00504
00505 this->nodes.resize(2*this->leafNodes);
00506 std::cout << "Sets: " << this->leafNodes << std::endl;
00507
00508
00509
00510 for (uInt col =0 ; col < cols; col++)
00511 for (uInt row =0 ; row < rows; row++)
00512 {
00513 uInt actualIndex = disjointSet.index(col, row);
00514 if ((setID[actualIndex] == actualIndex) && isLeafNode[actualIndex])
00515 nodeID[actualIndex] = newNode(col, row, QVIMAGE_PIXEL(image, col, row,0));
00516 }
00517
00518
00519
00520 QVDisjointSet superSet(this->leafNodes);
00521
00522
00523
00524
00525 const QVector< QVector< QPoint > > points = CountingSort(image);
00526 for (int threshold = 0; threshold < points.size(); threshold++)
00527 {
00528
00529
00530
00531
00532 for (int n=0; n< points[threshold].size(); n++)
00533 {
00534 const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00535
00536
00537 if (!borderPixel[disjointSet.index(col, row)])
00538 continue;
00539
00540 const uInt actualIndex = disjointSet.index(col,row);
00541 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00542
00543
00544 for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00545 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00546 if ((col != i) || (row != j))
00547 {
00548 const uInt vecinoIndex = disjointSet.index(i,j);
00549 const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j,0);
00550
00551 if (actualPixel > vecinoPixel)
00552 {
00553 const uInt vecinoSet = setID[vecinoIndex], actualSet = setID[actualIndex];
00554
00555
00556 Q_ASSERT(vecinoSet != actualSet);
00557
00558 const uInt vecinoNode = nodeID[vecinoSet], actualNode = nodeID[actualSet];
00559
00560
00561 Q_ASSERT(vecinoNode != NULL_NODE);
00562
00563
00564
00565
00566
00567 if (actualNode == NULL_NODE)
00568 nodeID[actualSet] = vecinoNode;
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 }
00579 }
00580 }
00581
00582
00583 for (int n=0; n< points[threshold].size(); n++)
00584 {
00585 const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00586
00587 if (!borderPixel[disjointSet.index(col, row)])
00588 continue;
00589
00590 const uInt actualIndex = disjointSet.index(col,row);
00591 const uInt actualSet = setID[actualIndex];
00592 const uInt actualNode = nodeID[actualSet];
00593
00594 closedNode(actualNode) = true;
00595 }
00596 }
00597
00598 rootNode() = nodeID[disjointSet.find(0)];
00599
00600
00601 #ifndef QT_NO_DEBUG
00602
00603 #endif
00604
00605 delete borderPixel;
00606 delete isLeafNode;
00607 delete nodeID;
00608 delete setID;
00609
00610 qDebug() << "getComponentTree() <~ return";
00611 }
00612
00613