src/qvdta/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 <qvdta/qvpolyline.h>
00026 
00027 #define CONST_PI        ((double)3.14159)
00028 #define SIGN(X)         (((X)>=0)?1:-1)
00029 
00030 namespace qvdta
00031 {
00033 // QVPolylines
00034 QVPolyline::QVPolyline(): QList<QPoint>(),
00035         closed(false), direction(false)//, dir(0)
00036         {
00037         qDebug() << "QVPolyline()";
00038         qDebug() << "QVPolyline() <~ return";
00039         };
00040 
00041 QVPolyline::QVPolyline(const QVPolyline &polyline): QList<QPoint>(polyline),
00042         closed(polyline.closed), direction(polyline.direction)//, dir(polyline.dir)
00043         {
00044         qDebug() << "QVPolyline(const QVPolyline &)";
00045         qDebug() << "QVPolyline(const QVPolyline &) <~ return";
00046         };
00047 
00048 QPoint  linesIntersection(QPoint a, QPoint b, QPoint c, QPoint d)
00049         // gets the intersection point for lines ab and cd
00050         {
00051         double x1 = a.rx(), x2 = b.rx(), x3 = c.rx(), x4 = d.rx();
00052         double y1 = a.ry(), y2 = b.ry(), y3 = c.ry(), y4 = d.ry();
00053 
00054         double denominador = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
00055         if (denominador == 0)
00056                 return QPoint( (int)(b.rx() + c.rx())/2, (int)(b.ry() + c.ry())/2 );
00057 
00058         double  ua = (x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3),
00059                 ub = (x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3);
00060 
00061         QPoint p = QPoint(
00062                         (int) (x1 + ua*(x2 - x1) / denominador),
00063                         (int) (y1 + ub*(y2 - y1) / denominador)
00064                         );
00065         return p;
00066         }
00067 
00069 
00070 void drawPoints(const QList<QPoint> &hotPoints, QVImage<uChar,3> &dest)
00071         {
00072         QListIterator<QPoint> iterator(hotPoints);
00073         uChar pixel[3] = { 255,0,0 };
00074 
00075         while(iterator.hasNext())
00076                 {
00077                 QPoint p = iterator.next();
00078                 QVPolyline rectangle = QVPolyline::rectangle(p.x()-2, p.y()-2, p.x()+2, p.y()+2);
00079                 draw(dest, rectangle, pixel,true,true);
00080                 }
00081         }
00082 
00083 void drawPoints(const QList<QPoint> &hotPoints, QVImage<uChar> &dest)
00084         {
00085         QListIterator<QPoint> iterator(hotPoints);
00086         while(iterator.hasNext())
00087                 {
00088                 QPoint p = iterator.next();
00089                 QVPolyline rectangle = QVPolyline::rectangle(p.x()-2, p.y()-2, p.x()+2, p.y()+2);
00090                 draw(dest, rectangle, 255,true,true);
00091                 }
00092         }
00093 
00094 
00095 void draw(QVImage<uChar> &image, const QVPolyline &polyline, const uChar constant, bool linked, bool safe)
00096         {
00097         Q_ASSERT_X(polyline.size() > 0, "drawPolyline()", "polyline size equals zero");
00098 
00099         QListIterator<QPoint> iterator(polyline);
00100         QRect roi = image.getROI();
00101 
00102         QPoint previous;
00103 
00104         if (linked)
00105                 previous = iterator.next();
00106 
00107         QVIMAGE_INIT_WRITE(uChar,image);
00108         while (iterator.hasNext())
00109                 {
00110                 QPoint actual = iterator.next();
00111                 int x = actual.x(), y = actual.y();
00112                 if (!linked && !safe)
00113                         QVIMAGE_PIXEL(image, x, y,0) = constant;
00114                 else if (linked)
00115                         {
00116                         QVPolyline line = QVPolyline::line(x, y, previous.rx(), previous.ry());
00117                         draw(image, line, constant, false, safe);
00118                         previous = actual;
00119                         }
00120                 else if (roi.contains(x, y))
00121                         QVIMAGE_PIXEL(image, x, y,0) = constant;
00122                 }
00123         }
00124 
00125 void draw(QVImage<uChar,3> &image, const QVPolyline &polyline, const uChar constant[3], bool linked, bool safe)
00126         {
00127         Q_ASSERT_X(polyline.size() > 0, "drawPolyline()", "polyline size equals zero");
00128         //if (polyline.size() == 0) return;
00129 
00130         QListIterator<QPoint> iterator(polyline);
00131         QRect roi = image.getROI();
00132 
00133         QPoint previous;
00134 
00135         if (linked)
00136                 previous = iterator.next();
00137 
00138         QVIMAGE_INIT_WRITE(uChar,image);
00139         while (iterator.hasNext())
00140                 {
00141                 QPoint actual = iterator.next();
00142                 int x = actual.x(), y = actual.y();
00143                 if (!linked && !safe)
00144                         {
00145                         QVIMAGE_PIXEL(image, x, y,0) = constant[0];
00146                         QVIMAGE_PIXEL(image, x, y,1) = constant[1];
00147                         QVIMAGE_PIXEL(image, x, y,2) = constant[2];
00148                         //image(actual.rx(), actual.ry(),0) = constant[0];
00149                         //image(actual.rx(), actual.ry(),1) = constant[1];
00150                         //image(actual.rx(), actual.ry(),2) = constant[2];
00151                         }
00152                 else if (linked)
00153                         {
00154                         QVPolyline line = QVPolyline::line(actual.rx(), actual.ry(), previous.rx(), previous.ry());
00155                         draw(image, line, constant, false, safe);
00156                         previous = actual;
00157                         }
00158                 else if (roi.contains(actual.rx(), actual.ry()))
00159                         {
00160                         QVIMAGE_PIXEL(image, x, y,0) = constant[0];
00161                         QVIMAGE_PIXEL(image, x, y,1) = constant[1];
00162                         QVIMAGE_PIXEL(image, x, y,2) = constant[2];
00163                         /*image(actual.rx(), actual.ry(),0) = constant[0];
00164                         image(actual.rx(), actual.ry(),1) = constant[1];
00165                         image(actual.rx(), actual.ry(),2) = constant[2];*/
00166                         }
00167                 }
00168         }
00169 
00170 
00171 void draw(QVImage<uChar> &img, const QList< QVPolyline > &polylineList, const uChar constant, bool linked, bool safe)
00172         {
00173         QListIterator<QVPolyline> iterator(polylineList);
00174         while (iterator.hasNext())
00175                 draw(img, iterator.next(), constant, linked, safe);
00176         }
00177 
00178 void draw(QVImage<uChar,3> &img,const QList< QVPolyline > &polylineList, const uChar constant[3],bool linked,bool safe)
00179         {
00180         QListIterator<QVPolyline> iterator(polylineList);
00181         while (iterator.hasNext())
00182                 draw(img, iterator.next(), constant, linked, safe);
00183         }
00184 
00185 
00186 QVPolyline QVPolyline::ellipse(uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00187         {
00188         QVPolyline ellipse;
00189         float w = 2*CONST_PI/(n-1);
00190         float maxArg = (maxRadio+minRadio)/2;
00191         float minArg = (maxRadio-minRadio)/2;
00192 
00193         for (uInt t = 0; t < n; t++)
00194                 ellipse.append(QPoint ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00195                                                 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00196                                                 ));
00197         return ellipse;
00198         }
00199 
00200 QVPolyline QVPolyline::rectangle(int x1, int y1, int x2, int y2)
00201         {
00202         QVPolyline rectangle;
00203         rectangle.append(QPoint( x1, y1 ));
00204         rectangle.append(QPoint( x1, y2 ));
00205         rectangle.append(QPoint( x2, y2 ));
00206         rectangle.append(QPoint( x2, y1 ));
00207         rectangle.append(QPoint( x1, y1 ));
00208         return rectangle;
00209         }
00210 
00211 QVPolyline QVPolyline::line(int x1, int y1, int x2, int y2)
00212         {
00213         QVPolyline line;
00214 
00215         line.append(QPoint( x1, y1 ));
00216 
00217         if (x1 == x2 && y1 == y2)
00218                 return line;
00219 
00220         int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
00221         
00222         dx=x2-x1;      // the horizontal distance of the line
00223         dy=y2-y1;      // the vertical distance of the line
00224         dxabs=abs(dx);
00225         dyabs=abs(dy);
00226         sdx=SIGN(dx);
00227         sdy=SIGN(dy);
00228         x=dyabs>>1;
00229         y=dxabs>>1;
00230         px=x1;
00231         py=y1;
00232         
00233         if (dxabs>=dyabs) // the line is more horizontal than vertical
00234                 for(i=0;i<dxabs;i++)
00235                         {
00236                         y+=dyabs;
00237                         if (y>=dxabs)
00238                                 {
00239                                 y-=dxabs;
00240                                 py+=sdy;
00241                                 }
00242                         px+=sdx;
00243                         line.append(QPoint( px, py ));
00244                         }
00245         else    // the line is more vertical than horizontal
00246                 for(i=0;i<dyabs;i++)
00247                         {
00248                         x+=dxabs;
00249                         if (x>=dyabs)
00250                                 {
00251                                 x-=dyabs;
00252                                 px+=sdx;
00253                                 }
00254                         py+=sdy;
00255                         line.append(QPoint( px, py ));
00256                         }
00257 
00258         return line;
00259         }
00260 
00261 /*void joinExtremes(QVPolyline &main, QVPolyline &second)
00262         {
00263         QPoint a1 = main.takeLast(), a2 = main.last(), b1 = second.at(0), b2 = second.at(1);
00264 
00265         main.append(linesIntersection(a1,a2, b1,b2));
00266 
00267         for (int i = 1; i< second.size(); i++)
00268                 main.append(second.at(i));
00269         }
00270 
00271 double dist2(QPoint p1, QPoint p2)
00272         { return (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y()); }
00273 
00274 template <typename T>QList<T> & reverse(QList<T> &p)
00275         {
00276         for (int i = 0; i< p.size()/2; i++)
00277                 p.swap(i, p.size()-i-1);
00278         return p;
00279         }
00280 
00281 QList<QVPolyline> * compactPolylines(const QList<QVPolyline> &polylineList, double maxDist)
00282         {
00283         //qDebug() << "compactPolylines()";
00284         uInt n = polylineList.size();
00285         //qDebug() << "compactPolylines(): size"<<n;
00286         //if (n < 2) return new QList<QVPolyline>(polylineList);
00287 
00288         bool * segmentUsed = new bool[n];
00289         QList<QVPolyline> * result = new QList<QVPolyline>();
00290 
00291         for (uInt i=0; i<n; i++)
00292                 segmentUsed[i] = false;
00293 
00294         for (uInt i=0; i<n-1; i++)
00295                 {
00296                 //qDebug() << "compactPolylines(): segmento" << i << segmentUsed[i];
00297                 if (segmentUsed[i]) continue;
00298                 QVPolyline actual = polylineList.at(i);
00299                 if (actual.size() < 2) continue;
00300 
00301                 for (uInt j= i+1; j<n; j++)
00302                         {
00303                         if (segmentUsed[j]) continue;
00304                         QVPolyline next = polylineList.at(j);
00305                         if (next.size() < 2) continue;
00306 
00307                         if (dist2(actual.back(), next.front()) < maxDist)
00308                                 { append(actual, next); segmentUsed[j] = true; }
00309 
00310                         else if (dist2(actual.back(), next.back()) < maxDist)
00311                                 { reverse(next); append(actual, next); segmentUsed[j] = true; }
00312 
00313                         else if (dist2(actual.front(), next.front()) < maxDist)
00314                                 { reverse(actual); append(actual, next); segmentUsed[j] = true; }
00315 
00316                         else if (dist2(actual.front(), next.back()) < maxDist)
00317                                 { reverse(actual); reverse(next); append(actual, next); segmentUsed[j] = true; }
00318                         }
00319 
00320                 if ( (actual.size() > 3) && (dist2(actual.back(), actual.front()) < maxDist) )
00321                         {
00322                         QPoint a1 = actual.takeLast(), a2 = actual.last(), b1 = actual.takeFirst(), b2 = actual.front();
00323                         QPoint p = linesIntersection(a1,a2, b1,b2);
00324                         actual.push_back(p);
00325                         actual.push_front(p);
00326                         }
00327 
00328                 result->append(actual);
00329                 }
00330 
00331         if (!segmentUsed[n-1])
00332                 result->append(polylineList.back());
00333 
00334         delete [] segmentUsed;
00335 
00336         return result;
00337         }*/
00338 
00339 /*void qvEllipse(QVPolyline &ellipse, uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00340         {
00341         float w = 2*CONST_PI/(n-1);
00342         float maxArg = (maxRadio+minRadio)/2;
00343         float minArg = (maxRadio-minRadio)/2;
00344 
00345         for (uInt t = 0; t < n; t++)
00346                 ellipse.append(QPoint ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00347                                                 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00348                                                 ));
00349         }
00350 
00351 void qvRectangle(QVPolyline &rectangle, int x1, int y1, int x2, int y2)
00352         {
00353         rectangle.append(QPoint( x1, y1 ));
00354         rectangle.append(QPoint( x1, y2 ));
00355         rectangle.append(QPoint( x2, y2 ));
00356         rectangle.append(QPoint( x2, y1 ));
00357         rectangle.append(QPoint( x1, y1 ));
00358         }
00359 
00360 void qvLine(QVPolyline &line, int x1, int y1, int x2, int y2)
00361         {
00362         line.append(QPoint( x1, y1 ));
00363         if (x1 == x2 && y1 == y2)
00364                 return;
00365 
00366         int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
00367         
00368         dx=x2-x1;
00369         dy=y2-y1;
00370         dxabs=abs(dx);
00371         dyabs=abs(dy);
00372         sdx=SIGN(dx);
00373         sdy=SIGN(dy);
00374         x=dyabs>>1;
00375         y=dxabs>>1;
00376         px=x1;
00377         py=y1;
00378         
00379         if (dxabs>=dyabs)
00380                 for(i=0;i<dxabs;i++)
00381                         {
00382                         y+=dyabs;
00383                         if (y>=dxabs)
00384                                 {
00385                                 y-=dxabs;
00386                                 py+=sdy;
00387                                 }
00388                         px+=sdx;
00389                         line.append(QPoint( px, py ));
00390                         }
00391         else
00392                 for(i=0;i<dyabs;i++)
00393                         {
00394                         x+=dxabs;
00395                         if (x>=dyabs)
00396                                 {
00397                                 x-=dyabs;
00398                                 px+=sdx;
00399                                 }
00400                         py+=sdy;
00401                         line.append(QPoint( px, py ));
00402                         }
00403         }*/
00404         
00405 
00407 #define dist2(A,B)      (((A).rx() -(B).rx())*((A).rx() -(B).rx()) + ((A).ry() -(B).ry())*((A).ry() -(B).ry()))
00408 #define dot(A,B)        ( (A).rx()*(B).rx() + (A).ry()*(B).ry() )
00409 
00410 // simplifyDP():
00411 //  This is the Douglas-Peucker recursive simplification routine
00412 //  It just marks vertices that are part of the simplified polyline
00413 //  for approximating the polyline subchain v[j] to v[k].
00414 //    Input:  tol = approximation tolerance
00415 //            v[] = polyline array of vertex points 
00416 //            j,k = indices for the subchain v[j] to v[k]
00417 //    Output: mk[] = array of markers matching vertex array v[]
00418 /*void simplifyDP( float tol, QPoint* v, int j, int k, int* mk )
00419         {
00420         if (k <= j+1) // there is nothing to simplify
00421                 return;
00422 
00423         // check for adequate approximation by segment S from v[j] to v[k]
00424         int     maxi = j;          // index of vertex farthest from S
00425         float   maxd2 = 0;         // distance squared of farthest vertex
00426 
00427         QPoint S_P0 = v[j],
00428                 S_P1 = v[k];
00429 
00430         QPoint u = QPoint( S_P1.rx() - S_P0.rx(), S_P1.ry() - S_P0.ry() );
00431         double  cu = dot(u,u);     // segment length squared
00432         
00433         // test each vertex v[i] for max distance from S
00434         // compute using the Feb 2001 Algorithm's dist_Point_to_Segment()
00435         // Note: this works in any dimension (2D, 3D, ...)
00436         QPoint  w;   // vector
00437         QPoint   Pb;                // base of perpendicular from v[i] to S
00438         double  b, cw, dv2;        // dv2 = distance v[i] to S squared
00439         
00440         for (int i=j+1; i<k; i++)
00441                 {
00442                 // compute distance squared
00443                 w = QPoint( v[i].rx() - S_P0.rx(), v[i].ry() - S_P0.ry() );
00444                 cw = dot(w,u);
00445                 if ( cw <= 0 )   // if perp line doesnt fall on u, it calculates the dist2 to the nearest vertex
00446                         dv2 = dist2(v[i], S_P0);
00447                 else if ( cu <= cw )
00448                         dv2 = dist2(v[i], S_P1);
00449                 else
00450                         {
00451                         // if perp line does fall on u, it calculates the height^2 of the triangle
00452                         b = cw / cu;
00453                         Pb = QPoint( S_P0.rx() + (int) (b * u.rx()), S_P0.ry() + (int)(b*u.ry()) );
00454                         dv2 = dist2(v[i], Pb);
00455                         }
00456                 // test with current max distance squared
00457                 if (dv2 <= maxd2) 
00458                         continue;
00459                 // v[i] is a new max vertex
00460                 maxi = i;
00461                 maxd2 = dv2;
00462                 }
00463         if (maxd2 > tol * tol)        // error is worse than the tolerance
00464                 {
00465                 // split the polyline at the farthest vertex from S
00466                 mk[maxi] = 1;                           // mark v[maxi] for the simplified polyline
00467                                                         // recursively simplify the two subpolylines at v[maxi]
00468                 simplifyDP( tol, v, j, maxi, mk );      // polyline v[j] to v[maxi]
00469                 simplifyDP( tol, v, maxi, k, mk );      // polyline v[maxi] to v[k]
00470                 }
00471         // else the approximation is OK, so ignore intermediate vertices
00472         return;
00473         }*/
00474 
00475 // poly_simplify():
00476 //    Input:  tol = approximation tolerance
00477 //            V[] = polyline array of vertex points 
00478 //            n   = the number of points in V[]
00479 //    Output: sV[]= simplified polyline vertices (max is n)
00480 //    Return: m   = the number of points in sV[]
00481 /*QVPolyline IPE2( float tol, const QVPolyline &V )
00482         {
00483         int n=V.size();
00484         if (n == 0) return V;
00485 
00486         QVPolyline sV;
00487 
00488         QPoint* vt = new QPoint[n];      // vertex buffer
00489         int*   mk = new int[n];         // marker buffer
00490         
00491         // STAGE 1.  Vertex Reduction within tolerance of prior vertex cluster
00492         vt[0] = V.at(0);              // start at the beginning
00493 
00494         int i,k,pv;
00495         for (i=k=1, pv=0; i<n; i++)
00496                 {
00497                 // TODO: ERROR de compilación.
00498                 //if (dist2(V.at(i), V.at(pv)) < tol*tol)
00499                 //      continue;
00500                 vt[k++] = V.at(i);
00501                 pv = i;
00502                 }
00503         if (pv < n-1)
00504         vt[k++] = V.at(n-1);      // finish at the end
00505         
00506         // STAGE 2.  Douglas-Peucker polyline simplification
00507         for(int i=0; i<n; ++i)
00508                 mk[i]=0;
00509         mk[0] = mk[k-1] = 1;       // mark the first and last vertices
00510         simplifyDP( tol, vt, 0, k-1, mk );
00511         
00512         // copy marked vertices to the output simplified polyline
00513         for (int i=0; i<k; i++)
00514                 {
00515                 if (mk[i])
00516                         sV.append(vt[i]);
00517                         //sV.push_back(vt[i]);
00518                 }
00519         delete vt;
00520         delete mk;
00521         return sV;         // simplyfied polyline
00522         }*/
00523 }

Generated on Thu Dec 13 13:06:26 2007 for QVision by  doxygen 1.5.3