src/qvip/qvpolylinef.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/qvpolylinef.h>
00027 #include <qvip/qvpolyline.h>
00028 #include <qvmath/qvmatrixalgebra.h>
00029 
00030 #include <iostream>
00031 #include <float.h>
00032 
00034 // QVPolylineFs
00035 
00036 // Iterative point elimination:
00037 #ifndef DOXYGEN_IGNORE_THIS
00038 class ClassAuxIPE_F
00039         {
00040         public:
00041                 double cost;
00042                 int index;
00043                 ClassAuxIPE_F *prev,*next;
00044         };
00045 
00046 bool costLessThan(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00047         {
00048         return s1->cost < s2->cost;
00049         }
00050 
00051 bool indexLessThan(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00052         {
00053         return s1->index < s2->index;
00054         }
00055 
00056 inline double costElimination(const QVPolylineF &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_F {
00069         public:
00070         auxLine_F(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 QVPolylineF &polyline, QVPolylineF &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_F*> 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_F);
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_F *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_F* 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_F*>::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_F> 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_F(l1,l2,l3,ratio_eig < 0.1));
00223                         }
00224 
00225                 for(int i=0;i<list.size();i++)
00226                         {
00227                         QPointF 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                                 QPointF 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 // Draw
00293 QVPolylineF::QVPolylineF(): QList<QPointF>(),
00294         closed(false), direction(false)//, dir(0)
00295         {
00296         qDebug() << "QVPolylineF()";
00297         qDebug() << "QVPolylineF() <~ return";
00298         };
00299 
00300 QVPolylineF::QVPolylineF(const QVPolyline &polyline): QList<QPointF>(),
00301         closed(polyline.closed), direction(polyline.direction)//, dir(polyline.dir)
00302         {
00303         foreach(QPoint point, polyline)
00304                 {
00305                 append(QPointF(point));
00306                 }
00307         qDebug() << "QVPolylineF(const QVPolylineF &)";
00308         qDebug() << "QVPolylineF(const QVPolylineF &) <~ return";
00309         };
00310 
00311 QVPolylineF::QVPolylineF(const QVPolylineF &polyline): QList<QPointF>(polyline),
00312         closed(polyline.closed), direction(polyline.direction)//, dir(polyline.dir)
00313         {
00314         qDebug() << "QVPolylineF(const QVPolylineF &)";
00315         qDebug() << "QVPolylineF(const QVPolylineF &) <~ return";
00316         };
00317 
00318 
00319 // QPointF      linesIntersection(QPointF a, QPointF b, QPointF c, QPointF 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 QPointF( (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 //      QPointF p = QPointF(
00333 //                      (int) (x1 + ua*(x2 - x1) / denominador),
00334 //                      (int) (y1 + ub*(y2 - y1) / denominador)
00335 //                      );
00336 //      return p;
00337 //      }
00338 
00339 
00340 
00342 
00343 QVPolylineF QVPolylineF::ellipse(uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00344         {
00345         QVPolylineF 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(QPointF (        (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 QVPolylineF QVPolylineF::rectangle(float x1, float y1, float x2, float y2)
00358         {
00359         QVPolylineF rectangle;
00360         rectangle.append(QPointF( x1, y1 ));
00361         rectangle.append(QPointF( x1, y2 ));
00362         rectangle.append(QPointF( x2, y2 ));
00363         rectangle.append(QPointF( x2, y1 ));
00364         rectangle.append(QPointF( x1, y1 ));
00365         return rectangle;
00366         }
00367 
00368 QVPolylineF::operator QVPolyline() const
00369         {
00370         QVPolyline polyline;
00371         foreach(QPointF pointf, *this)
00372                 {
00373                 polyline.append( QPoint(pointf.toPoint()) );
00374                 }
00375         return polyline;
00376         }
00377 

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