00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvdefines.h>
00026
00027 #include <QVDisjointSet>
00028 #include <QVComponentTree>
00029
00030 QVComponentTree::QVComponentTree(const QVImage<uChar,1> &image, bool inverseTree, bool ): numNodes(0), freePoints(0), inverseTree(inverseTree)
00031 {
00032 const uInt cols = image.getCols(), rows = image.getRows();
00033
00034 this->numNodes = 0;
00035 this->leafNodes = 0;
00036 this->freePoints = 0;
00037 this->totalPoints = 0;
00038 this->maxNodes = cols * rows;
00039 this->nodes.resize(maxNodes/10);
00040
00041 if (inverseTree)
00042 {
00043 QVImage<uChar> notImage(cols, rows);
00044
00045 QVIMAGE_INIT_READ(uChar,image);
00046 QVIMAGE_INIT_WRITE(uChar,notImage);
00047 for (uInt col = 0; col < cols; col++)
00048 for (uInt row = 0; row < rows; row++)
00049 QVIMAGE_PIXEL(notImage, col, row,0) = 255 - QVIMAGE_PIXEL(image, col, row,0);
00050
00051 getComponentTree(notImage);
00052 }
00053 else
00054 getComponentTree(image);
00055 }
00056
00057 void QVComponentTree::getComponentTree(const QVImage<uChar> &image)
00058 {
00059 qDebug() << "getComponentTree()";
00060 const uInt cols = image.getCols(), rows = image.getRows();
00061
00062 QVIMAGE_INIT_READ(uChar,image);
00063
00064 const QVector< QVector< QPoint > > points = CountingSort(image);
00065 QVDisjointSet disjointSet(cols, rows);
00066
00067 uInt *nodeID = new uInt[maxNodes];
00068 for(uInt i=0; i<maxNodes; i++)
00069 nodeID[i] = NULL_NODE;
00070
00071
00072
00073 for (int threshold = 0; threshold < points.size(); threshold++)
00074 {
00075
00076
00077
00078
00079 for (int n=0; n< points[threshold].size(); n++)
00080 {
00081 const uInt col = points[threshold][n].x(),
00082 row = points[threshold][n].y();
00083 const uChar actualPixel = QVIMAGE_PIXEL(image, col, row,0);
00084 uInt actualSet = disjointSet.find(col, row);
00085
00086
00087
00088 for (uInt i = (uInt) MAX(0,(int)col-1); i< MIN(cols, col+2); i++)
00089 for (uInt j = (uInt) MAX(0,(int)row-1); j< MIN(rows, row+2); j++)
00090 if ((col != i) || (row != j))
00091 {
00092 const uChar vecinoPixel = QVIMAGE_PIXEL(image, i, j, 0);
00093 if (vecinoPixel <= actualPixel)
00094 {
00095 const uInt vecinoSet = disjointSet.find(i,j);
00096 if (vecinoSet != actualSet)
00097 {
00098
00099
00100 const uInt actualNodeID = nodeID[actualSet], vecinoNodeID = nodeID[vecinoSet];
00101
00102 actualSet = disjointSet.unify(col, row, i, j);
00103
00104 Q_ASSERT(disjointSet.find(disjointSet.index(col, row)) == disjointSet.find(disjointSet.index(i, j)));
00105
00106
00107
00108 if (vecinoNodeID == NULL_NODE)
00109 nodeID[actualSet] = actualNodeID;
00110 else if (actualNodeID == NULL_NODE)
00111 nodeID[actualSet] = vecinoNodeID;
00112 else
00113
00114
00115 {
00116
00117
00118 if (!closedNode(actualNodeID) && closedNode(vecinoNodeID))
00119
00120 {
00121 addChild(actualNodeID, vecinoNodeID);
00122 nodeID[actualSet] = actualNodeID;
00123 }
00124 else if (closedNode(actualNodeID) && !closedNode(vecinoNodeID))
00125
00126 {
00127 addChild(vecinoNodeID, actualNodeID);
00128 nodeID[actualSet] = vecinoNodeID;
00129 }
00130 else if (closedNode(actualNodeID) && closedNode(vecinoNodeID))
00131
00132 {
00133 const uInt newNodeID = newNode(col, row, threshold);
00134 addChild(newNodeID, actualNodeID);
00135 addChild(newNodeID, vecinoNodeID);
00136
00137
00138 nodeID[actualSet] = newNodeID;
00139 }
00140 else
00141
00142
00143
00144 {
00145 Q_ASSERT(closedNode(actualNodeID) == false);
00146 Q_ASSERT(closedNode(vecinoNodeID) == false);
00147 Q_ASSERT(numChilds(actualNodeID) > 0);
00148 Q_ASSERT(numChilds(vecinoNodeID) > 0);
00149
00150 mergeNodes(actualNodeID, vecinoNodeID);
00151 nodeID[actualSet] = actualNodeID;
00152 }
00153 }
00154
00155
00156 if (nodeID[actualSet] != NULL_NODE)
00157 {
00159
00160
00161 lastThreshold(nodeID[actualSet]) = threshold;
00162 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00163 }
00164
00165 Q_ASSERT(nodeID[disjointSet.find(disjointSet.index(col, row))] ==
00166 nodeID[disjointSet.find(disjointSet.index(i, j))]);
00167 }
00168 }
00169 }
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 for (int n=0; n< points[threshold].size(); n++)
00183 {
00184 const uInt col = points[threshold][n].x(),
00185 row = points[threshold][n].y(),
00186 actualIndex = disjointSet.index(col, row),
00187 actualSet = disjointSet.find(actualIndex);
00188
00189 Q_ASSERT_X(threshold < 256, "getComponentTree", "out of bounds 4");
00190 Q_ASSERT_X(actualIndex < cols * rows, "getComponentTree", "out of bounds 5");
00191
00192
00193
00194
00195
00196
00197
00198 if (actualIndex == actualSet)
00199 {
00200 if (nodeID[actualIndex] == NULL_NODE)
00201
00202
00203 {
00204 nodeID[actualSet] = newNode(col, row, threshold);
00205 area(nodeID[actualSet])[threshold] = disjointSet.getSetCardinality(actualSet);
00206
00207 this->leafNodes++;
00208 }
00209 else
00210
00211 this->freePoints++;
00212 }
00213 else
00214 this->freePoints++;
00215
00216 const uInt actualNodeID = nodeID[actualSet];
00217
00218 if (actualNodeID != NULL_NODE)
00219 {
00220
00221
00222
00223
00224
00225 closedNode(actualNodeID) = true;
00226 }
00227
00228
00229 this->totalPoints++;
00230 }
00231 }
00232
00233 rootNode() = nodeID[disjointSet.find(0)];
00234
00235
00236 #ifndef QT_NO_DEBUG
00237
00238 #endif
00239
00240 delete nodeID;
00241
00242 qDebug() << "getComponentTree() <~ return";
00243 }