src/qvip/qvpolyline.cpp

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

Generated on Thu Jul 17 17:23:28 2008 for QVision by  doxygen 1.5.3