00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <float.h>
00028 #include <iostream>
00029
00030 #include <qvip.h>
00031 #include <qvmath.h>
00032 #include <qvdefines.h>
00033 #include <qvmatrixalgebra.h>
00034 #include <QVPolyline>
00035 #include <QVPolylineF>
00036 #include <QList>
00037
00038 #ifdef QVIPP
00039 #include <qvipp.h>
00040 #endif
00041
00042 #ifndef QVIPP
00043 QVector<int> HistogramRange(const QVImage<uChar, 1> &src)
00044 {
00045 QVector< int > result(256);
00046
00047 QVIMAGE_INIT_READ(uChar,src);
00048 for(uInt row = 0; row < src.getRows(); row++)
00049 for(uInt col = 0; col < src.getCols(); col++)
00050 result[QVIMAGE_PIXEL(src, col, row,0)]++;
00051
00052 return result;
00053 }
00054
00055 void YUV420ToRGB(const QVImage<uChar, 1> &srcY, const QVImage<uChar, 1> &srcU, const QVImage<uChar, 1> &srcV,
00056 QVImage<uChar, 3> &destRGB, const QPoint &destROIOffset = QPoint(0,0))
00057 {
00058 const double y, u, v;
00059 const double y2 = y, u2 = u-128, v2 = v - 128;
00060
00061 double r = +y2 + 1.370705*v2;
00062 g = +y2 - 0.337633*u2 - 0.698001*v2;
00063 b = +y2 + 1.732446*u2;
00064
00065
00066 if (r > 255) r = 255;
00067 if (g > 255) g = 255;
00068 if (b > 255) b = 255;
00069 if (r < 0) r = 0;
00070 if (g < 0) g = 0;
00071 if (b < 0) b = 0;
00072
00073
00074 pixel[0] = r * 220 / 256;
00075 pixel[1] = g * 220 / 256;
00076 pixel[2] = b * 220 / 256;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 }
00088
00089 void RGBToYUV420(const QVImage<uChar, 3> &src, QVImage<uChar, 1> &dst1, QVImage<uChar, 1> &dst2, QVImage<uChar, 1> &dst3,
00090 const QPoint &destROIOffset = QPoint(0,0))
00091 {
00092
00093
00094
00095
00096
00097 }
00098 #endif
00099
00100 QVector< QVector< QPoint > > CountingSort(const QVImage<uChar, 1> &image)
00101 {
00102 QVector< QVector <QPoint> > result(256);
00103 const QVector<int> histogram = HistogramRange(image);
00104
00105 for (int k=0; k<256; k++)
00106 result[k].reserve(histogram[k]);
00107
00108 QVIMAGE_INIT_READ(uChar,image);
00109 for(uInt row = 0; row < image.getRows(); row++)
00110 for(uInt col = 0; col < image.getCols(); col++)
00111 result[QVIMAGE_PIXEL(image, col, row,0)].append(QPoint(col, row));
00112
00113 return result;
00114 }
00115
00116 #ifdef QVIPP
00117 void FilterHarrisCornerResponseImage(const QVImage<uChar> &image, QVImage<sFloat> &result, int aperture, int avgwindow, const QPoint &)
00118 {
00119 QVImage<uChar> buffer;
00120 MinEigenValGetBufferSize(image, buffer);
00121
00122 MinEigenVal(image, result, ippKernelSobel, aperture, avgwindow, buffer);
00123 }
00124
00125 void FilterDoG(const QVImage<uChar> &image, QVImage<uChar> &result)
00126 {
00127 const uInt rows = image.getRows(), cols = image.getCols();
00128 QVImage<uChar> gauss3x3(cols, rows), gauss5x5(cols, rows);
00129
00130
00131 FilterGauss(image, gauss3x3, ippMskSize3x3, QPoint(1,1));
00132 FilterGauss(image, gauss5x5, ippMskSize5x5, QPoint(2,2));
00133
00134 gauss3x3.setROI(gauss5x5.getROI());
00135
00136 AbsDiff(gauss3x3, gauss5x5, result);
00137 }
00138
00139 void SobelCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result)
00140 {
00141 std::cerr << "WARNING: SobelCornerResponseImage is deprecated. Use FilterHessianCornerResponseImage instead." << std::endl;
00142 FilterHessianCornerResponseImage(image, result);
00143 }
00144
00145 void FilterHessianCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result, const QPoint &destROIOffset)
00146 {
00147 QVImage<sFloat> Gx, Gy, Gxx, Gxy, Gyy, GxyGxy, GxxGyy;
00148
00149 FilterSobelHorizMask(image,Gx, ippMskSize3x3);
00150 FilterSobelVertMask(image,Gy, ippMskSize3x3);
00151
00152 FilterSobelHorizMask(Gx,Gxx, ippMskSize3x3, QPoint(2,0));
00153 FilterSobelVertMask(Gy,Gyy, ippMskSize3x3, QPoint(0,2));
00154 FilterSobelVertMask(Gx,Gxy, ippMskSize3x3, QPoint(2,2));
00155
00156 Gxx.setROI(Gxy.getROI());
00157 Gyy.setROI(Gxy.getROI());
00158
00159 Mul(Gxy, Gxy, GxyGxy);
00160 Mul(Gxx, Gyy, GxxGyy);
00161 AbsDiff(GxyGxy, GxxGyy, result, destROIOffset);
00162 }
00163
00164
00165 void FilterSeparable(const QVImage<sFloat, 1> &image, QVImage<sFloat, 1> &dest,
00166 const QVVector &rowFilter, const QVVector &colFilter, const QPoint &destROIOffset)
00167 {
00168 const uInt cols = image.getCols(), rows = image.getRows();
00169 QVImage<sFloat> rowFiltered(cols, rows);
00170 FilterRow(image, rowFiltered, rowFilter);
00171 FilterColumn(rowFiltered, dest, colFilter, destROIOffset);
00172 }
00173
00174 QMap<sFloat, QPointF> fastMaximalPoints(const QVImage<sFloat> &image, const double threshold, const int windowRadius)
00175 {
00176 QVImage<sFloat> maxImage;
00177 FilterMax(image, maxImage, QSize(2*windowRadius+1, 2*windowRadius+1), QPoint(0,0), image.getROI().topLeft() + QPoint(windowRadius, windowRadius));
00178
00179 const QRect ROI = maxImage.getROI();
00180 const int maxStep = maxImage.getStep() / sizeof(sFloat),
00181 imageStep = image.getStep() / sizeof(sFloat);
00182
00183 QMap<sFloat, QPointF> sortedPoints;
00184
00185 sFloat *actualPtr = (sFloat *) image.getReadData() + (imageStep + 1) * windowRadius;
00186 sFloat *maxPtr = (sFloat *) maxImage.getReadData() + (maxStep + 1) * windowRadius;
00187
00188 for(int j = 0; j < ROI.height(); j++, actualPtr += imageStep, maxPtr += maxStep)
00189 for(int i = 0; i < ROI.width(); i++)
00190 if ( (actualPtr[i] >= threshold) and (maxPtr[i] == actualPtr[i]) )
00191 sortedPoints.insertMulti(-actualPtr[i], QPointF(i+ROI.x(), j+ROI.y()));
00192
00193 return sortedPoints;
00194 }
00195
00196 QMap<sFloat, QPointF> fastMaximalPoints(const QVImage<uChar> &image, const double threshold, const int windowRadius)
00197 {
00198 QVImage<uChar> maxImage;
00199 FilterMax(image, maxImage, QSize(2*windowRadius+1, 2*windowRadius+1), QPoint(0,0), image.getROI().topLeft() + QPoint(windowRadius, windowRadius));
00200
00201 const QRect ROI = maxImage.getROI();
00202 const int maxStep = maxImage.getStep() / sizeof(sFloat),
00203 imageStep = image.getStep() / sizeof(sFloat);
00204
00205 QMap<sFloat, QPointF> sortedPoints;
00206
00207 uChar *actualPtr = (uChar *) image.getReadData() + (imageStep + 1) * windowRadius;
00208 uChar *maxPtr = (uChar *) maxImage.getReadData() + (maxStep + 1) * windowRadius;
00209
00210 for(int j = 0; j < ROI.height(); j++, actualPtr += imageStep, maxPtr += maxStep)
00211 for(int i = 0; i < ROI.width(); i++)
00212 if ( (actualPtr[i] >= threshold) and (maxPtr[i] == actualPtr[i]) )
00213 sortedPoints.insertMulti(-actualPtr[i], QPointF(i+ROI.x(), j+ROI.y()));
00214
00215 return sortedPoints;
00216 }
00217
00218 #define DEFINE_QVDTA_FUNCTION_NORMALIZE(TYPE, C) \
00219 void FilterNormalize(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00220 { \
00221 TYPE maxVal, minVal; \
00222 \
00223 Max(image,maxVal); \
00224 Min(image,minVal); \
00225 \
00226 QVImage<TYPE,C> temp, result; \
00227 SubC(image, minVal, temp); \
00228 MulC(temp, 255/(maxVal-minVal), result, 1, destROIOffset); \
00229 equalized = result; \
00230 }
00231
00232 DEFINE_QVDTA_FUNCTION_NORMALIZE(uChar,1);
00233
00234 #define DEFINE_QVDTA_FUNCTION_NORMALIZE2(TYPE, C) \
00235 void FilterNormalize(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00236 { \
00237 uInt rows = image.getRows(), cols = image.getCols(); \
00238 TYPE maxVal, minVal; \
00239 \
00240 Max(image,maxVal); \
00241 Min(image,minVal); \
00242 \
00243 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00244 SubC(image, minVal, temp); \
00245 MulC(temp, 255/(maxVal-minVal), result, destROIOffset); \
00246 equalized = result; \
00247 }
00248 DEFINE_QVDTA_FUNCTION_NORMALIZE2(sFloat,1);
00249 #endif
00250
00251 void FilterLocalMax(const QVImage<sFloat> &src, QVImage<uChar> &dest, uInt colMaskSize, uInt rowMaskSize, sFloat threshold)
00252 {
00253 const int cols = src.getCols(), rows = src.getRows();
00254 Set(0, dest);
00255 sFloat actual;
00256 QVIMAGE_INIT_READ(sFloat,src);
00257 QVIMAGE_INIT_WRITE(uChar,dest);
00258 for(int row = ((int)rowMaskSize); row < rows-((int)rowMaskSize); row++)
00259 for(int col = ((int)colMaskSize); col < cols-((int)colMaskSize); col++)
00260 {
00261 actual = QVIMAGE_PIXEL(src, col, row,0);
00262 if (actual >= threshold)
00263 {
00264 QVIMAGE_PIXEL(dest, col, row, 0) = std::numeric_limits<unsigned char>::max();
00265 for (int j = ((int)row-rowMaskSize); (j < row+((int)rowMaskSize)) && (QVIMAGE_PIXEL(dest, col, row, 0) > 0); j++)
00266 for (int i = ((int)col-colMaskSize); i < col+((int)colMaskSize); i++)
00267 if ( ((i != col) || (j != row)) && (actual <= QVIMAGE_PIXEL(src, i, j, 0)) )
00268 {
00269 QVIMAGE_PIXEL(dest, col, row, 0) = 0;
00270 break;
00271 }
00272 }
00273 }
00274 }
00275
00277 int myFloodFill(QVImage<uChar> &image, uInt x, uInt y, uInt value, uInt minVal, uInt maxVal)
00278 {
00279
00280 Q_ASSERT( (value <= minVal) || (value >= maxVal) );
00281 Q_ASSERT( minVal <= maxVal );
00282
00283
00284 if ( (x >= image.getCols()) || (y >= image.getRows()))
00285 return 0;
00286
00287 if ( (image(x,y) < minVal) || (image(x,y) > maxVal) )
00288 return 0;
00289
00290 image(x,y) = value;
00291
00292 int val = 1;
00293 val += myFloodFill(image, x-1, y, value, minVal, maxVal);
00294 val += myFloodFill(image, x, y-1, value, minVal, maxVal);
00295 val += myFloodFill(image, x+1, y, value, minVal, maxVal);
00296 val += myFloodFill(image, x, y+1, value, minVal, maxVal);
00297
00298 val += myFloodFill(image, x-1, y-1, value, minVal, maxVal);
00299 val += myFloodFill(image, x-1, y+1, value, minVal, maxVal);
00300 val += myFloodFill(image, x+1, y-1, value, minVal, maxVal);
00301 val += myFloodFill(image, x+1, y+1, value, minVal, maxVal);
00302
00303 return val;
00304 }
00305
00307
00308 #include <QVComponentTree>
00309
00310 void pruneLowComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00311 {
00312 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00313 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00314 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00315
00316 bool prune = false;
00317 int lastValidThreshold = validThreshold;
00318
00319
00320
00321 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00322 if (componentTree.area(node)[threshold] > 0)
00323 {
00324 if (componentTree.area(node)[threshold] < minArea)
00325 prune = true;
00326 else
00327 lastValidThreshold = threshold;
00328 }
00329
00330
00331 if (prune)
00332 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), lastValidThreshold, 0, lastValidThreshold-1);
00333 else
00334 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00335 pruneLowComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00336 }
00337
00338 void pruneHighComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00339 {
00340 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00341 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00342 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00343
00344 bool prune = false;
00345 int lastValidThreshold = validThreshold;
00346
00347
00348
00349 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00350 if (componentTree.area(node)[threshold] > 0)
00351 {
00352 if (componentTree.area(node)[threshold] < minArea)
00353 prune = true;
00354 else
00355 lastValidThreshold = threshold;
00356 }
00357
00358
00359 if (prune)
00360 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00361 else
00362 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00363 pruneHighComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00364 }
00365
00366 void FilterPruneComponentTreeSmallRegions(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea)
00367 {
00368 qDebug() << "pruneRegions()";
00369 if (componentTree.isInverseTree())
00370 {
00371 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00372 pruneHighComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00373 }
00374 else {
00375 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00376 pruneLowComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00377 }
00378
00379 qDebug() << "pruneRegions() <~ return";
00380 }
00381
00382 #include <qvmath/qvdisjointset.h>
00383 #include <qvmath/qvvector.h>
00384
00385 QMap<sFloat, QPointF> maximalPoints(const QVImage<sFloat> &cornerResponseImage, const double threshold, const int windowRadius)
00386 {
00387 const QRect ROI = cornerResponseImage.getROI();
00388 const int step = cornerResponseImage.getStep() / sizeof(sFloat),
00389 windowSize = windowRadius * 2 +1;
00390
00391 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00392
00393 QMap<sFloat, QPointF> sortedPoints;
00394 for(int row = ROI.y() + windowRadius; row < ROI.y() + ROI.height() - windowRadius; row++)
00395 for(int col = ROI.x() + windowRadius; col < ROI.x() + ROI.width() - windowRadius; col++)
00396 {
00397 const sFloat actual = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00398 if (actual >= threshold)
00399 {
00400 bool cond = true;
00401
00402 sFloat const * pixel = & QVIMAGE_PIXEL(cornerResponseImage, col, row, 0) - windowRadius * (1 + step);
00403 for (int j = 0; j < windowSize && cond; j++, pixel += step - windowSize )
00404 for (int i = 0; i < windowSize && cond; i++, pixel++)
00405 if ( ( i != windowRadius || j != windowRadius ) && ( actual <= *pixel) )
00406 cond = false;
00407
00408 if (cond)
00409 sortedPoints.insertMulti(-actual, QPointF(col+2, row+2));
00410 }
00411 }
00412
00413 return sortedPoints;
00414 }
00415
00417
00418 #ifndef DOXYGEN_IGNORE_THIS
00419 class ClassAuxIPE
00420 {
00421 public:
00422 double cost;
00423 int index;
00424 ClassAuxIPE *prev,*next;
00425 };
00426
00427 class ClassAuxIPE_F
00428 {
00429 public:
00430 double cost;
00431 int index;
00432 ClassAuxIPE_F *prev,*next;
00433 };
00434
00435 bool costLessThan(ClassAuxIPE* &s1,ClassAuxIPE* &s2)
00436 {
00437 return s1->cost < s2->cost;
00438 }
00439
00440 bool costLessThanF(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00441 {
00442 return s1->cost < s2->cost;
00443 }
00444
00445 bool indexLessThan(ClassAuxIPE* &s1,ClassAuxIPE* &s2)
00446 {
00447 return s1->index < s2->index;
00448 }
00449
00450 bool indexLessThanF(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00451 {
00452 return s1->index < s2->index;
00453 }
00454
00455 inline double costElimination(const QVPolyline &polyline,int ia, int ib, int ic)
00456 {
00457 double xA,yA,xB,yB,xC,yC;
00458 xA = polyline[ia].x(); yA=polyline[ia].y();
00459 xB = polyline[ib].x(); yB=polyline[ib].y();
00460 xC = polyline[ic].x(); yC=polyline[ic].y();
00461 if((xA != xC) or (yA != yC))
00462 return ABS(xA*(yC-yB) + xB*(yA-yC) + xC*(yB-yA)) / sqrt((xA-xC)*(xA-xC)+(yA-yC)*(yA-yC));
00463 else
00464 return sqrt((xB-xC)*(xB-xC)+(yB-yC)*(yB-yC));
00465 }
00466
00467 inline double costEliminationF(const QVPolylineF &polyline,int ia, int ib, int ic)
00468 {
00469 double xA,yA,xB,yB,xC,yC;
00470 xA = polyline[ia].x(); yA=polyline[ia].y();
00471 xB = polyline[ib].x(); yB=polyline[ib].y();
00472 xC = polyline[ic].x(); yC=polyline[ic].y();
00473 if((xA != xC) or (yA != yC))
00474 return ABS(xA*(yC-yB) + xB*(yA-yC) + xC*(yB-yA)) / sqrt((xA-xC)*(xA-xC)+(yA-yC)*(yA-yC));
00475 else
00476 return sqrt((xB-xC)*(xB-xC)+(yB-yC)*(yB-yC));
00477 }
00478
00479 class auxLine {
00480 public:
00481 auxLine(double l1,double l2,double l3,bool ok) : l1(l1),l2(l2),l3(l3),ok(ok) {};
00482 double l1,l2,l3;
00483 bool ok;
00484 };
00485
00486 class auxLine_F {
00487 public:
00488 auxLine_F(double l1,double l2,double l3,bool ok) : l1(l1),l2(l2),l3(l3),ok(ok) {};
00489 double l1,l2,l3;
00490 bool ok;
00491 };
00492 #endif
00493
00494 double IterativePointElimination(const QVPolyline &polyline, QVPolyline &result,
00495 const double param, bool maxNumberOfPointsMethod,bool intersectLines,
00496 double *max_removed_cost)
00497 {
00498 const uInt tot_siz = polyline.size();
00499 QList<ClassAuxIPE*> list;
00500
00501
00502 result.clear();
00503
00504
00505 if(max_removed_cost != NULL) *max_removed_cost = 0.0;
00506
00507
00508
00509 if(polyline.size()<3)
00510 {
00511 result = polyline;
00512 return FLT_MAX;
00513 }
00514
00515
00516 for(uInt i=0;i<tot_siz;i++)
00517 list.push_back(new ClassAuxIPE);
00518
00519 for(uInt i=0;i<tot_siz;i++)
00520 {
00521 int ia = (i==0)?tot_siz-1:i-1, ib = i, ic = (i==tot_siz-1)?0:i+1;
00522 list[i]->cost = costElimination(polyline,ia,ib,ic);
00523 list[i]->index = ib;
00524 list[i]->prev = list[ia];
00525 list[i]->next = list[ic];
00526 }
00527 if(not polyline.closed)
00528 {
00529 list[0]->cost = FLT_MAX;
00530 list[tot_siz-1]->cost = FLT_MAX;
00531 }
00532 qSort(list.begin(),list.end(), costLessThan);
00533
00534
00535 while(TRUE)
00536 {
00537
00538 if( (list.size() == 3) or
00539 ((not maxNumberOfPointsMethod) and (list[0]->cost > param)) or
00540 ((maxNumberOfPointsMethod) and
00541 (list.size() <= static_cast<int>(param))) )
00542 break;
00543
00544
00545 ClassAuxIPE *elem = list.takeAt(0),
00546 *elemPrev = list.takeAt(list.indexOf(elem->prev)),
00547 *elemNext = list.takeAt(list.indexOf(elem->next));
00548 elemPrev->next = elem->next;
00549 elemNext->prev = elem->prev;
00550 if(elemPrev->cost != FLT_MAX)
00551 elemPrev->cost = costElimination(polyline,elemPrev->prev->index,
00552 elemPrev->index,
00553 elemPrev->next->index);
00554 if(elemNext->cost != FLT_MAX)
00555 elemNext->cost = costElimination(polyline,elemNext->prev->index,
00556 elemNext->index,
00557 elemNext->next->index);
00558
00559
00560 int here;
00561 for(int i=0;i<2;i++)
00562 {
00563 ClassAuxIPE* newelem = ((i==0)?elemNext:elemPrev);
00564 int first=0,last=list.size()-1;
00565 while (first <= last) {
00566 int mid = (first + last) / 2;
00567 if (newelem->cost > list[mid]->cost)
00568 first = mid + 1;
00569 else if (newelem->cost < list[mid]->cost)
00570 last = mid - 1;
00571 else
00572 {
00573 here = mid;
00574 break;
00575 }
00576 }
00577 if(first>last)
00578 here=first;
00579 list.insert(here,newelem);
00580
00581 }
00582
00583 if(max_removed_cost != NULL)
00584 if(elem->cost > *max_removed_cost)
00585 *max_removed_cost = elem->cost;
00586 delete elem;
00587 }
00588
00589
00590 double return_value = list.first()->cost;
00591
00592
00593 qSort(list.begin(),list.end(),indexLessThan);
00594
00595
00596 QList<ClassAuxIPE*>::iterator it = list.begin();
00597 if(intersectLines)
00598 {
00599
00600 double ratio_eig=1.0;
00601 QList<auxLine> lines;
00602 for(int i=0;i<list.size();i++)
00603 {
00604
00605 if((not polyline.closed) and (i==list.size()-1))
00606 break;
00607 int i1 = list[i]->index;
00608 int i2 = list[(i+1)%list.size()]->index;
00609 if(i2<i1) i2 += tot_siz;
00610 int dist = i2-i1+1;
00611 #define MIN_PIXELS_IPE_LINE 15
00612 if(dist >= MIN_PIXELS_IPE_LINE)
00613 {
00614 i1 = (i1+dist/5)%tot_siz;
00615 i2 = (i2-dist/5)%tot_siz;
00616 dist = dist-2*(dist/5);
00617 }
00618 else
00619 {
00620 dist = i2-i1+1;
00621 i1 = i1%tot_siz;
00622 i2 = i2%tot_siz;
00623 }
00624
00625 double x=0,y=0,xx=0,xy=0,yy=0;
00626 uInt j=i1;
00627 do
00628 {
00629 x += polyline[j].x();
00630 y += polyline[j].y();
00631 xx += polyline[j].x()*polyline[j].x();
00632 xy += polyline[j].x()*polyline[j].y();
00633 yy += polyline[j].y()*polyline[j].y();
00634 j = (j+1)%tot_siz;
00635 } while(j!=(i2+1)%tot_siz);
00636 double l1,l2,l3;
00637 x /= dist; y /= dist; xx /= dist; xy /= dist; yy /= dist;
00638
00639 ratio_eig = homogLineFromMoments(x,y,xx,xy,yy,l1,l2,l3);
00640 lines.push_back(auxLine(l1,l2,l3,ratio_eig < 0.1));
00641 }
00642
00643 for(int i=0;i<list.size();i++)
00644 {
00645 QPoint oldPoint = polyline[list[i]->index];
00646 if( (not polyline.closed) and ((i==0) or (i==list.size()-1)))
00647 {
00648
00649 result.append(oldPoint);
00650 continue;
00651 }
00652 int ant = (i-1+list.size())%list.size();
00653 int post = (i+1)%list.size();
00654 double newx = (lines[i].l2)*(lines[ant].l3) - (lines[i].l3)*(lines[ant].l2);
00655 double newy = -(lines[i].l1)*(lines[ant].l3) + (lines[i].l3)*(lines[ant].l1);
00656 double newz = (lines[i].l1)*(lines[ant].l2) - (lines[i].l2)*(lines[ant].l1);
00657 if ( (not lines[i].ok) or (not lines[ant].ok) or
00658 (fabs(newz) < EPSILON) )
00659 result.append(oldPoint);
00660 else
00661 {
00662 int nx = qRound(newx/newz);
00663 int ny = qRound(newy/newz);
00664
00665
00666
00667
00668 double dist =
00669 sqrt((nx-oldPoint.x())*(nx-oldPoint.x()) +
00670 (ny-oldPoint.y())*(ny-oldPoint.y()));
00671 QPoint prevPoint = polyline[list[ant]->index],
00672 nextPoint = polyline[list[post]->index];
00673 double minDist =
00674 qMin(
00675 sqrt((prevPoint.x()-oldPoint.x())*(prevPoint.x()-oldPoint.x()) +
00676 (prevPoint.y()-oldPoint.y())*(prevPoint.y()-oldPoint.y())),
00677 sqrt((nextPoint.x()-oldPoint.x())*(nextPoint.x()-oldPoint.x()) +
00678 (nextPoint.y()-oldPoint.y())*(nextPoint.y()-oldPoint.y()))
00679 );
00680 if(dist < 0.2*minDist)
00681 result.append(QPoint(nx,ny));
00682 else
00683 result.append(oldPoint);
00684 }
00685 }
00686 }
00687 else
00688 {
00689
00690 it = list.begin();
00691 while(it != list.end())
00692 {
00693 result.append(polyline.at((*it)->index));
00694 it++;
00695 }
00696 }
00697
00698
00699 while (!list.isEmpty())
00700 delete list.takeFirst();
00701
00702
00703 result.closed = polyline.closed;
00704 result.direction = polyline.direction;
00705
00706
00707 return return_value;
00708 }
00709
00710 double IterativePointElimination(const QVPolylineF &polyline, QVPolylineF &result,
00711 const double param, bool maxNumberOfPointsMethod,bool intersectLines,
00712 double *max_removed_cost)
00713 {
00714 const uInt tot_siz = polyline.size();
00715 QList<ClassAuxIPE_F*> list;
00716
00717
00718 result.clear();
00719
00720
00721 if(max_removed_cost != NULL) *max_removed_cost = 0.0;
00722
00723
00724
00725 if(polyline.size()<3)
00726 {
00727 result = polyline;
00728 return FLT_MAX;
00729 }
00730
00731
00732 for(uInt i=0;i<tot_siz;i++)
00733 list.push_back(new ClassAuxIPE_F);
00734
00735 for(uInt i=0;i<tot_siz;i++)
00736 {
00737 int ia = (i==0)?tot_siz-1:i-1, ib = i, ic = (i==tot_siz-1)?0:i+1;
00738 list[i]->cost = costEliminationF(polyline,ia,ib,ic);
00739 list[i]->index = ib;
00740 list[i]->prev = list[ia];
00741 list[i]->next = list[ic];
00742 }
00743 if(not polyline.closed)
00744 {
00745 list[0]->cost = FLT_MAX;
00746 list[tot_siz-1]->cost = FLT_MAX;
00747 }
00748 qSort(list.begin(),list.end(),costLessThanF);
00749
00750
00751 while(TRUE)
00752 {
00753
00754 if( (list.size() == 3) or
00755 ((not maxNumberOfPointsMethod) and (list[0]->cost > param)) or
00756 ((maxNumberOfPointsMethod) and
00757 (list.size() <= static_cast<int>(param))) )
00758 break;
00759
00760
00761 ClassAuxIPE_F *elem = list.takeAt(0),
00762 *elemPrev = list.takeAt(list.indexOf(elem->prev)),
00763 *elemNext = list.takeAt(list.indexOf(elem->next));
00764 elemPrev->next = elem->next;
00765 elemNext->prev = elem->prev;
00766 if(elemPrev->cost != FLT_MAX)
00767 elemPrev->cost = costEliminationF(polyline,elemPrev->prev->index,
00768 elemPrev->index,
00769 elemPrev->next->index);
00770 if(elemNext->cost != FLT_MAX)
00771 elemNext->cost = costEliminationF(polyline,elemNext->prev->index,
00772 elemNext->index,
00773 elemNext->next->index);
00774
00775
00776 int here;
00777 for(int i=0;i<2;i++)
00778 {
00779 ClassAuxIPE_F* newelem = ((i==0)?elemNext:elemPrev);
00780 int first=0,last=list.size()-1;
00781 while (first <= last) {
00782 int mid = (first + last) / 2;
00783 if (newelem->cost > list[mid]->cost)
00784 first = mid + 1;
00785 else if (newelem->cost < list[mid]->cost)
00786 last = mid - 1;
00787 else
00788 {
00789 here = mid;
00790 break;
00791 }
00792 }
00793 if(first>last)
00794 here=first;
00795 list.insert(here,newelem);
00796
00797 }
00798
00799 if(max_removed_cost != NULL)
00800 if(elem->cost > *max_removed_cost)
00801 *max_removed_cost = elem->cost;
00802 delete elem;
00803 }
00804
00805
00806 double return_value = list.first()->cost;
00807
00808
00809 qSort(list.begin(),list.end(),indexLessThanF);
00810
00811
00812 QList<ClassAuxIPE_F*>::iterator it = list.begin();
00813 if(intersectLines)
00814 {
00815
00816 double ratio_eig=1.0;
00817 QList<auxLine_F> lines;
00818 for(int i=0;i<list.size();i++)
00819 {
00820
00821 if((not polyline.closed) and (i==list.size()-1))
00822 break;
00823 int i1 = list[i]->index;
00824 int i2 = list[(i+1)%list.size()]->index;
00825 if(i2<i1) i2 += tot_siz;
00826 int dist = i2-i1+1;
00827 #define MIN_PIXELS_IPE_LINE 15
00828 if(dist >= MIN_PIXELS_IPE_LINE)
00829 {
00830 i1 = (i1+dist/5)%tot_siz;
00831 i2 = (i2-dist/5)%tot_siz;
00832 dist = dist-2*(dist/5);
00833 }
00834 else
00835 {
00836 dist = i2-i1+1;
00837 i1 = i1%tot_siz;
00838 i2 = i2%tot_siz;
00839 }
00840
00841 double x=0,y=0,xx=0,xy=0,yy=0;
00842 uInt j=i1;
00843 do
00844 {
00845 x += polyline[j].x();
00846 y += polyline[j].y();
00847 xx += polyline[j].x()*polyline[j].x();
00848 xy += polyline[j].x()*polyline[j].y();
00849 yy += polyline[j].y()*polyline[j].y();
00850 j = (j+1)%tot_siz;
00851 } while(j!=(i2+1)%tot_siz);
00852 double l1,l2,l3;
00853 x /= dist; y /= dist; xx /= dist; xy /= dist; yy /= dist;
00854
00855 ratio_eig = homogLineFromMoments(x,y,xx,xy,yy,l1,l2,l3);
00856 lines.push_back(auxLine_F(l1,l2,l3,ratio_eig < 0.1));
00857 }
00858
00859 for(int i=0;i<list.size();i++)
00860 {
00861 QPointF oldPoint = polyline[list[i]->index];
00862 if( (not polyline.closed) and ((i==0) or (i==list.size()-1)))
00863 {
00864
00865 result.append(oldPoint);
00866 continue;
00867 }
00868 int ant = (i-1+list.size())%list.size();
00869 int post = (i+1)%list.size();
00870 double newx = (lines[i].l2)*(lines[ant].l3) - (lines[i].l3)*(lines[ant].l2);
00871 double newy = -(lines[i].l1)*(lines[ant].l3) + (lines[i].l3)*(lines[ant].l1);
00872 double newz = (lines[i].l1)*(lines[ant].l2) - (lines[i].l2)*(lines[ant].l1);
00873 if ( (not lines[i].ok) or (not lines[ant].ok) or
00874 (fabs(newz) < EPSILON) )
00875 result.append(oldPoint);
00876 else
00877 {
00878 int nx = qRound(newx/newz);
00879 int ny = qRound(newy/newz);
00880
00881
00882
00883
00884 double dist =
00885 sqrt((nx-oldPoint.x())*(nx-oldPoint.x()) +
00886 (ny-oldPoint.y())*(ny-oldPoint.y()));
00887 QPointF prevPoint = polyline[list[ant]->index],
00888 nextPoint = polyline[list[post]->index];
00889 double minDist =
00890 qMin(
00891 sqrt((prevPoint.x()-oldPoint.x())*(prevPoint.x()-oldPoint.x()) +
00892 (prevPoint.y()-oldPoint.y())*(prevPoint.y()-oldPoint.y())),
00893 sqrt((nextPoint.x()-oldPoint.x())*(nextPoint.x()-oldPoint.x()) +
00894 (nextPoint.y()-oldPoint.y())*(nextPoint.y()-oldPoint.y()))
00895 );
00896 if(dist < 0.2*minDist)
00897 result.append(QPoint(nx,ny));
00898 else
00899 result.append(oldPoint);
00900 }
00901 }
00902 }
00903 else
00904 {
00905
00906 it = list.begin();
00907 while(it != list.end())
00908 {
00909 result.append(polyline.at((*it)->index));
00910 it++;
00911 }
00912 }
00913
00914
00915 while (!list.isEmpty())
00916 delete list.takeFirst();
00917
00918
00919 result.closed = polyline.closed;
00920 result.direction = polyline.direction;
00921
00922
00923 return return_value;
00924 }
00925
00927
00928
00929
00930
00931
00932
00933
00934 #ifndef DOXYGEN_IGNORE_THIS
00935 const char coorX8Connect[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
00936 const char coorY8Connect[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };
00937 const char coorX4Connect[4] = { 0, 1, 0, -1, };
00938 const char coorY4Connect[4] = { -1, 0, 1, 0, };
00939 const char coorX4Diag[8] = { 1, 1, -1, -1 };
00940 const char coorY4Diag[8] = { -1, 1, 1, -1 };
00941 #endif
00942
00943
00944 #ifndef DOXYGEN_IGNORE_THIS
00945 QVPolyline getConnectedSetBorderContourThresholdFromBorderPoint(const QVImage<uChar> &image, const int startPointX, const int startPointY, const uChar threshold)
00946 {
00947 QVPolyline lista;
00948
00949 lista.closed = true;
00950 lista.append(QPoint(startPointX, startPointY));
00951
00952 QVIMAGE_INIT_READ(uChar,image);
00953 QRect roi = image.getROI();
00954
00955 Q_ASSERT_X(roi.contains(startPointX, startPointY), "getContourThresholdFromBorderPoint", "start point out of image ROI");
00956 Q_ASSERT_X(QVIMAGE_PIXEL(image, startPointX, startPointY, 0) >= threshold, "getContourThresholdFromBorderPoint", "start point is not contained in a connected set");
00957
00958
00959
00960 uChar searchDir = 128, numOuterPixels = 0;
00961 for (int i = 0; i<8; i++)
00962 {
00963 int x = startPointX +coorX8Connect[i], y = startPointY +coorY8Connect[i];
00964 if (!roi.contains(x, y))
00965 {
00966 numOuterPixels++;
00967 searchDir = i;
00968 }
00969 else if (QVIMAGE_PIXEL(image, x, y,0) < threshold)
00970 {
00971 numOuterPixels++;
00972 searchDir = i;
00973 }
00974 }
00975
00976
00977 Q_ASSERT_X(searchDir < 8, "getContourThresholdFromBorderPoint", "start point is inside the set, not in the border");
00978
00979
00980 if (numOuterPixels == 8)
00981 return lista;
00982
00983
00984 int sumSearchDir = 0, actualPointX = startPointX, actualPointY = startPointY;
00985 while (true)
00986 {
00987
00988 uChar d;
00989 int nextPointX, nextPointY;
00990 for (d = 0; d < 8; d++)
00991 {
00992 searchDir = (searchDir+1)%8;
00993 nextPointX = actualPointX + coorX8Connect[searchDir];
00994 nextPointY = actualPointY + coorY8Connect[searchDir];
00995 if (roi.contains(nextPointX, nextPointY))
00996 if ( (QVIMAGE_PIXEL(image, nextPointX, nextPointY,0) >= threshold) )
00997 break;
00998 }
00999
01000 sumSearchDir += d - 3;
01001
01002 actualPointX = nextPointX;
01003 actualPointY = nextPointY;
01004
01005 if ( QVIMAGE_PIXEL(image, actualPointX, actualPointY,0) < threshold )
01006 break;
01007
01008 if ( startPointX == actualPointX && startPointY == actualPointY)
01009 break;
01010
01011 lista.append(QPoint(actualPointX, actualPointY));
01012 searchDir = searchDir + 4;
01013 }
01014
01015 lista.direction = (sumSearchDir >= 0);
01016 return lista;
01017 }
01018
01019 QVPolyline getConnectedSetBorderContourThresholdFromBorderPoint(const QVImage<uShort> &image, const int startPointX, const int startPointY, const uShort threshold)
01020 {
01021 QVPolyline lista;
01022
01023 lista.closed = true;
01024 lista.append(QPoint(startPointX, startPointY));
01025
01026 QVIMAGE_INIT_READ(uShort,image);
01027 QRect roi = image.getROI();
01028
01029 Q_ASSERT_X(roi.contains(startPointX, startPointY), "getContourThresholdFromBorderPoint", "start point out of image ROI");
01030 Q_ASSERT_X(QVIMAGE_PIXEL(image, startPointX, startPointY, 0) >= threshold, "getContourThresholdFromBorderPoint", "start point is not contained in a connected set");
01031
01032
01033
01034 uShort searchDir = 128, numOuterPixels = 0;
01035 for (int i = 0; i<8; i++)
01036 {
01037 int x = startPointX +coorX8Connect[i], y = startPointY +coorY8Connect[i];
01038 if (!roi.contains(x, y))
01039 {
01040 numOuterPixels++;
01041 searchDir = i;
01042 }
01043 else if (QVIMAGE_PIXEL(image, x, y,0) < threshold)
01044 {
01045 numOuterPixels++;
01046 searchDir = i;
01047 }
01048 }
01049
01050
01051 Q_ASSERT_X(searchDir < 8, "getContourThresholdFromBorderPoint", "start point is inside the set, not in the border");
01052
01053
01054 if (numOuterPixels == 8)
01055 return lista;
01056
01057
01058 int sumSearchDir = 0, actualPointX = startPointX, actualPointY = startPointY;
01059 while (true)
01060 {
01061
01062 uShort d;
01063 int nextPointX, nextPointY;
01064 for (d = 0; d < 8; d++)
01065 {
01066 searchDir = (searchDir+1)%8;
01067 nextPointX = actualPointX + coorX8Connect[searchDir];
01068 nextPointY = actualPointY + coorY8Connect[searchDir];
01069 if (roi.contains(nextPointX, nextPointY))
01070 if ( (QVIMAGE_PIXEL(image, nextPointX, nextPointY,0) >= threshold) )
01071 break;
01072 }
01073
01074 sumSearchDir += d - 3;
01075
01076 actualPointX = nextPointX;
01077 actualPointY = nextPointY;
01078
01079 if ( QVIMAGE_PIXEL(image, actualPointX, actualPointY,0) < threshold )
01080 break;
01081
01082 if ( startPointX == actualPointX && startPointY == actualPointY)
01083 break;
01084
01085 lista.append(QPoint(actualPointX, actualPointY));
01086 searchDir = searchDir + 4;
01087 }
01088
01089 lista.direction = (sumSearchDir >= 0);
01090 return lista;
01091 }
01092
01093
01094
01095
01096 #endif
01097
01098 QVPolyline getConnectedSetBorderContourThreshold(const QVImage<uChar> &image, const QPoint startPoint, const uChar threshold)
01099 {
01100 QVIMAGE_INIT_READ(uChar,image);
01101 const QRect roi = image.getROI();
01102
01103 int col = startPoint.x(), row = startPoint.y();
01104
01105 if (QVIMAGE_PIXEL(image, col, row,0) < threshold)
01106 return QVPolyline();
01107
01108 while (roi.contains(col+1, row))
01109 {
01110 if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
01111 break;
01112 col++;
01113 }
01114
01115 return getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01116 }
01117
01118 QVPolyline getConnectedSetBorderContourThreshold(const QVImage<uShort> &image, const QPoint startPoint, const uShort threshold)
01119 {
01120 QVIMAGE_INIT_READ(uShort,image);
01121 const QRect roi = image.getROI();
01122
01123 int col = startPoint.x(), row = startPoint.y();
01124
01125 if (QVIMAGE_PIXEL(image, col, row,0) < threshold)
01126 return QVPolyline();
01127
01128 while (roi.contains(col+1, row))
01129 {
01130 if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
01131 break;
01132 col++;
01133 }
01134
01135 return getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01136 }
01137
01138 QList<QVPolyline> getConnectedSetBorderContoursThreshold(const QVImage <uChar> &image, const uChar threshold)
01139 {
01140 qDebug() << "getPolylinesThreshold()";
01141 QVImage<uChar> mask(image.getCols()+1, image.getRows()+1);
01142 Set(0, mask);
01143
01144 QVIMAGE_INIT_READ(uChar,image);
01145 QVIMAGE_INIT_WRITE(uChar,mask);
01146
01147 const QRect roi = image.getROI();
01148
01149 QList<QVPolyline> polylineList;
01150
01151
01152 for (int row = roi.y(); row < roi.y() + roi.height(); row++)
01153 for (int col = roi.x(); col < roi.y() + roi.width(); col++)
01154 {
01155
01156 if (QVIMAGE_PIXEL(image, col, row,0) >= threshold)
01157 {
01158
01159 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
01160 {
01161 QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01162 polylineList.append(lista);
01163
01164 QListIterator<QPoint> iterator(lista);
01165 for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
01166 {
01167 actual = iterator.next();
01168 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
01169 QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
01170 }
01171 }
01172
01173
01174 while (roi.contains(col+1, row))
01175 {
01176 if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
01177 break;
01178 col++;
01179 }
01180
01181
01182 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
01183 {
01184 QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01185 polylineList.append(lista);
01186
01187 QListIterator<QPoint> iterator(lista);
01188 for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
01189 {
01190 actual = iterator.next();
01191 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
01192 QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
01193 }
01194 }
01195 }
01196
01197 }
01198 qDebug() << "getPolylinesThreshold():"<< polylineList.size() << "contours obtained";
01199 qDebug() << "getPolylinesThreshold() <~ return";
01200 return polylineList;
01201 }
01202
01203
01204 QList<QVPolyline> getConnectedSetBorderContoursThreshold(const QVImage <uShort> &image, const uShort threshold)
01205 {
01206 qDebug() << "getPolylinesThreshold()";
01207 QVImage<uShort> mask(image.getCols()+1, image.getRows()+1);
01208 Set(0, mask);
01209
01210 QVIMAGE_INIT_READ(uShort,image);
01211 QVIMAGE_INIT_WRITE(uShort,mask);
01212
01213 const QRect roi = image.getROI();
01214
01215 QList<QVPolyline> polylineList;
01216
01217
01218 for (int row = roi.y(); row < roi.y() + roi.height(); row++)
01219 for (int col = roi.x(); col < roi.y() + roi.width(); col++)
01220 {
01221
01222 if (QVIMAGE_PIXEL(image, col, row,0) >= threshold)
01223 {
01224
01225 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
01226 {
01227 QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01228 polylineList.append(lista);
01229
01230 QListIterator<QPoint> iterator(lista);
01231 for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
01232 {
01233 actual = iterator.next();
01234 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
01235 QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
01236 }
01237 }
01238
01239
01240 while (roi.contains(col+1, row))
01241 {
01242 if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
01243 break;
01244 col++;
01245 }
01246
01247
01248 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
01249 {
01250 QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
01251 polylineList.append(lista);
01252
01253 QListIterator<QPoint> iterator(lista);
01254 for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
01255 {
01256 actual = iterator.next();
01257 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
01258 QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
01259 }
01260 }
01261 }
01262
01263 }
01264 qDebug() << "getPolylinesThreshold():"<< polylineList.size() << "contours obtained";
01265 qDebug() << "getPolylinesThreshold() <~ return";
01266 return polylineList;
01267 }
01268
01269
01270
01272
01273 QVPolyline getLineContourThreshold4Connectivity(QVImage<uChar> &image, const QPoint point, QVPolyline &polyline, const uChar threshold, bool reverse)
01274 {
01275 const uInt cols = image.getCols(), rows = image.getRows();
01276 QVIMAGE_INIT_WRITE(uChar, image);
01277
01278 uInt lastDir = 666, coorX = point.x(), coorY = point.y();
01279
01280 qDebug() << "\tContour: new contour";
01281
01282 forever {
01283 qDebug() << "\tContour:\tAppending point (" << coorX << ", " << coorY << ")";
01284 if (reverse)
01285 polyline.prepend(QPoint(coorX, coorY));
01286 else
01287 polyline.append(QPoint(coorX, coorY));
01288
01289 QVIMAGE_PIXEL(image, coorX, coorY, 0) = 0;
01290
01291 uInt dir;
01292 int newCoorX, newCoorY;
01293 for (dir = 0; dir < 4; dir++)
01294 {
01295 newCoorX = coorX + coorX4Connect[dir];
01296 newCoorY = coorY + coorY4Connect[dir];
01297
01298
01299 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01300 continue;
01301
01302
01303 if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold) && (lastDir != dir) )
01304 break;
01305 }
01306
01307 if (dir == 4) break;
01308
01309 coorX = newCoorX;
01310 coorY = newCoorY;
01311 lastDir = (dir+2)%4;
01312 }
01313
01314 return polyline;
01315 }
01316
01317 QList<QVPolyline> getLineContoursThreshold4Connectivity(const QVImage<uChar> &image, const uChar threshold)
01318 {
01319 const uInt cols = image.getCols(), rows = image.getRows();
01320 QVImage<uChar> clone = image;
01321
01322 QList<QVPolyline> polylineList;
01323
01324
01325 for(uInt col = 0; col < cols; col++)
01326 for(uInt row = 0; row < rows; row++)
01327 {
01328 QVIMAGE_INIT_READ(uChar, clone);
01329
01330 if ( (QVIMAGE_PIXEL(clone, col, row, 0) < threshold) )
01331 continue;
01332
01333
01334 QVPolyline polyline;
01335
01336
01337 getLineContourThreshold4Connectivity(clone, QPoint(col, row), polyline, threshold, false);
01338
01339
01340 uInt dir;
01341 int newCoorX, newCoorY;
01342 for (dir = 0; dir < 4; dir++)
01343 {
01344 newCoorX = col + coorX4Connect[dir];
01345 newCoorY = row + coorY4Connect[dir];
01346
01347
01348 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01349 continue;
01350
01351
01352 if ( (clone(newCoorX, newCoorY) >= threshold) )
01353 break;
01354 }
01355
01356
01357 if (dir != 4)
01358 getLineContourThreshold4Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
01359
01360
01361 polylineList.append(polyline);
01362 }
01363
01364 return polylineList;
01365 }
01366
01368
01369 QVPolyline getLineContourThreshold8Connectivity(QVImage<uChar> &image, const QPoint point, QVPolyline &polyline, const uChar threshold, bool reverse)
01370 {
01371 const uInt cols = image.getCols(), rows = image.getRows();
01372 QVIMAGE_INIT_WRITE(uChar, image);
01373
01374 uInt lastDir = 666, coorX = point.x(), coorY = point.y();
01375
01376 qDebug() << "\tContour: new contour";
01377
01378 bool continueCond = true;
01379 while(continueCond)
01380 {
01381 qDebug() << "\tContour:\tAppending point (" << coorX << ", " << coorY << ")";
01382 if (reverse)
01383 polyline.prepend(QPoint(coorX, coorY));
01384 else
01385 polyline.append(QPoint(coorX, coorY));
01386
01387 QVIMAGE_PIXEL(image, coorX, coorY, 0) = 0;
01388
01389
01390 uInt dir;
01391 int newCoorX, newCoorY;
01392 for (dir = 0; dir < 4; dir++)
01393 {
01394 newCoorX = coorX + coorX4Connect[dir];
01395 newCoorY = coorY + coorY4Connect[dir];
01396
01397
01398 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01399 continue;
01400
01401
01402 if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold) && (lastDir != dir) )
01403 break;
01404 }
01405
01406 if (dir == 4)
01407 {
01408
01409 uInt dir;
01410 int newCoorX, newCoorY;
01411 for (dir = 0; dir < 4; dir++)
01412 {
01413 newCoorX = coorX + coorX4Diag[dir];
01414 newCoorY = coorY + coorY4Diag[dir];
01415
01416
01417 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01418 continue;
01419
01420
01421 if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold) && (lastDir != dir) )
01422 break;
01423 }
01424 if (dir == 4) break;
01425
01426 coorX = newCoorX;
01427 coorY = newCoorY;
01428 lastDir = (dir+2)%4;
01429 }
01430 else {
01431 coorX = newCoorX;
01432 coorY = newCoorY;
01433 lastDir = (dir+2)%4;
01434 }
01435 }
01436
01437 return polyline;
01438 }
01439
01440 QList<QVPolyline> getLineContoursThreshold8Connectivity(const QVImage<uChar> &image, const uChar threshold)
01441 {
01442 const uInt cols = image.getCols(), rows = image.getRows();
01443 QVImage<uChar> clone = image;
01444
01445 QList<QVPolyline> polylineList;
01446
01447
01448 for(uInt col = 0; col < cols; col++)
01449 for(uInt row = 0; row < rows; row++)
01450 {
01451 QVIMAGE_INIT_READ(uChar, clone);
01452
01453 if ( (QVIMAGE_PIXEL(clone, col, row, 0) < threshold) )
01454 continue;
01455
01456
01457 QVPolyline polyline;
01458
01459
01460 getLineContourThreshold8Connectivity(clone, QPoint(col, row), polyline, threshold, false);
01461
01462
01463 uInt dir;
01464 int newCoorX, newCoorY;
01465 for (dir = 0; dir < 4; dir++)
01466 {
01467 newCoorX = col + coorX4Connect[dir];
01468 newCoorY = row + coorY4Connect[dir];
01469
01470
01471 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01472 continue;
01473
01474
01475 if ( (clone(newCoorX, newCoorY) >= threshold) )
01476 break;
01477 }
01478
01479
01480 if (dir != 4)
01481 getLineContourThreshold8Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
01482 else {
01483
01484 uInt dir;
01485 int newCoorX, newCoorY;
01486 for (dir = 0; dir < 4; dir++)
01487 {
01488 newCoorX = col + coorX4Diag[dir];
01489 newCoorY = row + coorY4Diag[dir];
01490
01491
01492 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= ((int)cols)) || (newCoorY >= ((int)rows)) )
01493 continue;
01494
01495
01496 if ( (clone(newCoorX, newCoorY) >= threshold) )
01497 break;
01498 }
01499
01500
01501 if (dir != 4)
01502 getLineContourThreshold8Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
01503 }
01504
01505
01506 polylineList.append(polyline);
01507 }
01508
01509 return polylineList;
01510 }