Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

QbWatershed.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Array_Trait_QbWatershed_h
00002 #define Impala_Core_Array_Trait_QbWatershed_h
00003 
00004 #include "Core/Geometry/PointZ.h"
00005 #include "Core/Array/Pattern/FcvArray.h"
00006 #include "Core/Array/Pattern/QCollection.h"
00007 #include "Core/Array/Pattern/Array2D.h"
00008 #include "Core/Array/Arrays.h"
00009 
00010 namespace Impala
00011 {
00012 namespace Core
00013 {
00014 namespace Array
00015 {
00016 namespace Trait
00017 {
00018 
00019 
00020 const int CONTOURVAL    = -3;
00021 const int MASKVAL       = -2;
00022 const int INITVAL       = -1;
00023 const int WSHEDVAL      =  0;
00024 
00025 
00026 template<class DstArrayT, class Src1ArrayT, class Src2ArrayT>
00027 class QbWatershed {
00028 
00029     typedef typename DstArrayT::ArithType DstArithT;
00030     typedef typename Src1ArrayT::ArithType Src1ArithT;
00031     typedef typename Src2ArrayT::ArithType Src2ArithT;
00032 
00033 public:
00034 
00035     typedef struct structPointValue {
00036         DstArithT arith; 
00037         Src1ArithT img; 
00038         Src1ArithT mask; 
00039         Geometry::PointZ point;
00040         int cost;
00041         int lastDist;
00042 
00043         bool
00044         less(const struct structPointValue &rhs) const 
00045         { 
00046             if (cost<rhs.cost)
00047                 return true;
00048             if (cost>rhs.cost)
00049                 return false;
00050             // for equal values be a FIFO=QUEUE
00051             return localOrderCounter < rhs.localOrderCounter; 
00052         }
00053 
00054         bool
00055         operator < (const struct structPointValue &rhs) const
00056         { 
00057 //          return !less(rhs); // for priority_queue returning highest value
00058             return less(rhs); // for set/multiset returning lowest value
00059         }
00060  
00061         unsigned localOrderCounter;
00062     } PointValueT;
00063 
00064     typedef Pattern::Qset<PointValueT> QT;
00065 
00066     typedef struct {
00067         Geometry::PointZ point;
00068         DstArithT arith;
00069         Src1ArithT img;
00070         Src1ArithT mask;
00071     } NeighborsT;
00072  
00073     typedef Pattern::FcvArray<NeighborsT> VecNeighborsT;
00074 
00075     QbWatershed(int width, int height, int minVal, int maxVal,
00076                 Array2dScalarInt32* exportDistImage = 0)
00077         : costImage(width, height, 0), distImage(width, height, 0)
00078     { 
00079         labelcode=0;
00080         globalOrderCounter=0;
00081         curdist=1;
00082         h = hmin = minVal;
00083         hmax = maxVal;
00084         for(int i=0;i<256;i++)
00085             hist[i]=false;
00086         exportDistIm = exportDistImage;
00087     }
00088 
00089     bool
00090     GlobalPixelInit(PointValueT&vp, DstArithT& arith, Src1ArithT img, Src1ArithT)
00091     {
00092         arith = INITVAL;
00093         return false;
00094     }
00095 
00096     bool
00097     WantAnotherLoop()
00098     { 
00099         h++; 
00100         if (h<=hmax) 
00101             return true; 
00102         else {
00103             //exports distImage if that was required by the user
00104             if (exportDistIm) {
00105                 for (int y=0 ; y<distImage.getDim(1) ; y++)
00106                     for (int x=0 ; x<distImage.getDim(0) ; x++)
00107                         *Pattern::ArrayCPB(exportDistIm, x, y) = distImage(x, y);
00108             }
00109             return false;
00110         }
00111     }
00112 
00113     bool
00114     WantFreshStartLocalPixelInit()
00115     {
00116         return true; //this is the real action of this function
00117     }
00118 
00119     bool
00120     LocalPixelInit(PointValueT& vp, DstArithT& arith, Src1ArithT img,
00121                    Src1ArithT mask, bool& continua)
00122     { 
00123         vp.arith=arith;
00124         vp.img=img;
00125         vp.mask=mask;
00126         continua = true;
00127         bool q=false;
00128 
00129 //when I'm first time in this function (for level hmin) I fill the histogram
00130         if (h==hmin) {
00131             hist[img]=true;
00132         }
00133 //then, chech if the current level h exist in the image
00134         if (h!=hmin && !hist[h] ) {
00135             continua = false;
00136             return q;
00137         }
00138 
00139 //init for searching new local minima (with this one starts the algorithm) (point 4)
00140         if (img == h && arith == INITVAL && arith != CONTOURVAL ) {
00141             q=true; // do queue
00142             distImage(vp.point.mX, vp.point.mY)=0; // this I don't have to do, it
00143                                                  // was done in globalinit
00144             costImage(vp.point.mX, vp.point.mY)=1;
00145             vp.arith = MASKVAL;
00146             vp.lastDist = 0;
00147         }
00148 //init for the part of propagating "contour" pixels (point 1)
00149         if (img==h && (arith == CONTOURVAL || arith == WSHEDVAL) ) {
00150             distImage(vp.point.mX, vp.point.mY)= 1;
00151             costImage(vp.point.mX, vp.point.mY)= -2;
00152             curdist=1;
00153             vp.lastDist=1;
00154             q=true; // do queue
00155         }
00156 
00157         if (q) { 
00158             vp.localOrderCounter=globalOrderCounter++; // for equal values
00159                                                        // be a FIFO=QUEUE
00160             vp.cost=costImage(vp.point.mX, vp.point.mY);
00161         }
00162         arith=vp.arith;
00163         return q;
00164     }
00165 
00166     // first from queue
00167     void
00168     First(const PointValueT& val, DstArithT arith, Src1ArithT img, Src1ArithT)
00169     { 
00170         center=val; 
00171         center.arith=arith; //take  the current value from the image, not from queue
00172     }
00173 
00174     // sequentially read point/value and action to be done; 
00175     // return false if no more data
00176     Pattern::QAction
00177     Result()
00178     {
00179         if (index>=neighboursout.size())
00180             return Pattern::STOP; // quit asking 
00181         resultVP=neighboursout[index];
00182         Pattern::QAction action=actionsout[index];
00183         index++;
00184         return action;
00185     }
00186 
00187     void
00188     GetItemToQueue(PointValueT& vp)
00189     {
00190         vp=resultVP;
00191     }
00192 
00193     // speed up searching in set<less..>, provide low/up bound where
00194     // resultVP is never out
00195     void
00196     GetItemToRemove(PointValueT& lower, PointValueT& upper)
00197     {
00198         lower.cost=upper.cost=resultVP.cost;
00199         lower.localOrderCounter=0; // unsigned int
00200         upper.localOrderCounter=4000000000;
00201     }
00202 
00203     bool
00204     KillThisOne(const PointValueT& vp)
00205     {
00206         if (resultVP.cost==vp.cost && resultVP.point==vp.point) 
00207             return true;
00208         return false; 
00209     }
00210 
00211     void
00212     GetItemToWrite(Geometry::PointZ& point, DstArithT& arith)
00213     {
00214         point=resultVP.point;
00215         arith=resultVP.arith;
00216     }
00217 
00218     void
00219     Calculate(VecNeighborsT& neighboursin)
00220     {
00221         index=0; // for result()
00222         neighboursout.clear();
00223         actionsout.clear();
00224 
00225         int i;
00226         bool step2=false;
00227 //here starts the propagation part (in algorithm point 2 to 4)
00228         if (!neighboursin.empty() && (center.arith == CONTOURVAL)) {
00229             // here we increment curDist, every time a new layer of pixels is
00230             // gonna be processed.
00231             if (center.lastDist > curdist) {
00232                 curdist++;
00233             }
00234 
00235             step2=true;
00236             for (i=0; i<neighboursin.size(); i++) {
00237                 NeighborsT val=neighboursin[i];
00238                 PointValueT neighbor;
00239                 neighbor.point=val.point; 
00240                 neighbor.arith=val.arith; 
00241                 neighbor.img=val.img; 
00242                 neighbor.mask=val.mask;
00243                 neighbor.cost=costImage(neighbor.point.mX, neighbor.point.mY);
00244                 int dn= distImage(neighbor.point.mX, neighbor.point.mY);
00245                 if ((neighbor.arith > 0 || neighbor.arith == WSHEDVAL
00246                        || neighbor.arith == CONTOURVAL)) { //not labeled yet
00247                     if (neighbor.arith > 0) {
00248                         if (center.arith == WSHEDVAL
00249                                  || center.arith == CONTOURVAL  ) {
00250                             center.arith = neighbor.arith;
00251                             neighboursout.push_back(center);
00252                             actionsout.push_back(Pattern::WRITE);
00253                         } else if (center.arith != neighbor.arith) {
00254                             center.arith = WSHEDVAL;
00255                             neighboursout.push_back(center);
00256                             actionsout.push_back(Pattern::WRITE);
00257                         }
00258                     } else if (center.arith < 0 && center.img == h) {
00259                         center.arith = WSHEDVAL;
00260                         neighboursout.push_back(center);
00261                         actionsout.push_back(Pattern::WRITE);
00262                     }
00263                 }
00264                 else if((neighbor.arith <0 && neighbor.img == h) 
00265                             && distImage(neighbor.point.mX, neighbor.point.mY) == 0) {
00266                     // nu aici trebuie incrementat current distance, sau in orice
00267                     // caz nu de fiecare data cumva trebuie sa semnalizez cind
00268                     // iau de pe stiva, primul pixel pus aici
00269                     // pot folosi de exemplu cimputl cost...
00270                     distImage(neighbor.point.mX, neighbor.point.mY)=curdist+1; 
00271                     neighbor.lastDist=distImage(neighbor.point.mX, neighbor.point.mY);
00272                     costImage(neighbor.point.mX, neighbor.point.mY) = -1;// curdist+2;
00273                     neighbor.localOrderCounter=globalOrderCounter++; // for equal
00274                     // values be a FIFO=QUEUE
00275                     neighbor.cost=costImage(neighbor.point.mX, neighbor.point.mY);
00276                     neighboursout.push_back(neighbor);
00277                     actionsout.push_back(Pattern::QUEUE);
00278 
00279                     neighbor.arith = CONTOURVAL;
00280                     neighboursout.push_back(neighbor);
00281                     actionsout.push_back(Pattern::WRITE);
00282 
00283                 }
00284                 //leon a adaugat asta, ca sa markez pixeli de contur
00285                 //else
00286                 if (neighbor.img!=center.img && center.img==h 
00287                         && neighbor.arith<0) {
00288                     // we mark this pixel, to be treated later, but we do not put
00289                     // it on Queue
00290                     neighbor.arith=CONTOURVAL; // line 9
00291                     distImage(neighbor.point.mX, neighbor.point.mY)= 1; 
00292                     costImage(neighbor.point.mX, neighbor.point.mY)= -2;
00293                     neighbor.localOrderCounter=globalOrderCounter++; // for equal
00294                     // values be a FIFO=QUEUE
00295                     neighbor.cost=costImage(neighbor.point.mX, neighbor.point.mY);
00296                     neighboursout.push_back(neighbor);
00297                     actionsout.push_back(Pattern::WRITE);
00298                 }
00299 
00300             }
00301         }
00302 
00303 
00304 //the next LOOP(2) should start only AFTER ALL pixels from the queue were tried
00305 // to be processed with LOOP1
00306 //here starts the propagation part searching for local minima (in algorithm point 4)
00307 
00308         if (!step2) {
00309             //if not labeled yet
00310             if(!neighboursin.empty() && center.arith == MASKVAL) {
00311                 labelcode++;
00312                 center.arith = labelcode;
00313                 neighboursout.push_back(center);
00314                 actionsout.push_back(Pattern::WRITE);
00315             } //end if(!neighboursin.empty() && center.arith == MASKVAL)
00316 
00317             if(!neighboursin.empty() && center.arith > 0) {
00318                 for (i=0; i<neighboursin.size(); i++) {
00319                     NeighborsT val=neighboursin[i];
00320                     PointValueT neighbor;
00321                     neighbor.point=val.point; 
00322                     neighbor.arith=val.arith; 
00323                     neighbor.img=val.img; 
00324                     neighbor.mask=val.mask;
00325                     neighbor.cost=costImage(neighbor.point.mX, neighbor.point.mY);
00326 
00327                     if(neighbor.arith == MASKVAL 
00328                         || neighbor.arith == INITVAL )
00329 //if we uncomment this, the watershed lines will be removed
00330 //                      || neighbor.arith == WSHEDVAL
00331 //                      || neighbor.arith == CONTOURVAL) //not labeled yet
00332                     {
00333                         if(neighbor.img==center.img && center.img==h ) {
00334                             neighbor.arith=center.arith; // line 9
00335                             costImage(neighbor.point.mX, neighbor.point.mY)= 0;
00336                             neighbor.localOrderCounter=globalOrderCounter++; // for
00337                             // equal values be a FIFO=QUEUE
00338                             neighbor.cost=costImage(neighbor.point.mX,
00339                                                     neighbor.point.mY);
00340                             neighboursout.push_back(neighbor);
00341                             actionsout.push_back(Pattern::WRITE);
00342                             neighboursout.push_back(neighbor);
00343                             actionsout.push_back(Pattern::QUEUE);
00344                         }
00345                         else if(neighbor.img!=center.img && neighbor.arith<0) {
00346                             // this is contour pixel
00347                             // we mark this pixel, to be treated by the other loop,
00348                             // but we do not put it on Queue
00349                             neighbor.arith=CONTOURVAL; // line 9
00350                             distImage(neighbor.point.mX, neighbor.point.mY)= 1; 
00351                             costImage(neighbor.point.mX, neighbor.point.mY)= -2;
00352                             neighbor.localOrderCounter=globalOrderCounter++; // for
00353                             // equal values be a FIFO=QUEUE
00354                             neighbor.cost=costImage(neighbor.point.mX,
00355                                                     neighbor.point.mY);
00356                             neighboursout.push_back(neighbor);
00357                             actionsout.push_back(Pattern::WRITE);
00358                         }
00359                     }
00360                 }
00361             }
00362         }
00363 //here ends the propagation part searching for local minima (in algorithm point 4)
00364         
00365     } //end calculate
00366 
00367 private:
00368 
00369     PointValueT center;
00370     Pattern::FcvArray<PointValueT> neighboursout;
00371     Pattern::FcvArray<Pattern::QAction> actionsout;
00372     int index;
00373     int labelcode;
00374     int curdist;
00375     PointValueT resultVP;
00376 
00377     int h;  //current gray value
00378     int hmin, hmax; //the min and max grey value in the image
00379 
00380     //we asume the input image has only 256 levels of gray
00381     bool hist[256];
00382 
00383     unsigned globalOrderCounter;
00384     Pattern::Array2D<int> costImage;
00385     Pattern::Array2D<int> distImage; 
00386     Array2dScalarInt32* exportDistIm;
00387 };
00388 
00389 } // namespace Trait
00390 } // namespace Array
00391 } // namespace Core
00392 } // namespace Impala
00393 
00394 #endif

Generated on Fri Mar 19 09:30:59 2010 for ImpalaSrc by  doxygen 1.5.1