00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvmath/qvdisjointset.h>
00026 #include <qvip/qvimagefeatures/qvcomponenttree.h>
00027 #include <qvcore/qvdefines.h>
00028
00029 QVComponentTree::QVComponentTree(const QVImage<uChar,1> &image, bool inverseTree, bool useAlternative): numNodes(0), freePoints(0), inverseTree(inverseTree)
00030 {
00031 const uInt cols = image.getCols(), rows = image.getRows();
00032
00033 this->numNodes = 0;
00034 this->leafNodes = 0;
00035 this->freePoints = 0;
00036 this->totalPoints = 0;
00037 this->maxNodes = cols * rows;
00038 this->nodes.resize(maxNodes/10);
00039
00040 if (inverseTree)
00041 {
00042 QVImage<uChar> notImage(cols, rows);
00043
00044 QVIMAGE_INIT_READ(uChar,image);
00045 QVIMAGE_INIT_WRITE(uChar,notImage);
00046 for (uInt col = 0; col < cols; col++)
00047 for (uInt row = 0; row < rows; row++)
00048 QVIMAGE_PIXEL(notImage, col, row,0) = 255 - QVIMAGE_PIXEL(image, col, row,0);
00049
00050 if (useAlternative)
00051 getComponentTree2(notImage);
00052 else
00053 getComponentTree(notImage);
00054 }
00055 else {
00056 if (useAlternative)
00057 getComponentTree2(image);
00058 else
00059 getComponentTree(image);
00060 }
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00136
00137 void QVComponentTree::getComponentTree(const QVImage<uChar> &image)
00138 {
00139 qDebug() << "getComponentTree()";
00140 const uInt cols = image.getCols(), rows = image.getRows();
00141
00142 QVIMAGE_INIT_READ(uChar,image);
00143
00144 const QVector< QVector< QPoint > > points = CountingSort(image);
00145 QVDisjointSet disjointSet(cols, rows);
00146
00147 uInt *nodeID = new uInt[maxNodes];
00148 for(uInt i=0; i<maxNodes; i++)
00149 nodeID[i] = NULL_NODE;
00150
00151
00152
00153 for (int threshold = 0; threshold < points.size(); threshold++)
00154 {
00155
00156
00157
00158
00159 for (int n=0; n< points[threshold].size(); n++)
00160 {
00161 const uInt col = points[threshold][n].x(),
00162 row = points[threshold][n].y(),
00163 actualIndex = disjointSet.index(col, row);
00164 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00165 uInt actualSet = disjointSet.find(col, row);
00166
00167
00168
00169 for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00170 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00171 if ((col != i) || (row != j))
00172 {
00173 const uInt vecinoSet = disjointSet.find(i,j);
00174 const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j, 0);
00175
00176 if ( (vecinoPixel <= actualPixel) && (vecinoSet != actualSet) )
00177 {
00178
00179
00180 const uInt actualNodeID = nodeID[actualSet], vecinoNodeID = nodeID[vecinoSet];
00181
00182 actualSet = disjointSet.unify(col, row, i, j);
00183
00184 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00185
00186
00187
00188 if (vecinoNodeID == NULL_NODE)
00189 nodeID[actualSet] = actualNodeID;
00190 else if (actualNodeID == NULL_NODE)
00191 nodeID[actualSet] = vecinoNodeID;
00192 else
00193
00194
00195 {
00196
00197
00198 if (!closedNode(actualNodeID) && closedNode(vecinoNodeID))
00199
00200 {
00201 addChild(actualNodeID, vecinoNodeID);
00202 nodeID[actualSet] = actualNodeID;
00203 }
00204 else if (closedNode(actualNodeID) && !closedNode(vecinoNodeID))
00205
00206 {
00207 addChild(vecinoNodeID, actualNodeID);
00208 nodeID[actualSet] = vecinoNodeID;
00209 }
00210 else if (closedNode(actualNodeID) && closedNode(vecinoNodeID))
00211
00212 {
00213 const uInt newNodeID = newNode(col, row, threshold);
00214 addChild(newNodeID, actualNodeID);
00215 addChild(newNodeID, vecinoNodeID);
00216
00217
00218 nodeID[actualSet] = newNodeID;
00219 }
00220 else
00221
00222
00223
00224 {
00225 Q_ASSERT(closedNode(actualNodeID) == false);
00226 Q_ASSERT(closedNode(vecinoNodeID) == false);
00227 Q_ASSERT(numChilds(actualNodeID) > 0);
00228 Q_ASSERT(numChilds(vecinoNodeID) > 0);
00229
00230 mergeNodes(actualNodeID, vecinoNodeID);
00231 nodeID[actualSet] = actualNodeID;
00232 }
00233 }
00234
00235
00236 if (nodeID[actualSet] != NULL_NODE)
00237 {
00239
00240 lastThreshold(nodeID[actualSet]) = threshold;
00241 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00242 }
00243
00244 Q_ASSERT(nodeID[disjointSet.find(disjointSet.index(col, row))] == nodeID[disjointSet.find(disjointSet.index(i, j))]);
00245 }
00246 }
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 for (int n=0; n< points[threshold].size(); n++)
00260 {
00261 const uInt col = points[threshold][n].x(),
00262 row = points[threshold][n].y(),
00263 actualIndex = disjointSet.index(col, row),
00264 actualSet = disjointSet.find(actualIndex);
00265
00266 Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00267 Q_ASSERT_X(actualIndex < cols * rows, "getComponentTree", "out of bounds 5");
00268
00269
00270
00271
00272
00273
00274
00275 if (actualIndex == actualSet)
00276 {
00277 if (nodeID[actualIndex] == NULL_NODE)
00278
00279
00280 {
00281 nodeID[actualSet] = newNode(col, row, threshold);
00282 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00283
00284 this->leafNodes++;
00285 }
00286 else
00287
00288 this->freePoints++;
00289 }
00290 else
00291 this->freePoints++;
00292
00293 const uInt actualNodeID = nodeID[actualSet];
00294
00295 if (actualNodeID != NULL_NODE)
00296 {
00297
00298
00299
00300
00301
00302 closedNode(actualNodeID) = true;
00303 }
00304
00305
00306 this->totalPoints++;
00307 }
00308 }
00309
00310 rootNode() = nodeID[disjointSet.find(0)];
00311
00312
00313 #ifndef QT_NO_DEBUG
00314
00315 #endif
00316
00317 delete nodeID;
00318
00319 qDebug() << "getComponentTree() <~ return";
00320 }
00321
00327
00328
00329
00330 #define TEST_JOIN_PIXELS(col1, row1, col2,row2) \
00331 { \
00332 const uChar actualPixel = QVIMAGE_PIXEL(image, col1, row1,0); \
00333 const uChar neigbourPixel = QVIMAGE_PIXEL(image, col2, row2,0); \
00334 uInt actualSet = disjointSet.find(col1,row1), neighbourSet = disjointSet.find(col2,row2); \
00335 \
00336 if (neigbourPixel == actualPixel) \
00337 \
00338 { \
00339 uInt destinationSet = disjointSet.unify(actualSet, neighbourSet); \
00340 isLeafNode[destinationSet] = isLeafNode[actualSet] && isLeafNode[neighbourSet]; \
00341 } \
00342 else if (neigbourPixel < actualPixel) \
00343 \
00344 { \
00345 borderPixel[disjointSet.index(col1,row1)] = true; \
00346 isLeafNode[actualSet] = false; \
00347 } \
00348 else \
00349 \
00350 { \
00351 borderPixel[disjointSet.index(col2,row2)] = true; \
00352 isLeafNode[neighbourSet] = false; \
00353 } \
00354 }
00355
00356 void QVComponentTree::getComponentTree2(const QVImage<uChar> &image)
00357 {
00358 qDebug() << "getComponentTree()";
00359 const uInt cols = image.getCols(), rows = image.getRows();
00360
00361 this->maxNodes = cols * rows;
00362
00363 this->numNodes = 0;
00364 this->leafNodes = 0;
00365 this->freePoints = 0;
00366 this->totalPoints = 0;
00367
00368 QVIMAGE_INIT_READ(uChar,image);
00369
00370 QVDisjointSet disjointSet(cols, rows);
00371
00373
00374
00375 bool *isLeafNode = new bool[maxNodes],
00376 *borderPixel = new bool[maxNodes];
00377 uInt *nodeID = new uInt[maxNodes],
00378 *setID = new uInt[maxNodes];
00379
00380 for(uInt i=0; i<maxNodes; i++)
00381 {
00382 isLeafNode[i] = true;
00383 borderPixel[i] = false;
00384 nodeID[i] = NULL_NODE;
00385 setID[i] = 0;
00386 }
00387
00388
00389 for (int col =0; col < cols-1; col++)
00390 for (int row =0; row < rows-1; row++)
00391 {
00392 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00393 for (int i = col; i< col+2; i++)
00394 for (int j = row; j < row + 2; j++)
00395 if ((i != col) || (j != row))
00396 TEST_JOIN_PIXELS(col, row, i,j);
00397
00398
00399 if (row != 0)
00400 TEST_JOIN_PIXELS(col, row, col+1, row-1);
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00413
00414
00415
00416 for (uInt col =0 ; col < cols; col++)
00417 for (uInt row =0 ; row < rows; row++)
00418 {
00419 uInt actualIndex = disjointSet.index(col, row), actualSet = disjointSet.find(col, row);
00420
00421 setID[actualIndex] = actualSet;
00422
00423 if ((actualSet == actualIndex) && isLeafNode[actualIndex])
00424 this->leafNodes++;
00425
00426
00427
00428 }
00429
00430
00431
00432 this->nodes.resize(2*this->leafNodes);
00433 std::cout << "Sets: " << this->leafNodes << std::endl;
00434
00435
00436
00437 for (uInt col =0 ; col < cols; col++)
00438 for (uInt row =0 ; row < rows; row++)
00439 {
00440 uInt actualIndex = disjointSet.index(col, row);
00441 if ((setID[actualIndex] == actualIndex) && isLeafNode[actualIndex])
00442 nodeID[actualIndex] = newNode(col, row, QVIMAGE_PIXEL(image, col, row,0));
00443 }
00444
00445
00446
00447 QVDisjointSet superSet(this->leafNodes);
00448
00449
00450
00451
00452 const QVector< QVector< QPoint > > points = CountingSort(image);
00453 for (int threshold = 0; threshold < points.size(); threshold++)
00454 {
00455
00456
00457
00458
00459 for (int n=0; n< points[threshold].size(); n++)
00460 {
00461 const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00462
00463
00464 if (!borderPixel[disjointSet.index(col, row)])
00465 continue;
00466
00467 const uInt actualIndex = disjointSet.index(col,row);
00468 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00469
00470
00471 for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00472 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00473 if ((col != i) || (row != j))
00474 {
00475 const uInt vecinoIndex = disjointSet.index(i,j);
00476 const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j,0);
00477
00478 if (actualPixel > vecinoPixel)
00479 {
00480 const uInt vecinoSet = setID[vecinoIndex], actualSet = setID[actualIndex];
00481
00482
00483 Q_ASSERT(vecinoSet != actualSet);
00484
00485 const uInt vecinoNode = nodeID[vecinoSet], actualNode = nodeID[actualSet];
00486
00487
00488 Q_ASSERT(vecinoNode != NULL_NODE);
00489
00490
00491
00492
00493
00494 if (actualNode == NULL_NODE)
00495 nodeID[actualSet] = vecinoNode;
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 }
00506 }
00507 }
00508
00509
00510 for (int n=0; n< points[threshold].size(); n++)
00511 {
00512 const uInt col = points[threshold][n].x(), row = points[threshold][n].y();
00513
00514 if (!borderPixel[disjointSet.index(col, row)])
00515 continue;
00516
00517 const uInt actualIndex = disjointSet.index(col,row);
00518 const uInt actualSet = setID[actualIndex];
00519 const uInt actualNode = nodeID[actualSet];
00520
00521 closedNode(actualNode) = true;
00522 }
00523 }
00524
00525 rootNode() = nodeID[disjointSet.find(0)];
00526
00527
00528 #ifndef QT_NO_DEBUG
00529
00530 #endif
00531
00532 delete borderPixel;
00533 delete isLeafNode;
00534 delete nodeID;
00535 delete setID;
00536
00537 qDebug() << "getComponentTree() <~ return";
00538 }
00539
00540