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