Horus Doc || C++ Reference || Class Overview   Pixels   Images   Detector   Geometry   Registry || Doxygen's quick Index  

HxWatershedSlow.h File Reference

More...

#include "HxSF.h"

Go to the source code of this file.

Functions

HxImageRep L_HXIMAGEREP HxWatershedSlow (HxImageRep im, HxSF sf, HxString linereg)
 Watershed function creates the result image by detecting the domain of the catchment basins of "im" indicated by the "immersion definition", according to the connectivity defined by "sf". More...


Detailed Description


Function Documentation

HxImageRep L_HXIMAGEREP HxWatershedSlow HxImageRep    im,
HxSF    sf,
HxString    linereg
 

Watershed function creates the result image by detecting the domain of the catchment basins of "im" indicated by the "immersion definition", according to the connectivity defined by "sf".

According to the flag "linereg" the result image will be a labeled image of the catchment basins domain or just a binary image that presents the watershed lines.

Implementation based on Vincent algorithm (PAMI) Evaluation using SDC Matlab toolbox (www.morph.com)

  • im is the input image (HxImageRep)
  • mark is the marker image (HxImageRep)
  • sf is the structuring function; default type is crossSF (HxSF)
  • linereg HxString. Possible values 'LINES' or ' REGIONS'. Default: "LINES".
Returns:
the watershed Image, ImageRep
* references: L. Vincent and P. Soille, Watersheds in digital spaces: an efficient algorithm based on immersion simulations, IEEE Transactions on Pattern Analysis and Machine Intelligence. 13:583-598, 1991.

Remarks:
this queue based implementation is based on sorted lists of pixels for color images there is no partial ordering therefore we cannot use this for color

00247 {
00248     HxSizes             sz  = im.sizes();
00249     HxImageSignature    sig = im.signature();
00250 
00251 //because there is no ordering in 3D space of color images, here we consider gray level images only
00252 //  
00253     if( sig.pixelDimensionality() == 3 )
00254     {
00255         im = HxRGB2Intensity(im);
00256         im = HxImageAsInt(im);
00257 
00258         HX_COUT << "this function is not implemented for color images!" << STD_ENDL;
00259     }
00260 
00261 
00262     int conn = sf.getConnectivity();
00263 
00264     HxImageSignature    sigOut; //default constructor, make a singature 2DINT
00265     //initialize the resltImage with -1
00266     HxImageRep      im0 = HxMakeFromValue(sigOut, sz, -1);
00267     HxImageRep      imd = HxMakeFromValue(sigOut, sz, 0);
00268 
00269     int     currentLabel    = 0;
00270     int     currentDist;
00271 
00272     HxPoint2 p;
00273     HxPoint2 p1(-1,-1);
00274     HxImgAsListIterator p1lIter, p2lIter;
00275 
00276 //fifo
00277     std::list< HxPoint2>  fifo;
00278 
00279 
00280     int     mask    = -2;   //the initial value of a threshold level
00281     int     wshed   = -3; //0;  //value of pixels belonging to the watersheds
00282     int     h, hmin,hmax;
00283     hmin = HxPixMin(im).HxScalarIntValue().x(); //what about color image?
00284     hmax = HxPixMax(im).HxScalarIntValue().x();
00285 
00286 //sort the pixels in im in the increasing order of their gray values
00287 //use HxGetPoints,  HxGetValues, and sort these lists
00288 
00289     HxValueList        vl;
00290     HxPointList        pl;
00291     HxPointListIter    plIter;
00292     HxValueListIter    vlIter;
00293 
00295 HxTimer timer;
00296 timer.start();
00297 
00298     HxGetPoints(im, std::back_inserter(pl));
00299     HxGetValues(im, pl.begin(), pl.end(), std::back_inserter(vl));
00300 
00301 
00302     HxImgAsList iml;
00303 
00304 
00305 //  printf("\nSTART imlsize=%d\n", iml.size());
00306 
00307     for(plIter = pl.begin(), vlIter = vl.begin(); 
00308         plIter!= pl.end() && vlIter!= vl.end();
00309         plIter++, vlIter++)
00310         {
00311             HxPointAndValue pv((*plIter), (*vlIter).HxScalarIntValue());
00312             iml.push_back(pv);
00313         }
00314 
00315     //this is not possible because HxValue does not implement the < operator
00316     //vl.sort();
00317 //  printf("\nimlsize=%d\n", iml.size());
00318 
00319 //  iml.sort();
00320     //sort the vector, not the list
00321     std::sort(iml.begin(), iml.end());
00322 
00323     //printf("\n");
00324 timer.stop();
00325 show(timer);
00326 timer.start();
00327 
00328 //  printf("\nimlsize=%d\n", iml.size());
00329 //  printf("hmin=%d hmax=%d\n", hmin, hmax);
00330 
00331     HxImgAsListIterator imlIter,imlIter2, startIter, startIterMin ;
00332 
00333 
00334     startIter = iml.begin();
00335     startIterMin = iml.begin();
00336 //<<1>>
00337     for(h = hmin; h<=hmax; h++)
00338     {
00339         bool hIsNotPresent = false;
00340         bool processed = false;
00341         //geodesic SKIZ of level h-1 inside level h
00342         for(imlIter=startIter; imlIter!=iml.end(); imlIter++)
00343         {
00344             if( (*imlIter).v == h)  //LT here you can speedup using a set instead of list of values
00345             {
00346                 processed = true;
00347 
00348                 p = (*imlIter).p;
00349                 //im0(p) <- mask
00350                 im0.setAt(mask, p.x(), p.y() );
00351 
00352                 //now check the vecinity of pixel p in im0
00353                 if( HxCompareNeighborPixels(im0, p, conn, GT, 0) ||  //if one of the nighbor is already labeled.
00354                     HxCompareNeighborPixels(im0, p, conn, EQ, wshed) )
00355                 {
00356                     imd.setAt(1, p.x(), p.y() );
00357                     //and put 'p' in fifo list
00358                     fifo.push_back(p);
00359                 }
00360 
00361             }
00362             else    //because the image is sorted by pixelvalues, you can speed up by breaking this loop
00363             {
00364                 if((*imlIter).v > h && !processed) //this level doesn't exist in the image, so break the main loop
00365                 {
00366                     hIsNotPresent = true;
00367                     break;
00368                 }
00369                 if(processed)
00370                 {
00371                     startIter = imlIter;
00372                     break;
00373                 }
00374             }
00375 
00376         }
00377 
00378     if(hIsNotPresent)
00379         continue;
00380 // printf("h=%3d: fifo size=%7d\n",h, fifo.size());
00381 //<<2>>
00382     currentDist=1;
00383     HxPoint2 fictionPoint(-1,-1);
00384     fifo.push_back(fictionPoint);
00385     while(true)
00386     {
00387         p = *fifo.begin();
00388         fifo.erase(fifo.begin());
00389         if ( p==fictionPoint) 
00390         {
00391             if(fifo.empty()) 
00392                 break;
00393             else
00394             {
00395                 fifo.push_back(fictionPoint);
00396                 currentDist++;
00397                 p = *fifo.begin();
00398                 fifo.erase(fifo.begin());
00399             }
00400         }
00401 //      printf("currentDist=%d\n",currentDist);
00402 //<<3>>
00403 
00404         //hey! what if point p is not correct?
00405         HxImgAsList p1l=HxGetNeighborPixels(im0, p, conn);
00406 //      if(!p1l.empty())
00407         for(p1lIter=p1l.begin(); p1lIter!=p1l.end(); p1lIter++)
00408         {
00409             p1 = (*p1lIter).p;
00410             if( (imd.getAt(p1.x(),p1.y()).HxScalarIntValue() < currentDist ) &&
00411                 ((im0.getAt(p1.x(),p1.y()).HxScalarIntValue() > 0 )          ||
00412                 (im0.getAt(p1.x(),p1.y()).HxScalarIntValue() == wshed )) )
00413             {
00414                 //i.e. p' belongs to an already labeled basin or to the watersheds
00415                 //then p get the value of p1 or 'wshed' value
00416 
00417                 if( im0.getAt(p1.x(),p1.y()).HxScalarIntValue() > 0  ) //a basin point
00418                 {
00419                     if( (im0.getAt(p.x(),p.y()).HxScalarIntValue() == mask) ||
00420                         (im0.getAt(p.x(),p.y()).HxScalarIntValue() == wshed) )
00421                         im0.setAt(im0.getAt(p1.x(),p1.y()).HxScalarIntValue(),p.x(),p.y());
00422                     else 
00423                         if( im0.getAt(p.x(),p.y()).HxScalarIntValue() != im0.getAt(p1.x(),p1.y()).HxScalarIntValue() ) //im0(p)!=im0(p')
00424                         im0.setAt(wshed,p.x(),p.y());
00425                 }
00426                 else
00427                     //i.e. p' is a wshed point
00428                     //then check the value of p
00429                     if(im0.getAt(p.x(),p.y()).HxScalarIntValue() == mask )
00430                                     im0.setAt(wshed,p.x(),p.y());
00431             }
00432             else
00433                 if( (im0.getAt(p1.x(),p1.y()).HxScalarIntValue() == mask) && 
00434                     (imd.getAt(p1.x(),p1.y()).HxScalarIntValue() == 0) )
00435                 {
00436                     imd.setAt(currentDist+1,p1.x(),p1.y());
00437                     fifo.push_back(p1);
00438                 }
00439         }
00440     }//end while(true) -> endless loop; break when fifo is empty
00441 
00442 
00443     //lt for debug
00444 //export the distance image
00445 //  HxImageRep imdE = HxImageAsByte(imd);
00446 //  HxWriteFile(imdE, "dist.tif");
00447 
00448 
00449 
00450 //<<4>>
00451 
00452       // check if new minima have been discovered
00453 
00454         bool minFound=false;
00455         for(imlIter2 = startIterMin; imlIter2 != iml.end(); imlIter2++)
00456         {
00457             if( (*imlIter2).v.x() == h)
00458             {
00459                 minFound = true;
00460                 p = (*imlIter2).p;
00461                 //the distance associated with p is reset to 0
00462                 imd.setAt(0, p.x(),p.y());
00463                 if(im0.getAt(p.x(),p.y()).HxScalarIntValue().x() == mask )
00464                 {
00465                     currentLabel++;
00466                     fifo.push_back(p);
00467                     im0.setAt(currentLabel, p.x(),p.y());
00468                     while(!fifo.empty())
00469                     {
00470                         p1 = *fifo.begin();
00471                         fifo.erase(fifo.begin());
00472                         HxPoint2 p2;
00473                         HxImgAsList p2l = HxGetNeighborPixels(im0, p1, conn);
00474                         for(p2lIter=p2l.begin(); p2lIter!=p2l.end(); p2lIter++)
00475                         {
00476                             p2 = (*p2lIter).p;
00477                             if(im0.getAt(p2.x(),p2.y()).HxScalarIntValue().x() == mask)
00478                             {
00479                                 fifo.push_back(p2);
00480                                 im0.setAt(currentLabel, p2.x(),p2.y());
00481                             }
00482                         }
00483                     }
00484                 }
00485             }
00486             else
00487             {
00488                 if(minFound)
00489                 {
00490                     startIterMin=imlIter2;
00491                     break;
00492                 }
00493             }
00494         }
00495 
00496 //  HxImageRep im0E = HxImageAsByte(im0);
00497 //  HxWriteFile(im0E, "im0before4.tif");
00498 
00499     }//end for every h level in [hmin,hmax]
00500 
00501 timer.stop();
00502 show(timer);
00503 
00504 /*************************/
00505 //end lucVincent algorithm, now make the tesselation image
00506 /************************/
00507 
00508 //implement this with neighbourhood operators
00509 
00510 timer.start();
00511 
00512     HxImageRep      imres = im0;
00513 
00514 
00515     pl.clear();
00516     vl.clear();
00517 
00518     //take care HxGetPoints doesn't include the zero pixels!
00519     //but here I changed whsed value from 0 to -3
00520     HxGetPoints(im0, std::back_inserter(pl));
00521     HxGetValues(im0, pl.begin(), pl.end(), std::back_inserter(vl));
00522 
00523 //  printf("plsize=%d, vlsize=%d\n",pl.size(), vl.size());
00524  STD_COUT << "imres : " << imres.signature() << ", sizes: " << imres.sizes() << STD_ENDL;
00525 
00526     for(plIter = pl.begin(), vlIter = vl.begin(); 
00527         plIter!= pl.end() && vlIter!= vl.end();
00528         plIter++, vlIter++)
00529         {
00530             HxPoint2 pc = (*plIter);
00531             int v = (*vlIter).HxScalarIntValue().x();
00532 
00533             if( v == wshed)
00534             {
00535                 //leon it is better to give to wshed pixel the label of 
00536                 //the smallest label among neighbors - this is just to be consistent
00537                 HxImgAsList p0l=HxGetNeighborPixels(im0, pc, conn);
00538 
00539                 int maxValNg = 0;
00540                 for(p1lIter=p0l.begin(); p1lIter!=p0l.end(); p1lIter++)
00541                 {
00542                     if(( *p1lIter).v.x() > maxValNg)
00543                         maxValNg = (*p1lIter).v.x();
00544                 }
00545 
00546 STD_COUT << "    in loop before setAt" << STD_ENDL;
00547                 if(maxValNg > 0 )
00548                     {
00549 STD_COUT << "values : " << maxValNg << "," << pc.x() << "," << pc.y() << STD_ENDL;
00550                         HxValue maxValNgV(maxValNg);
00551                         int x = pc.x();
00552                         int y = pc.y();
00553 STD_COUT << "values local : " << maxValNgV << "," << x << "," << y << STD_ENDL;
00554                         HxValue orgV = imres.getAt(x, y); 
00555 STD_COUT << "org value : " << orgV << STD_ENDL;
00556                         //imres.setAt(maxValNg, pc.x(),pc.y());
00557                         //imres.setAt(maxValNgV, x, y);
00558                         imres.setAt(orgV, x, y);
00559                     }
00560 STD_COUT << "    in loop after setAt" << STD_ENDL;
00561             
00562             }
00563         }
00564 
00565 
00566 
00567 
00568 
00569     im0 = imres;
00570 
00571 //to separate catchment basines
00572     if(linereg=="LINES"){
00573 
00574         //im0 =  HxLWshed(im0,conn,wshed);
00575         HxTagList tags;
00576         HxAddTag(tags, "conn", conn);
00577         HxAddTag(tags, "wshedval", wshed);
00578         im0 = im0.neighbourhoodOp("lwshed", tags);
00579 
00580 //this can be implemented iwth LUT, some  unary pixel operation anyway...
00581         pl.clear();
00582         vl.clear();
00583         HxGetPoints(im0, std::back_inserter(pl));
00584         HxGetValues(im0, pl.begin(), pl.end(), std::back_inserter(vl));
00585 
00586         for(plIter = pl.begin(), vlIter = vl.begin(); 
00587             plIter!= pl.end() && vlIter!= vl.end();
00588             plIter++, vlIter++)
00589             {
00590                 HxPoint2 pc = (*plIter);
00591                 int v = (*vlIter).HxScalarIntValue().x();
00592                 if(v == wshed )
00593                         imres.setAt(255, pc.x(),pc.y());
00594                 else
00595                         imres.setAt(0, pc.x(),pc.y());
00596             }
00597 
00598         im0=imres;
00599     
00600     }
00601 
00602     if(linereg=="REGIONS"){
00603 
00604 //implemented with neighbourhood operator
00605         //im0 =  HxLWshed(im0,conn,wshed);
00606         HxTagList tags;
00607         HxAddTag(tags, "conn", conn);
00608         HxAddTag(tags, "wshedval", wshed);
00609         im0 = im0.neighbourhoodOp("lwshed", tags);
00610 
00611 
00612         pl.clear();
00613         vl.clear();
00614         HxGetPoints(im0, std::back_inserter(pl));
00615         HxGetValues(im0, pl.begin(), pl.end(), std::back_inserter(vl));
00616 
00617         for(plIter = pl.begin(), vlIter = vl.begin(); 
00618             plIter!= pl.end() && vlIter!= vl.end();
00619             plIter++, vlIter++)
00620             {
00621                 HxPoint2 pc = (*plIter);
00622                 int v = (*vlIter).HxScalarIntValue().x();
00623                 if(v == wshed )
00624                         imres.setAt(0, pc.x(),pc.y());
00625             }
00626 
00627         im0=imres;
00628     
00629     }
00630 
00631 timer.stop();
00632 show(timer);
00633 
00634     return im0;
00635 }


Generated on Tue Feb 3 14:18:51 2004 for C++Reference by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001