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