src/qvip/qvpolyline.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <iostream>
00026 #include <float.h>
00027 
00028 #include <qvdefines.h>
00029 #include <qvmatrixalgebra.h>
00030 
00031 #include <QVPolyline>
00032 #include <QVPolylineF>
00033 
00035 // QVPolylines
00036 
00037 // Iterative point elimination:
00038 #ifndef DOXYGEN_IGNORE_THIS
00039 class ClassAuxIPE
00040         {
00041         public:
00042                 double cost;
00043                 int index;
00044                 ClassAuxIPE *prev,*next;
00045         };
00046 
00047 bool costLessThan(ClassAuxIPE* &s1,ClassAuxIPE* &s2)
00048         {
00049         return s1->cost < s2->cost;
00050         }
00051 
00052 bool indexLessThan(ClassAuxIPE* &s1,ClassAuxIPE* &s2)
00053         {
00054         return s1->index < s2->index;
00055         }
00056 
00057 inline double costElimination(const QVPolyline &polyline,int ia, int ib, int ic)
00058         {
00059         double   xA,yA,xB,yB,xC,yC;
00060         xA = polyline[ia].x(); yA=polyline[ia].y();
00061         xB = polyline[ib].x(); yB=polyline[ib].y();
00062         xC = polyline[ic].x(); yC=polyline[ic].y();
00063         if((xA != xC) or (yA != yC))
00064                 return ABS(xA*(yC-yB) + xB*(yA-yC) + xC*(yB-yA)) / sqrt((xA-xC)*(xA-xC)+(yA-yC)*(yA-yC));
00065         else
00066                 return sqrt((xB-xC)*(xB-xC)+(yB-yC)*(yB-yC));
00067         }
00068 
00069 class auxLine {
00070         public:
00071         auxLine(double l1,double l2,double l3,bool ok) : l1(l1),l2(l2),l3(l3),ok(ok) {};
00072         double l1,l2,l3;
00073         bool ok;
00074 };
00075 #endif
00076 
00077 double IterativePointElimination(const QVPolyline &polyline, QVPolyline &result,
00078         const double param, bool maxNumberOfPointsMethod,bool intersectLines,
00079         double *max_removed_cost)
00080         {
00081         const uInt tot_siz = polyline.size();
00082         QList<ClassAuxIPE*> list;
00083 
00084         // We start with an empty list:
00085         result.clear();
00086 
00087         // Maximum removed cost initialized to zero:
00088         if(max_removed_cost != NULL) *max_removed_cost = 0.0;
00089 
00090         // Only for polylines with 3 points or more; otherwise, the same
00091         // input polyline is returned:
00092         if(polyline.size()<3)
00093                 {
00094                 result = polyline;
00095                 return FLT_MAX;
00096                 }
00097 
00098         // Initialization of main data structure:
00099         for(uInt i=0;i<tot_siz;i++)
00100                 list.push_back(new ClassAuxIPE);
00101 
00102         for(uInt i=0;i<tot_siz;i++)
00103                 {
00104                 int ia = (i==0)?tot_siz-1:i-1, ib = i, ic = (i==tot_siz-1)?0:i+1;
00105                 list[i]->cost = costElimination(polyline,ia,ib,ic);
00106                 list[i]->index = ib;
00107                 list[i]->prev = list[ia];
00108                 list[i]->next = list[ic];
00109                 }
00110         if(not polyline.closed) // If not closed, never eliminate end points:
00111                 {
00112                 list[0]->cost = FLT_MAX;
00113                 list[tot_siz-1]->cost = FLT_MAX;
00114                 }
00115         qSort(list.begin(),list.end(),costLessThan);
00116 
00117         // Main loop:
00118         while(TRUE)
00119                 {
00120                 // Stop condition:
00121                 if( (list.size() == 3) or // Minimal size of a polyline.
00122                     ((not maxNumberOfPointsMethod) and (list[0]->cost > param)) or
00123                     ((maxNumberOfPointsMethod) and
00124                      (list.size() <= static_cast<int>(param))) )
00125                         break;
00126 
00127                 // Removal of best point (first in the list): 
00128                 ClassAuxIPE *elem = list.takeAt(0),
00129                             *elemPrev = list.takeAt(list.indexOf(elem->prev)),
00130                             *elemNext = list.takeAt(list.indexOf(elem->next));
00131                 elemPrev->next = elem->next;
00132                 elemNext->prev = elem->prev;
00133                 if(elemPrev->cost != FLT_MAX)
00134                         elemPrev->cost = costElimination(polyline,elemPrev->prev->index,
00135                                                                 elemPrev->index,
00136                                                                 elemPrev->next->index);
00137                 if(elemNext->cost != FLT_MAX)
00138                 elemNext->cost = costElimination(polyline,elemNext->prev->index,
00139                                                         elemNext->index,
00140                                                         elemNext->next->index);
00141 
00142                 // Binary (fast) insertion of neighbours in data structure:
00143                 int here;
00144                 for(int i=0;i<2;i++)
00145                         {
00146                         ClassAuxIPE* newelem = ((i==0)?elemNext:elemPrev);
00147                         int first=0,last=list.size()-1;
00148                         while (first <= last) {
00149                                 int mid = (first + last) / 2;
00150                                 if (newelem->cost > list[mid]->cost)
00151                                         first = mid + 1;
00152                                 else if (newelem->cost < list[mid]->cost)
00153                                         last = mid - 1;
00154                                 else
00155                                         {
00156                                         here = mid;
00157                                         break;
00158                                         }
00159                         }
00160                         if(first>last)
00161                                 here=first;
00162                         list.insert(here,newelem);
00163 
00164                         }
00165 
00166                 if(max_removed_cost != NULL)
00167                         if(elem->cost > *max_removed_cost)
00168                                 *max_removed_cost = elem->cost;
00169                 delete elem;
00170                 }
00171 
00172         // We will return the cost of the first non deleted point:
00173         double return_value = list.first()->cost;
00174 
00175         // Once IPE finished, sort the list by position in original polyline:
00176         qSort(list.begin(),list.end(),indexLessThan);
00177 
00178         // Now, postprocess, fitting lines:
00179         QList<ClassAuxIPE*>::iterator it = list.begin();
00180         if(intersectLines)
00181                 {
00182                 // Line intersection computation (could be subpixel, in fact...):
00183                 double ratio_eig=1.0;
00184                 QList<auxLine> lines;
00185                 for(int i=0;i<list.size();i++)
00186                         {
00187                         // If not closed, do not need to compute last line:
00188                         if((not polyline.closed) and (i==list.size()-1))
00189                                 break;
00190                         int i1 = list[i]->index;
00191                         int i2 = list[(i+1)%list.size()]->index;
00192                         if(i2<i1) i2 += tot_siz;
00193                         int dist = i2-i1+1;
00194                         #define MIN_PIXELS_IPE_LINE 15
00195                         if(dist >= MIN_PIXELS_IPE_LINE)
00196                                 {
00197                                 i1 = (i1+dist/5)%tot_siz;
00198                                 i2 = (i2-dist/5)%tot_siz;
00199                                 dist = dist-2*(dist/5);
00200                                 }
00201                         else 
00202                                 {
00203                                 dist = i2-i1+1;
00204                                 i1 = i1%tot_siz;
00205                                 i2 = i2%tot_siz;
00206                                 }
00207         
00208                         double x=0,y=0,xx=0,xy=0,yy=0;
00209                         uInt j=i1;
00210                         do
00211                                 {
00212                                 x += polyline[j].x();
00213                                 y += polyline[j].y();
00214                                 xx += polyline[j].x()*polyline[j].x();
00215                                 xy += polyline[j].x()*polyline[j].y();
00216                                 yy += polyline[j].y()*polyline[j].y();
00217                                 j = (j+1)%tot_siz;
00218                                 } while(j!=(i2+1)%tot_siz);
00219                         double l1,l2,l3;
00220                         x /= dist; y /= dist; xx /= dist; xy /= dist; yy /= dist;
00221                         // If line does not fit well, just put old point instead of intersection:
00222                         ratio_eig = homogLineFromMoments(x,y,xx,xy,yy,l1,l2,l3);
00223                         lines.push_back(auxLine(l1,l2,l3,ratio_eig < 0.1));
00224                         }
00225 
00226                 for(int i=0;i<list.size();i++)
00227                         {
00228                         QPoint oldPoint = polyline[list[i]->index];
00229                         if( (not polyline.closed) and ((i==0) or (i==list.size()-1)))
00230                                 {
00231                                 // If not closed, just include end points:
00232                                 result.append(oldPoint);
00233                                 continue;
00234                                 }
00235                         int ant = (i-1+list.size())%list.size();
00236                         int post = (i+1)%list.size();
00237                         double  newx = (lines[i].l2)*(lines[ant].l3) - (lines[i].l3)*(lines[ant].l2);
00238                         double  newy = -(lines[i].l1)*(lines[ant].l3) + (lines[i].l3)*(lines[ant].l1);
00239                         double  newz = (lines[i].l1)*(lines[ant].l2) - (lines[i].l2)*(lines[ant].l1);
00240                         if ( (not lines[i].ok) or (not lines[ant].ok) or // Bad segment
00241                                 (fabs(newz) < EPSILON) ) // Lines too parallel
00242                                 result.append(oldPoint);
00243                         else
00244                                 {
00245                                 int nx = qRound(newx/newz);
00246                                 int ny = qRound(newy/newz);
00247                                 // Only consider intersection if it is inside
00248                                 // a maximum radius circle around the old point
00249                                 // (relative to its nearer previous/next point
00250                                 // in polyline):
00251                                 double dist =
00252                                         sqrt((nx-oldPoint.x())*(nx-oldPoint.x()) +
00253                                              (ny-oldPoint.y())*(ny-oldPoint.y()));
00254                                 QPoint prevPoint = polyline[list[ant]->index],
00255                                         nextPoint = polyline[list[post]->index];
00256                                 double minDist =
00257                                         qMin(
00258                                         sqrt((prevPoint.x()-oldPoint.x())*(prevPoint.x()-oldPoint.x()) +
00259                                         (prevPoint.y()-oldPoint.y())*(prevPoint.y()-oldPoint.y())),
00260                                         sqrt((nextPoint.x()-oldPoint.x())*(nextPoint.x()-oldPoint.x()) +
00261                                         (nextPoint.y()-oldPoint.y())*(nextPoint.y()-oldPoint.y()))
00262                                         );
00263                                 if(dist < 0.2*minDist)
00264                                         result.append(QPoint(nx,ny));
00265                                 else
00266                                         result.append(oldPoint);
00267                                 }
00268                         }
00269                 }
00270         else 
00271                 {
00272                 // No postprocess, simply store the resulting points in result polyline.
00273                 it = list.begin();
00274                 while(it != list.end())
00275                         {
00276                                 result.append(polyline.at((*it)->index));
00277                                 it++;
00278                         }
00279                 }
00280 
00281         // Free memory of remaining structure:
00282         while (!list.isEmpty())
00283                 delete list.takeFirst();
00284 
00285         // Polyline type and direction are the same of the original polyline:
00286         result.closed = polyline.closed;
00287         result.direction = polyline.direction;
00288 
00289         // We return the cost of the first non deleted point:
00290         return return_value;
00291         }
00292 
00293 
00294 // Draw
00295 QVPolyline::QVPolyline(): QList<QPoint>(),
00296         closed(false), direction(false)//, dir(0)
00297         {
00298         qDebug() << "QVPolyline()";
00299         qDebug() << "QVPolyline() <~ return";
00300         };
00301 
00302 QVPolyline::QVPolyline(const QVPolyline &polyline): QList<QPoint>(polyline),
00303         closed(polyline.closed), direction(polyline.direction)//, dir(polyline.dir)
00304         {
00305         qDebug() << "QVPolyline(const QVPolyline &)";
00306         qDebug() << "QVPolyline(const QVPolyline &) <~ return";
00307         };
00308 
00309 QVPolyline::QVPolyline(const QVPolylineF &polyline): QList<QPoint>(),
00310         closed(polyline.closed), direction(polyline.direction)//, dir(polyline.dir)
00311         {
00312         foreach(QPointF pointf, polyline)
00313                 {
00314                 append( QPoint(pointf.toPoint()) );
00315                 }
00316         qDebug() << "QVPolylineF(const QVPolylineF &)";
00317         qDebug() << "QVPolylineF(const QVPolylineF &) <~ return";
00318         };
00319 
00320 // QPoint       linesIntersection(QPoint a, QPoint b, QPoint c, QPoint d)
00321 //      // gets the intersection point for lines ab and cd
00322 //      {
00323 //      double x1 = a.rx(), x2 = b.rx(), x3 = c.rx(), x4 = d.rx();
00324 //      double y1 = a.ry(), y2 = b.ry(), y3 = c.ry(), y4 = d.ry();
00325 // 
00326 //      double denominador = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
00327 //      if (denominador == 0)
00328 //              return QPoint( (int)(b.rx() + c.rx())/2, (int)(b.ry() + c.ry())/2 );
00329 // 
00330 //      double  ua = (x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3),
00331 //              ub = (x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3);
00332 // 
00333 //      QPoint p = QPoint(
00334 //                      (int) (x1 + ua*(x2 - x1) / denominador),
00335 //                      (int) (y1 + ub*(y2 - y1) / denominador)
00336 //                      );
00337 //      return p;
00338 //      }
00339 
00340 
00341 
00343 
00344 QVPolyline QVPolyline::ellipse(uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00345         {
00346         QVPolyline ellipse;
00347         float w = 2*PI/(n-1);
00348         float maxArg = (maxRadio+minRadio)/2;
00349         float minArg = (maxRadio-minRadio)/2;
00350 
00351         for (uInt t = 0; t < n; t++)
00352                 ellipse.append(QPoint ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00353                                                 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00354                                                 ));
00355         return ellipse;
00356         }
00357 
00358 QVPolyline QVPolyline::rectangle(int x1, int y1, int x2, int y2)
00359         {
00360         QVPolyline rectangle;
00361         rectangle.append(QPoint( x1, y1 ));
00362         rectangle.append(QPoint( x1, y2 ));
00363         rectangle.append(QPoint( x2, y2 ));
00364         rectangle.append(QPoint( x2, y1 ));
00365         rectangle.append(QPoint( x1, y1 ));
00366         return rectangle;
00367         }
00368 
00369 QVPolyline QVPolyline::line(int x1, int y1, int x2, int y2)
00370         {
00371         QVPolyline line;
00372 
00373         line.append(QPoint( x1, y1 ));
00374 
00375         if (x1 == x2 && y1 == y2)
00376                 return line;
00377 
00378         int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
00379         
00380         dx=x2-x1;      // the horizontal distance of the line
00381         dy=y2-y1;      // the vertical distance of the line
00382         dxabs=abs(dx);
00383         dyabs=abs(dy);
00384         sdx=SIGN(dx);
00385         sdy=SIGN(dy);
00386         x=dyabs>>1;
00387         y=dxabs>>1;
00388         px=x1;
00389         py=y1;
00390         
00391         if (dxabs>=dyabs) // the line is more horizontal than vertical
00392                 for(i=0;i<dxabs;i++)
00393                         {
00394                         y+=dyabs;
00395                         if (y>=dxabs)
00396                                 {
00397                                 y-=dxabs;
00398                                 py+=sdy;
00399                                 }
00400                         px+=sdx;
00401                         line.append(QPoint( px, py ));
00402                         }
00403         else    // the line is more vertical than horizontal
00404                 for(i=0;i<dyabs;i++)
00405                         {
00406                         x+=dxabs;
00407                         if (x>=dyabs)
00408                                 {
00409                                 x-=dyabs;
00410                                 px+=sdx;
00411                                 }
00412                         py+=sdy;
00413                         line.append(QPoint( px, py ));
00414                         }
00415 
00416         return line;
00417         }
00418 
00419 QVPolyline::operator QVPolylineF() const
00420         {
00421         QVPolylineF polyline;
00422         foreach(QPoint point, *this)
00423                 {
00424                 polyline.append(QPointF(point));
00425                 }
00426         return polyline;
00427         }
00428 
00429 
00431 // Direction-number             Y
00432 //      NE-7    N-0     NW-1    |
00433 //      E-6     *       W-2     v
00434 //      SE-5    S-4     SW-3
00435 // X -->
00436 //                                              N       NO      O       SO      S       SE      E       NE
00437 #ifndef DOXYGEN_IGNORE_THIS
00438 const char      coorX8Connect[8] =      {       0,      1,      1,      1,      0,      -1,     -1,     -1      };
00439 const char      coorY8Connect[8] =      {       -1,     -1,     0,      1,      1,      1,      0,      -1      };
00440 const char      coorX4Connect[4] =      {       0,              1,              0,              -1,             };
00441 const char      coorY4Connect[4] =      {       -1,             0,              1,              0,              };
00442 const char      coorX4Diag[8] =         {               1,              1,              -1,             -1      };
00443 const char      coorY4Diag[8] =         {               -1,             1,              1,              -1      };
00444 #endif
00445 
00446 // Auxiliar function for border extraction. It gets a border point, and the direction where there is one of the outside of the connected-set pixels.
00447 #ifndef DOXYGEN_IGNORE_THIS
00448 QVPolyline getConnectedSetBorderContourThresholdFromBorderPoint(const QVImage<uChar> &image, const int startPointX, const int startPointY, const uChar threshold)
00449         {
00450         QVPolyline lista;
00451 
00452         lista.closed = true;
00453         lista.append(QPoint(startPointX, startPointY));
00454 
00455         QVIMAGE_INIT_READ(uChar,image);
00456         QRect roi = image.getROI();
00457 
00458         Q_ASSERT_X(roi.contains(startPointX, startPointY), "getContourThresholdFromBorderPoint", "start point out of image ROI");
00459         Q_ASSERT_X(QVIMAGE_PIXEL(image, startPointX, startPointY, 0) >= threshold, "getContourThresholdFromBorderPoint", "start point is not contained in a connected set");
00460 
00461         // We check this is not an interior pixel, neither a solitary one.
00462         // Also we look for a neighbour pixel not belonging to any connected set.
00463         uChar searchDir = 128, numOuterPixels = 0;
00464         for (int i = 0; i<8; i++)
00465                 {
00466                 int x =  startPointX +coorX8Connect[i], y =  startPointY +coorY8Connect[i];
00467                 if (!roi.contains(x, y))
00468                         {
00469                         numOuterPixels++;
00470                         searchDir = i;
00471                         }
00472                 else if (QVIMAGE_PIXEL(image, x, y,0) < threshold)
00473                         {
00474                         numOuterPixels++;
00475                         searchDir = i;
00476                         }
00477                 }
00478 
00479         // Case we receive an interior pixel, raise assert.
00480         Q_ASSERT_X(searchDir < 8, "getContourThresholdFromBorderPoint", "start point is inside the set, not in the border");
00481 
00482         // Case we have a solitary pixel, we return that pixel.
00483         if (numOuterPixels == 8)
00484                 return lista;
00485 
00486         // We insert each point of the border contour, inserting it to the point list.
00487         int sumSearchDir = 0, actualPointX = startPointX, actualPointY = startPointY;
00488         while (true)
00489                 {
00490                 // We search for the next point belonging to the contour.
00491                 uChar d;
00492                 int     nextPointX, nextPointY;
00493                 for (d = 0; d < 8; d++)
00494                         {
00495                         searchDir = (searchDir+1)%8;
00496                         nextPointX = actualPointX + coorX8Connect[searchDir];
00497                         nextPointY = actualPointY + coorY8Connect[searchDir];
00498                         if (roi.contains(nextPointX, nextPointY))
00499                                 if ( (QVIMAGE_PIXEL(image, nextPointX, nextPointY,0) >= threshold) )
00500                                         break;
00501                         }
00502 
00503                 sumSearchDir += d - 3;
00504 
00505                 actualPointX = nextPointX;
00506                 actualPointY = nextPointY;
00507 
00508                 if ( QVIMAGE_PIXEL(image, actualPointX, actualPointY,0) < threshold )
00509                         break;
00510 
00511                 if ( startPointX == actualPointX && startPointY == actualPointY)
00512                         break;
00513 
00514                 lista.append(QPoint(actualPointX, actualPointY));
00515                 searchDir = searchDir + 4;
00516                 }
00517 
00518         lista.direction = (sumSearchDir >= 0);
00519         return lista;
00520         }
00521 #endif
00522 
00523 QVPolyline getConnectedSetBorderContourThreshold(const QVImage<uChar> &image, const QPoint startPoint, const uChar threshold)
00524         {
00525         QVIMAGE_INIT_READ(uChar,image);
00526         const QRect roi = image.getROI();
00527 
00528         int col = startPoint.x(), row = startPoint.y();
00529 
00530         if (QVIMAGE_PIXEL(image, col, row,0) < threshold)
00531                 return QVPolyline();
00532 
00533         while (roi.contains(col+1, row))
00534                 {
00535                 if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
00536                         break;
00537                 col++;
00538                 }
00539 
00540         return getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
00541         }
00542 
00543 QList<QVPolyline> getConnectedSetBorderContoursThreshold(const QVImage <uChar> &image, const uChar threshold)
00544         {
00545         qDebug() << "getPolylinesThreshold()";
00546         QVImage<uChar> mask(image.getCols()+1, image.getRows()+1);
00547         Set(0, mask);
00548 
00549         QVIMAGE_INIT_READ(uChar,image);
00550         QVIMAGE_INIT_WRITE(uChar,mask);
00551 
00552         const QRect roi = image.getROI();
00553 
00554         QList<QVPolyline> polylineList;
00555 
00556         // We look for pixels contained in a connected set (gray-level value >= threshold) in the image
00557         for (int row = roi.y(); row < roi.y() + roi.height(); row++)
00558                 for (int col = roi.x(); col < roi.y() + roi.width(); col++)
00559                         {
00560                         // If we find any pixel like that, we can be sure (because the search we did) it belongs to it's border.
00561                         if (QVIMAGE_PIXEL(image, col, row,0) >= threshold)
00562                                 {
00563                                 // if pixel is not marked, we get it's contour
00564                                 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
00565                                         {
00566                                         QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
00567                                         polylineList.append(lista);
00568 
00569                                         QListIterator<QPoint> iterator(lista);
00570                                         for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
00571                                                 {
00572                                                 actual = iterator.next();
00573                                                 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
00574                                                         QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
00575                                                 }
00576                                         }
00577 
00578                                 // We ensure next pixel we process will not belong to a connected set.
00579                                 while (roi.contains(col+1, row))
00580                                         {
00581                                         if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
00582                                                 break;
00583                                         col++;
00584                                         }
00585 
00586                                 // This is for the case in which we find an internal contour, that has not been processed and marked.
00587                                 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
00588                                         {
00589                                         QVPolyline lista = getConnectedSetBorderContourThresholdFromBorderPoint(image, col, row, threshold);
00590                                         polylineList.append(lista);
00591 
00592                                         QListIterator<QPoint> iterator(lista);
00593                                         for (QPoint previous = iterator.next(), actual; iterator.hasNext(); previous = actual)
00594                                                 {
00595                                                 actual = iterator.next();
00596                                                 foreach (QPoint point, QVPolyline::line(actual.x(), actual.y(), previous.x(), previous.y()))
00597                                                         QVIMAGE_PIXEL(mask, point.x(), point.y(),0) = true;
00598                                                 }
00599                                         }
00600                                 }
00601 
00602                         }
00603         qDebug() << "getPolylinesThreshold():"<< polylineList.size() << "contours obtained";
00604         qDebug() << "getPolylinesThreshold() <~ return";
00605         return polylineList;
00606         }
00607 
00609 
00610 QVPolyline getLineContourThreshold4Connectivity(QVImage<uChar> &image, const QPoint point, QVPolyline &polyline, const uChar threshold, bool reverse)
00611         {
00612         const uInt cols = image.getCols(), rows = image.getRows();
00613         QVIMAGE_INIT_WRITE(uChar, image);
00614 
00615         uInt lastDir = 666, coorX = point.x(), coorY = point.y();
00616 
00617         qDebug() << "\tContour: new contour";
00618 
00619         forever {
00620                 qDebug() << "\tContour:\tAppending point (" << coorX << ", " << coorY << ")";
00621                 if (reverse)
00622                         polyline.prepend(QPoint(coorX, coorY));
00623                 else
00624                         polyline.append(QPoint(coorX, coorY));
00625 
00626                 QVIMAGE_PIXEL(image, coorX, coorY, 0) = 0;
00627 
00628                 uInt dir;
00629                 int newCoorX, newCoorY;
00630                 for (dir = 0; dir < 4; dir++)
00631                         {
00632                         newCoorX = coorX + coorX4Connect[dir];
00633                         newCoorY = coorY + coorY4Connect[dir];
00634 
00635                         // Check if we are inside the limits in that direction
00636                         if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00637                                 continue;
00638 
00639                         // Check if it is a valid direction and if the pixel in that direction is part of a contour
00640                         if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold)  && (lastDir != dir) )
00641                                 break;
00642                         }
00643 
00644                 if (dir == 4) break;
00645 
00646                 coorX = newCoorX;
00647                 coorY = newCoorY;
00648                 lastDir = (dir+2)%4;
00649                 }
00650 
00651         return polyline;
00652         }
00653 
00654 QList<QVPolyline> getLineContoursThreshold4Connectivity(const QVImage<uChar> &image, const uChar threshold)
00655         {
00656         const uInt cols = image.getCols(), rows = image.getRows();
00657         QVImage<uChar> clone = image;
00658 
00659         QList<QVPolyline> polylineList;
00660 
00661         // Transverse the image
00662         for(uInt col = 0; col < cols; col++)
00663                 for(uInt row = 0; row < rows; row++)
00664                         {
00665                         QVIMAGE_INIT_READ(uChar, clone);
00666                         // If we don't have an active pixel, continue
00667                         if ( (QVIMAGE_PIXEL(clone, col, row, 0) < threshold) )
00668                                 continue;
00669 
00670                         // Else, we compose the contour following two active neighbour pixels:
00671                         QVPolyline polyline;
00672 
00673                         // We follow first active neighbour pixel, composing the list of pixels in direct order
00674                         getLineContourThreshold4Connectivity(clone, QPoint(col, row), polyline, threshold, false);
00675 
00676                         // Find another neighbour close to the pixel.
00677                         uInt dir;                       
00678                         int     newCoorX, newCoorY;
00679                         for (dir = 0; dir < 4; dir++)
00680                                 {
00681                                 newCoorX = col + coorX4Connect[dir];
00682                                 newCoorY = row + coorY4Connect[dir];
00683         
00684                                 // Check if we are inside the limits in that direction
00685                                 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00686                                         continue;
00687         
00688                                 // Check if it is a valid direction and if the pixel in that direction is part of a contour
00689                                 if ( (clone(newCoorX, newCoorY) >= threshold) )
00690                                         break;
00691                                 }
00692 
00693                         // If we found it, add the contour in reverse order.
00694                         if (dir != 4)
00695                                 getLineContourThreshold4Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
00696 
00697                         // Finally add the polyline to the list.
00698                         polylineList.append(polyline);
00699                         }
00700 
00701         return polylineList;
00702         }
00703 
00705 // Replicated functions from 4-connected version.
00706 QVPolyline getLineContourThreshold8Connectivity(QVImage<uChar> &image, const QPoint point, QVPolyline &polyline, const uChar threshold, bool reverse)
00707         {
00708         const uInt cols = image.getCols(), rows = image.getRows();
00709         QVIMAGE_INIT_WRITE(uChar, image);
00710 
00711         uInt lastDir = 666, coorX = point.x(), coorY = point.y();
00712 
00713         qDebug() << "\tContour: new contour";
00714 
00715         bool continueCond = true;
00716         while(continueCond)
00717                 {
00718                 qDebug() << "\tContour:\tAppending point (" << coorX << ", " << coorY << ")";
00719                 if (reverse)
00720                         polyline.prepend(QPoint(coorX, coorY));
00721                 else
00722                         polyline.append(QPoint(coorX, coorY));
00723 
00724                 QVIMAGE_PIXEL(image, coorX, coorY, 0) = 0;
00725 
00726                 // Buscamos un píxel en los vecinos 4 conectados.
00727                 uInt dir;
00728                 int newCoorX, newCoorY;
00729                 for (dir = 0; dir < 4; dir++)
00730                         {
00731                         newCoorX = coorX + coorX4Connect[dir];
00732                         newCoorY = coorY + coorY4Connect[dir];
00733 
00734                         // Check if we are inside the limits in that direction
00735                         if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00736                                 continue;
00737 
00738                         // Check if it is a valid direction and if the pixel in that direction is part of a contour
00739                         if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold)  && (lastDir != dir) )
00740                                 break;
00741                         }
00742 
00743                 if (dir == 4) 
00744                         {
00745                         // Buscamos un píxel en los vecinos 4 conectados diagonalmente.
00746                         uInt dir;
00747                         int newCoorX, newCoorY;
00748                         for (dir = 0; dir < 4; dir++)
00749                                 {
00750                                 newCoorX = coorX + coorX4Diag[dir];
00751                                 newCoorY = coorY + coorY4Diag[dir];
00752         
00753                                 // Check if we are inside the limits in that direction
00754                                 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00755                                         continue;
00756         
00757                                 // Check if it is a valid direction and if the pixel in that direction is part of a contour
00758                                 if ( (QVIMAGE_PIXEL(image, newCoorX, newCoorY, 0) >= threshold)  && (lastDir != dir) )
00759                                         break;
00760                                 }
00761                         if (dir == 4) break;
00762 
00763                         coorX = newCoorX;
00764                         coorY = newCoorY;
00765                         lastDir = (dir+2)%4;
00766                         }
00767                 else    {
00768                         coorX = newCoorX;
00769                         coorY = newCoorY;
00770                         lastDir = (dir+2)%4;
00771                         }
00772                 }
00773 
00774         return polyline;
00775         }
00776 
00777 QList<QVPolyline> getLineContoursThreshold8Connectivity(const QVImage<uChar> &image, const uChar threshold)
00778         {
00779         const uInt cols = image.getCols(), rows = image.getRows();
00780         QVImage<uChar> clone = image;
00781 
00782         QList<QVPolyline> polylineList;
00783 
00784         // Transverse the image
00785         for(uInt col = 0; col < cols; col++)
00786                 for(uInt row = 0; row < rows; row++)
00787                         {
00788                         QVIMAGE_INIT_READ(uChar, clone);
00789                         // If we don't have an active pixel, continue
00790                         if ( (QVIMAGE_PIXEL(clone, col, row, 0) < threshold) )
00791                                 continue;
00792 
00793                         // Else, we compose the contour following two active neighbour pixels:
00794                         QVPolyline polyline;
00795 
00796                         // We follow first active neighbour pixel, composing the list of pixels in direct order
00797                         getLineContourThreshold8Connectivity(clone, QPoint(col, row), polyline, threshold, false);
00798 
00799                         // Find another neighbour close to the pixel, in 4 connected neighbours
00800                         uInt dir;                       
00801                         int     newCoorX, newCoorY;
00802                         for (dir = 0; dir < 4; dir++)
00803                                 {
00804                                 newCoorX = col + coorX4Connect[dir];
00805                                 newCoorY = row + coorY4Connect[dir];
00806         
00807                                 // Check if we are inside the limits in that direction
00808                                 if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00809                                         continue;
00810         
00811                                 // Check if it is a valid direction and if the pixel in that direction is part of a contour
00812                                 if ( (clone(newCoorX, newCoorY) >= threshold) )
00813                                         break;
00814                                 }
00815 
00816                         // If we found it, add the contour in reverse order.
00817                         if (dir != 4)
00818                                 getLineContourThreshold8Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
00819                         else    {
00820                                 // Find another neighbour close to the pixel, in diagonal connected neighbours
00821                                 uInt dir;                       
00822                                 int     newCoorX, newCoorY;
00823                                 for (dir = 0; dir < 4; dir++)
00824                                         {
00825                                         newCoorX = col + coorX4Diag[dir];
00826                                         newCoorY = row + coorY4Diag[dir];
00827                 
00828                                         // Check if we are inside the limits in that direction
00829                                         if ( (newCoorX < 0) || (newCoorY < 0) || (newCoorX >= cols) || (newCoorY >= rows) )
00830                                                 continue;
00831                 
00832                                         // Check if it is a valid direction and if the pixel in that direction is part of a contour
00833                                         if ( (clone(newCoorX, newCoorY) >= threshold) )
00834                                                 break;
00835                                         }
00836         
00837                                 // If we found it, add the contour in reverse order.
00838                                 if (dir != 4)
00839                                         getLineContourThreshold8Connectivity(clone, QPoint(newCoorX, newCoorY), polyline, threshold, true);
00840                                 }
00841 
00842                         // Finally add the polyline to the list.
00843                         polylineList.append(polyline);
00844                         }
00845 
00846         return polylineList;
00847         }