#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... | |
|
||||||||||||||||
|
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)
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 }
|
1.2.12 written by Dimitri van Heesch,
© 1997-2001