#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 } |