Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Modules/ImageProcessor/ImageProcessorTools/SegmentationTools.h

Go to the documentation of this file.
00001 /** 
00002 * @file SegmentationTools.h
00003 * Declaration of file SegmentationTools.h
00004 *
00005 * @author <A href=mailto:damd@free.fr>Damien DEOM</A>
00006 */
00007 
00008 
00009 #ifndef _SEGMENTATION_TOOLS_
00010 #define _SEGMENTATION_TOOLS_
00011 
00012 
00013 /**
00014 * @class file SegmentationTools.h
00015 * This is a utility class for image processing.
00016 * A special slist has been defined :it can be used in other domains
00017 * than the little world of image processing ...
00018 */
00019 
00020 #include "Tools/Math/Geometry.h"
00021 #include "Tools/Math/Vector2.h"
00022 #include "Tools/ColorClasses.h"
00023 
00024 typedef Vector2<int> point;
00025 typedef Vector2<double> direction;
00026 
00027 struct LinePair2;
00028 
00029 ///////////////////////////////////////////////////////////
00030 ///               geometrical stuff
00031 ///////////////////////////////////////////////////////////
00032 
00033 
00034 inline point mil(point& v1,point& v2) {
00035   return point ((v1.x+v2.x) / 2,(v1.y+v2.y) / 2);
00036 };
00037 
00038 
00039 
00040 /*! Gives a number between 0 and 360 with the same order as v.angle()*/
00041 inline double theta2(point v1, point v2){
00042   double t = 0;
00043   int dx = v1.x - v2.x;
00044   int dy = v1.y - v2.y;
00045   int ax = abs(dx);
00046   int ay = abs(dy);
00047   if (dx == 0 && dy == 0) t = 0;
00048   else t = (double)dy /(double)(ax + ay);
00049   if (dx < 0) t = 2 - t;
00050   else if (dy < 0) t = 4 + t;
00051 
00052   return t*90;
00053 }
00054 
00055 
00056 
00057 /** 
00058 *same principle as theta2, but using trigonoetric 
00059 *functions (also more time consuming)
00060 */
00061 inline double AngleRelativeToHorizontal(const point & pt1, const point& pt2) {
00062   double d1 =  abs(pt2.x - pt1.x);
00063   double d2 =  (pt2 - pt1).abs();
00064   if ((d2 == 0) || (d1/d2 < -1) || (d1/d2 > 1))
00065     return 0;
00066   else
00067     return acos(d1/d2);
00068 }
00069 
00070 
00071 
00072 
00073 /**
00074 * implementation of slist : all the objects to be listed must
00075 * derive from the template class "listed" (use the name of the class
00076 * as template parameter for normal use) 
00077 */
00078 
00079 
00080 template <class T> struct listed {
00081 
00082   T* next;
00083 
00084   listed(): next(0) {}
00085 
00086   ~listed() {}
00087 
00088   T* getNext() const {return next;}
00089 
00090   void insert(T* i) {
00091     if (!i) return;
00092     T* tmp = next;
00093     next = i;
00094     i->setNext(tmp);
00095   }
00096 
00097   void swapNext(T* toSwapWith) {  // swap the element after next with toSwapWith
00098     
00099     if (!(next && toSwapWith && toSwapWith->next)) return;
00100     T* tmp = this->next;
00101     T* tmp2 = toSwapWith->next->next;
00102 
00103     this->next = toSwapWith->next;
00104     toSwapWith->next->next = tmp;
00105     toSwapWith->next = tmp2;
00106   }
00107 
00108 };
00109 
00110 
00111 /*! the slist itself*/
00112 template <class T> class slist {
00113 
00114 private:
00115   unsigned int size;
00116   T* first, *last;
00117 
00118 public:
00119 
00120   class iterator {
00121 
00122   private:
00123     T* elt;
00124   public:
00125   
00126     iterator(T* l = 0) : elt(l) {}
00127 
00128     T* operator++() {
00129       if (!elt) return 0;
00130       elt= elt->next;
00131       return elt;
00132     }
00133     T* operator++(int) {
00134       if (!elt) return 0;
00135       T* old = elt;
00136       elt = elt->next;
00137       return old;
00138     }
00139     T*operator+=(int n) {
00140       T* tmp = elt;
00141       int i;
00142       for (i = 0; i<n;++i) 
00143         if (tmp) tmp = tmp->next;
00144         else return 0;
00145       elt = tmp;
00146       return elt;
00147     }
00148     T* operator = (T* e) {
00149       elt = e;
00150       return elt;
00151     }
00152     bool operator != (const T* e) const {
00153       return (elt != e);
00154     }
00155 
00156     T* operator ->() const {return elt;}
00157     T* operator *() const {return elt;}
00158     bool end() {return !elt;}
00159   };
00160 
00161   T* front() const {return first;}
00162   T* back() const {return last;}
00163   void setLast(T* l) {last = l;}
00164   
00165   void cutFront() { first = last = 0;size = 0;}
00166 
00167   slist() : size(0), first(0), last(0){}
00168   
00169   void push_front(T* lp) {
00170     if (!lp) return;
00171     if (!last) last = lp; 
00172 
00173     lp->next = first;
00174     first = lp;
00175     ++size;
00176   }
00177 
00178   void push_back(const T* lp) {
00179     if (!lp) return;
00180     if (!first) {first = last = lp;} else last->next = lp; 
00181     last = lp;
00182     ++size;
00183   }
00184 
00185   void push_back(slist<T>& lst) {
00186     if (last) {
00187       last->next = lst.front();
00188       last = lst.back();
00189     } else {
00190       first = lst.front();
00191       last = lst.back();
00192     }
00193     size+= lst.getSize();
00194     lst.cutFront();
00195   }
00196 
00197   unsigned getSize() const {return size;}
00198   bool empty() {return size==0;}
00199 
00200   void clear() {
00201     while (first) {
00202       T* tmp = first->next;
00203       delete first;
00204       first = tmp;
00205     }
00206     last = 0;
00207     size = 0;
00208   }
00209 
00210   T* pop_front() {
00211     if (!first) return 0;
00212     T* tmp = first->next;
00213     delete first;
00214     first = tmp;
00215     if (size==1) last = first;
00216     --size;
00217     return first;
00218   }
00219 
00220   void insert(T*  pos, T* i) {
00221     if (!pos) return;
00222     T* tmp = pos->next;
00223 
00224     if (!tmp) {
00225       pos->next = i;
00226       i->next = 0;
00227       last = i;
00228     } else {
00229       pos->next = i;
00230       i->next = tmp;
00231     }
00232     if (pos==last) last = i;
00233     ++size;
00234   }
00235 
00236   void erase(T* e) {
00237 
00238     if (e->next = last) last = e;
00239     T* n = e->next->next;
00240 
00241     delete e->next;
00242     e->next = n;
00243     --size;
00244   }
00245 
00246 };
00247 
00248 
00249 
00250 /**
00251 * definition of an edge and a linePair : very convenient for mixing both 
00252 * in a list.
00253 * If you only want to use linePairs, please use the
00254 * LinePair2 struct defined below
00255 */
00256 
00257 struct figure : public listed<figure> {
00258 
00259 
00260   figure() : listed<figure>() {}
00261   virtual ~figure() {}
00262 
00263   virtual unsigned short getId() = 0;
00264   virtual point toConsider() = 0;
00265   virtual double size() {return 0;}
00266 };
00267 
00268 class edge : public figure {
00269 private:
00270   point pt;
00271   unsigned short id;
00272 public:
00273 
00274   edge(point& p, unsigned short i) : figure(), pt(p) , id(i) {}
00275   edge(int& x, int& y, unsigned short i) :  figure(), id(i) {
00276     pt.x = x; pt.y = y;
00277   }
00278 
00279   point toConsider() {;return pt;}
00280   unsigned short getId() {return id;}
00281 };
00282 
00283 struct LinePair : public figure {
00284   virtual point pt1() = 0;
00285   virtual point pt2() = 0;
00286   virtual direction getDirection() = 0;
00287 };
00288 
00289 class horLinePair : public LinePair {
00290   point p1;
00291   int p2x;
00292 public:
00293 
00294   horLinePair(point p1, int p2x)  {
00295     this->p1 = p1;
00296     this->p2x = p2x;
00297   }
00298 
00299   ~horLinePair() {}
00300 
00301   horLinePair(point& p1, point& p2)  {
00302     this->p1 = p1;
00303     this->p2x = p2.x;
00304   }
00305 
00306   unsigned short getId() {return (unsigned short)p1.y;}
00307   point toConsider() {return point((p1.x+p2x)/2, p1.y);}
00308   point pt1() {return p1;}
00309   point pt2() {return point(p2x, p1.y);}
00310   double size() {return (double) (p2x - p1.x);}
00311   direction getDirection() {return direction(1,0);}
00312 
00313 
00314 };
00315 
00316 
00317 
00318 struct extLinePair : public LinePair {
00319 
00320   point p1, p2;
00321   unsigned short id;
00322 
00323   extLinePair(point& p1, point& p2, unsigned short id = 0)  {
00324     this->p1 = p1;
00325     this->p2 = p2;
00326     this->id = id;
00327   }
00328 
00329   extLinePair()  {
00330     this->p1 = point();
00331     this->p2 = point();
00332     this->id = 0;
00333   }
00334 
00335   point pt1() {return p1;}
00336   point pt2() {return p2;}
00337   double size() {return (p2 - p1).abs();}
00338 
00339   point toConsider() {return mil(p1, p2);}
00340 
00341   unsigned short getId() {return id;}
00342   direction getDirection() {
00343     return direction((double)(p2.x - p1.x),(double)(p2.y - p1.y));
00344   }
00345 
00346 
00347 };
00348 
00349 
00350 
00351 struct LinePair2 : public listed<LinePair2> {
00352 
00353 
00354   point p1, p2;
00355 
00356   LinePair2(point& p1, point& p2) : listed<LinePair2>() {
00357     this->p1 = p1;
00358     this->p2 = p2;
00359   }
00360 
00361   
00362   /** defines the default order for LinePairs.
00363   *order is lexigographical in v1 (v1.y,v1.x).
00364   */
00365 
00366   bool operator <(const LinePair2& other){
00367     return p1.y < other.p1.y || 
00368          p1.y == other.p1.y && p1.x < other.p1.y ;
00369   }
00370 
00371   virtual colorClass getColor() {return noColor;}
00372   virtual double getLength() {return (p2 - p1).abs();}
00373 
00374 };
00375 
00376 /*
00377 * same as the LinePair2, exept the length: the value is stored
00378 * in case this parameter is frequently calcultaed 
00379 */
00380 
00381 class LinePair3 : public LinePair2 {
00382 private:
00383   double length;
00384   bool updated;
00385 
00386 public:
00387 
00388   void setP1(point& p) {
00389     updated = false;
00390     p1 = p;
00391   }
00392   void setP2(point& p) {
00393     updated = false;
00394     p2 = p;
00395   }
00396 
00397 
00398   LinePair3(point& p1, point& p2) : LinePair2(p1, p2), length(0), updated(false) {}
00399 
00400   void updateLength() { 
00401     length = (p2 - p1).abs();
00402     updated = true;
00403   }
00404   double getLength() {
00405     if (!updated) updateLength();
00406     return length;
00407   }
00408 
00409 };
00410 
00411 
00412 struct coloredLinePair2 : public LinePair2 {
00413 private :
00414   colorClass color;
00415 public:
00416 
00417 
00418   coloredLinePair2(point& v1,point& v2, colorClass c = noColor) :
00419     LinePair2(v1, v2), color(c) {}
00420 
00421   colorClass getColor() {return color;}
00422 };
00423 
00424 
00425 
00426 /*! calculate the angle between two lines using theta2*/
00427 
00428 inline double theta2(LinePair2* l1,LinePair2* l2) {
00429 
00430   double angle1 = theta2(l1->p1,l1->p2);
00431   double angle = theta2(l2->p1, l2->p2) - angle1;
00432 
00433   while (angle<0) angle+=360;
00434 
00435   return angle;
00436 
00437 }
00438 
00439 /*
00440 * Line detection related algorithms
00441 */
00442 
00443 
00444 /**
00445 *  finds the nearest point starting from lp
00446 *  @param lp the starting point
00447 *  @return the nearest point
00448 */
00449 inline figure* getMin (figure * lp) {
00450   
00451   figure * min = lp->getNext();
00452 
00453   if (!min) return 0;
00454 
00455   slist<figure>::iterator it = min;
00456 
00457   double d_min = Geometry::distance(
00458     lp->toConsider(),
00459     it->toConsider());
00460 
00461   unsigned short cur_id = min->getId();
00462 
00463   while(++it && cur_id == it->getId()) {
00464     
00465     double d = Geometry::distance(
00466       lp->toConsider(),
00467       it->toConsider());
00468 
00469     if (d <d_min) {
00470       d_min = d;
00471       min = *it;
00472     }
00473   } 
00474 
00475   return min;
00476 }
00477 
00478 
00479 /**
00480 * join the nearest LinePairs in order to make the
00481 * interpretation of the shape possible 
00482 */
00483 
00484 inline void createLinearSegment(slist<figure>& lst) {
00485 
00486   if (lst.getSize()<3)return;
00487   slist<figure>::iterator start = lst.front();
00488 
00489   do {
00490     figure* min = getMin(*start);
00491     if (min != *start) start->swapNext(min);
00492   } while (++start && start->getNext());
00493 
00494   lst.setLast(*start);
00495 }
00496 
00497 
00498 
00499 
00500 /* ! return the middle point of the line*/
00501 inline Vector2<double> mil(LinePair2& lp)  {
00502   return Vector2<double> ((lp.p1.x+lp.p2.x)/2, (lp.p1.y+lp.p2.y)/2);
00503 };
00504 
00505 /*! transform a line pair into a line defined into the Geometry library */ 
00506 inline Geometry::Line makeLine(LinePair2* lp) {
00507   Geometry::Line l;
00508 
00509   l.base = Vector2<double> ((double)lp->p1.x, (double)lp->p1.y);
00510   l.direction = Vector2<double> ((double)lp->p2.x, (double)lp->p2.y) - l.base;
00511 
00512   return l;
00513 };
00514 
00515 
00516 #endif
00517 
00518 /*
00519  * Change log :
00520  * $Log: SegmentationTools.h,v $
00521  * Revision 1.4  2004/09/07 16:01:15  deom
00522  * Documentation corrected
00523  *
00524  * Revision 1.3  2004/09/02 09:30:53  deom
00525  * commented segmentation tools
00526  *
00527  * Revision 1.15  2004/08/14 08:39:20  deom
00528  * optimized
00529  *
00530  * Revision 1.14  2004/06/17 14:18:22  kerdels
00531  * fixed bug in rfieldspecialist, changed threshold for bridge-detection
00532  *
00533  * Revision 1.13  2004/06/17 11:55:31  serwe
00534  * added changelog
00535  *
00536  */

Generated on Thu Sep 23 19:57:29 2004 for GT2004 by doxygen 1.3.6