00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020 #include<ImLib3D/VoxelCoding.hpp>
00021 #include<ImLib3D/Arithmetic.hpp>
00022 #include<ImLib3D/Display.hpp>
00023 #include<ImLib3D/ConvenienceProcessors.hpp>
00024
00025 void
00026 IP3D::ShortestPathExtraction(const Mask3D &shape,const Vect3Di &start,const Vect3Di &end,vector<Vect3Di> &path,
00027 Mask3D *pres,StructureElement *psel,
00028 const LabelImage3D *pssCode0,
00029 ShortestPathExtractionHelpers::StopCBType stopCB)
00030 {
00031
00032 const LabelImage3D *pssCode=pssCode0;
00033 if(!pssCode)
00034 {
00035 LabelImage3D *tmp=new LabelImage3D();
00036 IP3D::SSCode(shape,end,1,2,3,*tmp,&start);
00037 pssCode=tmp;
00038 }
00039 const LabelImage3D &ssCode=*pssCode;
00040
00041 path.push_back(start);
00042 vector<Vect3Di> sel;
00043 if(!psel)
00044 {
00046 sel.push_back(Vect3Di(-1,0,0));
00047 sel.push_back(Vect3Di( 1,0,0));
00048 sel.push_back(Vect3Di(0,-1,0));
00049 sel.push_back(Vect3Di(0, 1,0));
00050 sel.push_back(Vect3Di(0,0,-1));
00051 sel.push_back(Vect3Di(0,0, 1));
00052 }
00053 else
00054 {
00055 for(uint i=0;i<psel->size();i++){sel.push_back(psel->GetPoint(i));}
00056 }
00057
00058 for(uint it=0;;it++)
00059 {
00060 Vect3Di p=path.back();
00061 int smin=-1;
00062 int imin=-1;
00063 for(uint i=0;i<sel.size();i++)
00064 {
00065 Vect3Di npos=p+sel[i];
00066 if(ssCode.IsInside(npos) && ssCode(npos)>=0 && (imin<0 || ssCode(npos)<smin))
00067 {
00068 smin=ssCode(npos);
00069 imin=i;
00070 }
00071 }
00072 p=p+sel[imin];
00073 path.push_back(p);
00074 if(stopCB.first && stopCB.first(stopCB.second,p)){p.Show("CShortestPathExtraction:stoping at:","\n");break;}
00075 if(smin==0){break;}
00076 }
00077
00078 if(!pssCode0){delete pssCode;}
00079 }
00080 void
00081 IP3D::VoxelCode(const Mask3D &shape,const Mask3D &seeds,int m0,int m1,int m2,LabelImage3D& res,const Vect3Di *stopPoint)
00082 {
00083 int metric[3]={m0,m1,m2};
00084 Mask3D s=seeds;
00085 s.Normalize();
00086 s.Invert();
00087 LabelImage3D codes;
00088 codes=s;
00089 int inf=(codes.Width()+codes.Height()+codes.Depth())*10;
00090 codes*=inf;
00091
00092
00093
00094 StructureElement fNeighbors(MORPHO_Cross7);
00095 StructureElement planar19(MORPHO_Planar19);
00096 StructureElement cubic27(MORPHO_Cubic27);
00097 vector<Vect3Di> ePoints;
00098 for(uint i=0;i<planar19.size();i++)
00099 {
00100 if(fNeighbors.FindPoint(planar19[i])<0)
00101 {
00102 ePoints.push_back(planar19[i]);
00103 }
00104 }
00105 vector<Vect3Di> vPoints;
00106 for(uint i=0;i<cubic27.size();i++)
00107 {
00108 if(planar19.FindPoint(cubic27[i])<0)
00109 {
00110 vPoints.push_back(cubic27[i]);
00111 }
00112 }
00113 StructureElement eNeighbors(ePoints);
00114 StructureElement vNeighbors(vPoints);
00115
00116 fNeighbors.RemoveCenter();
00117
00118
00119
00120 StructureElement *neighbors[3];
00121 neighbors[0]=&fNeighbors;
00122 neighbors[1]=&eNeighbors;
00123 neighbors[2]=&vNeighbors;
00124
00125
00126 vector<Vect3Di> changedPts;
00127 changedPts.reserve(shape.GetNVoxels());
00128
00129 for(LabelImage3D::iteratorXYZ p=codes.begin();p!=codes.end();++p)
00130 {
00131 if(*p!=inf){changedPts.push_back(p.Pos());}
00132 }
00133
00134
00135
00136 LabelImage3D changedIm(shape.Size());
00137 changedIm.Fill(-1);
00138
00139
00140 for(int it=0;;it++)
00141 {
00142 bool changed=false;
00143 vector<Vect3Di> newChangedPts;
00144 newChangedPts.reserve(shape.GetNVoxels());
00145 LabelImage3D newCodes=codes;
00146 printf("it:%3d changedPts:%4d\n",it,changedPts.size());
00147
00148 for(uint pt=0;pt<changedPts.size();pt++)
00149 {
00150 const Vect3Di &pos=changedPts[pt];
00151
00152 for(int n=0;n<3;n++)
00153 {
00154
00155 for(uint i=0;i<neighbors[n]->size();i++)
00156 {
00157 Vect3Di npos=pos+neighbors[n]->GetPoint(i);
00158 int nval=codes(pos)+metric[n];
00159 if(shape.IsInside(npos) && shape(npos) && nval<newCodes(npos))
00160 {
00161 newCodes(npos)=nval;
00162 if(changedIm(npos)!=it){changedIm(npos)=it;newChangedPts.push_back(npos);}
00163 changed=true;
00164 }
00165 }
00166 }
00167 }
00168 codes=newCodes;
00169 if(0)
00170 {
00171 Mask3D changedDisp;
00172 IP3D::SimpleThresholds2(changedIm,it,it,changedDisp);
00173 ImLib3DDisplay::Show(changedDisp);
00174 ImLib3DDisplay::Show(codes);
00175 }
00176
00177 if(stopPoint && changedIm(*stopPoint)!=-1){break;}
00178 if(!changed){break;}
00179 changedPts=newChangedPts;
00180 }
00181
00182 for(LabelImage3D::iteratorXYZ p=codes.begin();p!=codes.end();++p)
00183 {
00184 if(*p==inf){*p=-1;}
00185 }
00186 res=codes;
00187 }
00188
00189 PathGraph::Path::Path(PathGraph::Node *_first,PathGraph::Node *_last,const vector<Vect3Di> &_points):
00190 first(_first),last(_last),points(_points)
00191 {
00192 first->point=points[0];
00193 last ->point=points.back();
00194 first->paths.push_back(this);
00195 last ->paths.push_back(this);
00196 }
00197 void
00198 SkeletonExtraction::MedPathFind::ExtractPath(SkeletonExtraction *se)
00199 {
00200 path.clear();
00201 Vect3Di start=cpath[0]->MedialPoint(cpath[0]->center);
00202 IP3D::ShortestPathExtraction(Mask3D(),start,Vect3Di(),path,NULL,NULL,&se->ssCode,
00203 IP3D::ShortestPathExtractionHelpers::StopCBType(&SkeletonExtraction::SpeStopCB,se));
00204 if(se->clustersIma(path.back())->stop>=0)
00205 {
00206 path.back().Show("ExtractPath: found stop at:","\n");
00207 id2=se->clustersIma(path.back())->stop;
00208 }
00209 else{ path.back().Show("ExtractPath: no stop at:","\n");}
00210 if(cpath.size()!=1){ThrowError("MedPathFind::ExtractPath Should only be start cluster in cpath");}
00211 for(uint i=1;i<path.size();i++)
00212 {
00213 cpath.push_back(se->clustersIma(path[i]));
00214 }
00215 }
00216
00217 void
00218 SkeletonExtraction::ExtractAllMedPaths(vector<MedPathFind> &medPaths)
00219 {
00220
00221 medPaths.clear();
00222 for(uint i=0;i<clusters.size();i++){clusters[i]->stop=-1;}
00223
00224 for(uint i=0;i<clusters.size();i++)
00225 {
00226 if(clusters[i]->isLM){medPaths.push_back(MedPathFind(clusters[i]));}
00227 }
00228 sort(medPaths.begin(),medPaths.end());
00229 reverse(medPaths.begin(),medPaths.end());
00230
00231 for(uint mi=0;mi<medPaths.size();mi++)
00232 {
00233
00234 printf("medpath %d:startcluster :%x val:%d\n",mi,(uint)medPaths[mi].cpath[0],medPaths[mi].cpath[0]->value);
00235 medPaths[mi].id=mi;
00236 medPaths[mi].ExtractPath(this);
00237 medPaths[mi].path[0].Show("first point:","\n");
00238
00239 for(uint pti=0;pti<medPaths[mi].path.size();pti++)
00240 {
00241 Vect3Di pt=medPaths[mi].path[pti];
00242 CodeCluster *c=clustersIma(pt);
00243 Vect3Di mp=c->MedialPoint(pt);
00244 printf("medpath % 3d : cluster:%x pti:% 3d ",mi,(uint)c,pti);
00245 pt.Show("pt:"," ");
00246 mp.Show("mp:","\n");
00247
00248
00249 vector<CodeCluster *> s;
00250 c->GetSuccessors(s);
00251 for(uint j=0;j<s.size();j++)
00252 {
00253 if(pti+1<medPaths[mi].path.size() &&
00254 s[j]!=clustersIma(medPaths[mi].path[pti+1]))
00255 {
00256 printf("branches %d\n",medPaths.size());
00257 medPaths.push_back(MedPathFind(s[j]));
00258 medPaths.back().id1=mi;
00259 medPaths.back().parentCluster=c;
00260 }
00261 }
00262 medPaths[mi].path[pti]=mp;
00263 c->stop=mi;
00264 }
00265 }
00266 }
00267 void
00268 SkeletonExtraction::PathGraphFromMedPaths(vector<MedPathFind> &medPaths,PathGraph &pathGraph)
00269 {
00270
00271 ssCode.WriteToFile("ssCode.im3D");
00272
00273 {
00274 Image3Df disp(clustersIma.Size());disp.Fill(-1);
00275 for(uint i=0;i<medPaths.size();i++)
00276 {
00277 MedPathFind &mpf=medPaths[i];
00278 for(uint j=0;j<mpf.path.size();j++)
00279 {
00280 disp(mpf.path[j])=i+j*.5/mpf.path.size();
00281 }
00282 }
00283 disp.WriteToFile("medpaths.im3D");
00284 }
00285
00286 for(uint i=0;i<medPaths.size();i++)
00287 {
00288 MedPathFind &mpf=medPaths[i];
00289 if(mpf.id1>=0)
00290 {
00291 mpf.cpath.insert(mpf.cpath.begin(),mpf.parentCluster);
00292 mpf. path.insert(mpf. path.begin(),mpf.parentCluster->MedialPoint(mpf.path[0]));
00293 }
00294 }
00295
00296
00297 for(uint i=0;i<medPaths.size();i++)
00298 {
00299 MedPathFind &mpf=medPaths[i];
00300 mpf.branches.assign(mpf.path.size(),vector<int>());
00301 }
00302
00303 for(uint i=0;i<medPaths.size();i++)
00304 {
00305 MedPathFind &mpf=medPaths[i];
00306 if(mpf.id1>=0)
00307 {
00308 MedPathFind &other=medPaths[mpf.id1];
00309 other.branches[other.FindCluster(mpf.cpath[0])].push_back(i);
00310 }
00311 if(mpf.id2>=0)
00312 {
00313 MedPathFind &other=medPaths[mpf.id2];
00314 other.branches[other.FindCluster(mpf.cpath.back())].push_back(i);
00315 }
00316 }
00317
00318 {
00319 for(uint i=0;i<medPaths.size();i++)
00320 {
00321 MedPathFind &mpf=medPaths[i];
00322 printf("medpath %3d : id1:%3d id2:%3d\n",i,mpf.id1,mpf.id2);
00323 for(uint j=0;j<mpf.path.size();j++)
00324 {
00325 printf("cluster %x, ",(uint)mpf.cpath[j]);
00326 mpf.path[j].Show("pt:"," ");
00327 if(mpf.branches[j].size()>0)
00328 {
00329 printf("branches (%d):",mpf.branches[j].size());
00330 for(uint k=0;k<mpf.branches[j].size();k++){printf("%d ",mpf.branches[j][k]);}
00331 }
00332 printf("\n");
00333 }
00334 }
00335 }
00336
00337 for(uint i=0;i<medPaths.size();i++)
00338 {
00339 MedPathFind &mpf=medPaths[i];
00340 mpf.branchNodes.assign(mpf.path.size(),NULL);
00341 if(mpf.id1<0){mpf.branchNodes[0]=pathGraph.AddNode();}
00342 for(uint j=1;j<mpf.path.size()-1;j++)
00343 {
00344 if(mpf.branches[j].size()>0)
00345 {
00346 mpf.branchNodes[j]=pathGraph.AddNode();
00347 }
00348 }
00349 if(mpf.id2<0){mpf.branchNodes[mpf.path.size()-1]=pathGraph.AddNode();}
00350 }
00351
00352 bool changed=false;
00353 while(!changed)
00354 {
00355 printf("merging\n");
00356 for(uint i=0;i<medPaths.size();i++)
00357 {
00358 MedPathFind &mpf=medPaths[i];
00359 if(mpf.id1>=0 && !mpf.branchNodes[0])
00360 {
00361 MedPathFind &other=medPaths[mpf.id1];
00362 int opos=other.FindCluster(mpf.cpath[0]);
00363 mpf.branchNodes[0]=other.branchNodes[opos];
00364 changed=true;
00365 }
00366 int l=mpf.path.size()-1;
00367 if(mpf.id2>=0 && !mpf.branchNodes[l])
00368 {
00369 MedPathFind &other=medPaths[mpf.id2];
00370 int opos=other.FindCluster(mpf.cpath[l]);
00371 mpf.branchNodes[l]=other.branchNodes[opos];
00372 changed=true;
00373 }
00374 }
00375 }
00376
00377 for(uint i=0;i<medPaths.size();i++)
00378 {
00379 MedPathFind &mpf=medPaths[i];
00380 PathGraph::Node *first=mpf.branchNodes[0];
00381 int j0=0;
00382 for(uint j=1;j<mpf.path.size();j++)
00383 {
00384 PathGraph::Node *node=mpf.branchNodes[j];
00385 if(node)
00386 {
00387 pathGraph.AddPath(first,node,vector<Vect3Di>(mpf.path.begin()+j0,mpf.path.begin()+j+1));
00388 j0=j;
00389 first=node;
00390 }
00391 }
00392 }
00393
00394 for(uint i=0;i<pathGraph.paths.size();i++)
00395 {
00396 pathGraph.paths[i]->points[0] =pathGraph.paths[i]->first->point;
00397 pathGraph.paths[i]->points.back()=pathGraph.paths[i]->last ->point;
00398 }
00399
00400 {
00401 Image3Df disp(clustersIma.Size());disp.Fill(-1);
00402 for(uint i=0;i<pathGraph.paths.size();i++)
00403 {
00404 vector<Vect3Di> &pts=pathGraph.paths[i]->points;
00405 for(uint j=0;j<pts.size();j++)
00406 {
00407 disp(pts[j])=i+j*.5/pts.size();
00408 }
00409 }
00410 disp.WriteToFile("paths.im3D");
00411 }
00412
00413 }
00414
00415 void
00416 SkeletonExtraction::ExtractPaths(PathGraph &pathGraph)
00417 {
00418 vector<MedPathFind> medPaths;
00419 ExtractAllMedPaths(medPaths);
00420 PathGraphFromMedPaths(medPaths,pathGraph);
00421
00422 for(uint i=0;i<pathGraph.paths.size();i++)
00423 {
00424 vector<Vect3Di> &pts=pathGraph.paths[i]->points;
00425 for(uint j=1;j<pts.size();j++)
00426 {
00427 Vect3Di dd=pts[j-1]-pts[j];
00428 if(abs(dd.x)>1 || abs(dd.y)>1 || abs(dd.z)>1)
00429 {
00430 vector<Vect3Di> inspts;
00431 ExtractLinkingMedPath(shape,pts[j-1],pts[j],inspts);
00432 if(inspts.size()>2)
00433 {
00434 pts.insert(pts.begin()+j,inspts.begin()+1,inspts.end()-1);
00435 j+=inspts.size()-2;
00436 }
00437 }
00438 }
00439 }
00440 }
00441
00442 void
00443 SkeletonExtraction::CreateClusters()
00444 {
00445 clusters.clear();
00446 clustersIma.Resize(ssCode.Size());
00447 clustersIma.Fill(NULL);
00448
00449 LabelImage3D labels;
00450 int bg=-1;
00451 IP3D::ConnectedComponentLabelling(ssCode,StructureElement(MORPHO_Cubic27),labels,&bg);
00452
00453
00454 map<int,CodeCluster *> label2cluster;
00455 for(LabelImage3D::iteratorXYZ p=labels.begin();p!=labels.end();++p)
00456 {
00457 if(ssCode(p.Pos())<0){continue;}
00458 int label=*p;
00459 CodeCluster *cluster;
00460
00461 if(label2cluster.find(label)==label2cluster.end())
00462 {
00463 printf("new cluster:label %d value:%d\n",label,ssCode(p.Pos()));
00464 cluster=new CodeCluster(ssCode(p.Pos()));
00465 label2cluster[label]=cluster;
00466 clusters.push_back(cluster);
00467 }
00468 else{cluster=label2cluster[label];}
00469
00470 clustersIma(p.Pos())=cluster;
00471 cluster->points.push_back(p.Pos());
00472 }
00473
00474 }
00475 void
00476 SkeletonExtraction::InitClusters()
00477 {
00478 for(uint i=0;i<clusters.size();i++)
00479 {
00480 clusters[i]->Init();
00481 }
00482 for(uint i=0;i<clusters.size();i++)
00483 {
00484 clusters[i]->FindNeighbors(clustersIma);
00485 }
00486 for(uint i=0;i<clusters.size();i++)
00487 {
00488 clusters[i]->FindType();
00489 }
00490 for(uint i=0;i<clusters.size();i++)
00491 {
00492 clusters[i]->FindMedialPoints(bsCode);
00493 }
00494 }
00495 SkeletonExtraction::SkeletonExtraction(const Mask3D &_shape,const Vect3Di *psourcePoint):shape(_shape)
00496 {
00497 Vect3Di sourcePoint(-1,0,0);
00498 if(psourcePoint){sourcePoint=*psourcePoint;}
00499 else
00500 {
00501
00502 for(Mask3D::const_iteratorXYZ p=shape.begin();p!=shape.end();++p){if(*p){sourcePoint=p.Pos();break;}}
00503 sourcePoint.Show("SkeletonExtraction: p0:","\n");
00504 if(sourcePoint.x<0){ThrowError("SkeletonExtraction::SkeletonExtraction shape is empty");}
00505 LabelImage3D ss0;
00506 IP3D::SSCode(shape,sourcePoint,1,2,3,ss0);
00507 Vect3Di dud;
00508 int dud0,dud1;
00509 IP3D::FindMinMax(ss0,dud0,dud1,&dud,&sourcePoint);
00510 sourcePoint.Show("SkeletonExtraction: auto sourcePoint:","\n");
00511 }
00512 IP3D::SSCode(shape,sourcePoint,1,2,3,ssCode);
00513 IP3D::BSCode(shape,1,2,3,bsCode);
00514 CreateClusters();
00515 InitClusters();
00516 }
00517 void
00518 SkeletonExtraction::ExtractAll(const Mask3D &shape,PathGraph &pathGraph)
00519 {
00520 LabelImage3D components;
00521 IP3D::ConnectedComponentLabelling(shape,StructureElement(MORPHO_Cross7),components);
00522 int cmin,cmax;
00523 IP3D::FindMinMax(components,cmin,cmax);
00524
00525 for(int i=1;i<=cmax;i++)
00526 {
00527 printf("SkeletonExtraction::ExtractAll indep component %d out of %d\n",i,cmax);
00528 Mask3D simpleShape;
00529 IP3D::SimpleThresholds2(components,i,i,simpleShape);
00530 SkeletonExtraction skel(simpleShape);
00531 skel.ExtractPaths(pathGraph);
00532 }
00533 }
00534 RectZone3Di
00535 PathGraph::BoundingBox() const
00536 {
00537 Vect3Di p0=paths[0]->points[0],p1=p0;
00538 for(uint i=0;i<paths.size();i++)
00539 {
00540 for(uint j=0;j<paths[i]->points.size();j++)
00541 {
00542 p0=min(p0,paths[i]->points[j]);
00543 p1=max(p1,paths[i]->points[j]);
00544 }
00545 }
00546 return RectZone3Di(p0,p1);
00547 }
00548 void
00549 SkeletonExtraction::DrawPathGraph(const PathGraph &pathGraph,Mask3D &res)
00550 {
00551 Vect3Di p0(0,0,0);
00552 if(res.Size()==Size3D(0,0,0))
00553 {
00554 RectZone3Di box=pathGraph.BoundingBox();
00555 res.Resize(Size3D(box.Width(),box.Height(),box.Depth()));
00556 p0=box.GetP0();
00557 res.properties.iCenter=new Vect3Di(p0);
00558 }
00559 for(uint i=0;i<pathGraph.paths.size();i++)
00560 {
00561 for(uint j=0;j<pathGraph.paths[i]->points.size();j++)
00562 {
00563 if(!res.IsInside(pathGraph.paths[i]->points[j]-p0))
00564 {
00565 ThrowError("SkeletonExtraction::DrawPathGraph point outside of image");
00566 }
00567 res(pathGraph.paths[i]->points[j]-p0)=1;
00568 }
00569 }
00570 }
00571 void
00572 SkeletonExtraction::ExtractLinkingMedPath(const Mask3D &shape,const Vect3Di &start,const Vect3Di &end,vector<Vect3Di> &res)
00573 {
00574 if(start==end){res.push_back(start);res.push_back(end);return;}
00575 if(0)
00576 {
00577 int jmx=0,dmx=abs(end(0)-start(0));
00578 for(int j=1;j<3;j++)
00579 {
00580 int dd=abs(end(j)-start(j));
00581 if(dd>dmx){dmx=dd;jmx=j;}
00582 }
00583 int j=jmx;
00584 Vect3Di p0=start,p1=end;
00585 if(p1(j)<p0(j)){p1=start;p0=end;}
00586 for(int i=p0(j);i<=p1(j);i++)
00587 {
00588 Vect3Df p=(Vect3Df)p0+((i-p0(j))/(float)(p1(j)-p0(j)))*((Vect3Df)(p1-p0));
00589 res.push_back(floor(p+Vect3Df(.5,.5,.5)));
00590 }
00591 }
00592
00593
00594 res.clear();
00595 IP3D::ShortestPathExtraction(shape,start,end,res);
00596
00597 }