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