#include #include #include #include #include #include #include #include #include using namespace std; #include #include #include using namespace cv; const Point2d origin(0, 0); const Scalar White = CV_RGB (255, 255, 255); const Scalar Black = CV_RGB (0, 0, 0); const Scalar Red = CV_RGB (255, 0, 0); const Scalar Lime = CV_RGB (0, 255, 0); const Scalar Green = CV_RGB (0, 128, 0); const Scalar Blue = CV_RGB (0, 0, 255); const Scalar Yellow = CV_RGB (255, 255, 0); const Scalar Orange = CV_RGB (255, 128, 0); const Scalar Magenta = CV_RGB (255, 0, 255); const Scalar Cyan = CV_RGB (0, 255, 255); const Scalar Olive = CV_RGB (128,128,0); const Scalar Gray = CV_RGB (128,128,128); const Scalar Silver = CV_RGB (192,192,192); const Scalar Maroon = CV_RGB (128,0,0); const Scalar Purple = CV_RGB (128,0,128); const Scalar Teal = CV_RGB (0,128,128); const Scalar Navy = CV_RGB (0,0,128); const Scalar Brown = CV_RGB (165,42,42); const Scalar Coral = CV_RGB (255,127,80); const Scalar Salmon = CV_RGB (250,128,114); const Scalar Khaki = CV_RGB (240,230,140); const Scalar Indigo = CV_RGB (75,0,130); const Scalar Plum = CV_RGB (221,160,221); const Scalar orchid = CV_RGB (218,112,214); const Scalar beige = CV_RGB (245,245,220); const Scalar peru = CV_RGB (205,133,63); const Scalar sienna = CV_RGB (160,82,45); const Scalar lavender = CV_RGB (230,230,250); const Scalar mocassin = CV_RGB (255,228,181); const Scalar honeydew = CV_RGB (240,255,240); const Scalar ivory = CV_RGB (255,255,240); const Scalar azure = CV_RGB (240,255,255); const Scalar crimson = CV_RGB (220,20,60); const Scalar gold = CV_RGB (255,215,0); const Scalar sky_blue = CV_RGB (135,206,235); const Scalar aqua_marine = CV_RGB (127,255,212); const Scalar bisque = CV_RGB (255,228,196); const Scalar peach_puff = CV_RGB (255,218,185); const Scalar corn_silk = CV_RGB (255,248,220); const Scalar wheat = CV_RGB (245,222,179); const Scalar violet = CV_RGB (238,130,238); const Scalar lawn_green = CV_RGB (124,252,0); vector Colors = { Lime, Orange, Gray, Cyan, Yellow, Red, Green, Olive, Magenta, Teal, Silver, Coral, Salmon, Khaki, Plum, orchid, beige, lavender, mocassin, honeydew, ivory, azure, crimson, gold, sky_blue, aqua_marine, bisque, peach_puff, corn_silk, wheat, violet, lawn_green}; // dark colors: Blue, Black, Brown, Maroon, Navy, Purple, Indigo, peru, sienna, #include "boost/graph/adjacency_list.hpp" #include "boost/graph/topological_sort.hpp" #include #include #include #include using namespace boost; #include #include #include #include #include using namespace CGAL; class Node { public: int index; // index of triangle in FaceHandles int uplink; double birth; int height; int bar; // index of the region containing the triangle of this node vector live; // indices of live triangles from Tree of this node //int weight; Node () { index = 0; // index in FaceHandles: 0 means external boundary uplink = 0; // index of the parent node in FaceHandles birth = 0; // height = 1; // no nodes below the new node bar = -1; live.clear(); } }; typedef Exact_predicates_inexact_constructions_kernel K; typedef Triangulation_vertex_base_with_info_2 VB; typedef Triangulation_face_base_with_info_2 FB; typedef Triangulation_data_structure_2 TDS; typedef Delaunay_triangulation_2 DT; typedef K::Point_2 P2; typedef DT::Edge DE; typedef DT::Face DF; typedef DT::Vertex_handle VH; typedef DT::Face_handle FH; typedef DT::Vertex_iterator VI; typedef DT::Edge_iterator EI; typedef DT::Finite_vertices_iterator FVI; typedef DT::Finite_edges_iterator FEI; typedef DT::All_faces_iterator AFI; typedef DT::Finite_faces_iterator FFI; pair Vertices (DE const& e) { // Edges are a triplet; (face, i, j). Get the i-th (either 0, 1, or 2) vertex of a face using vertex(i) VH v1 = e.first -> vertex ( (e.second + 1) % 3 ); VH v2 = e.first -> vertex ( (e.second + 2) % 3 ); return make_pair (v1, v2); } pair Faces (DE const& e) { //if you have an edge e, then e.first and e.first.neighbor( e.second ) are the two incident facets. FH f1 = e.first; FH f2 = e.first->neighbor( e.second ); return make_pair (f1, f2); }// double SquaredLength (DE const& e) { VH v1 = Vertices(e).first; VH v2 = Vertices(e).second; return squared_distance( v1->point(), v2->point() ); } class Edge { public: DE edge; VH end1, end2; int face1, face2; double length; bool boundary; Edge () {} Edge (DE const& e) { edge = e; pair ends = Vertices(e); end1 = ends.first; end2 = ends.second; pair faces = Faces(e); FH face = faces.first; face1 = face->info().index; face = faces.second; face2 = face->info().index; length = sqrt( SquaredLength(e) ); boundary = false; //UpdateLength(); } void UpdateLength() { length = sqrt( squared_distance( end1->point(), end1->point() ) ); } }; bool DecreasingLengths (Edge const& e1, Edge const& e2) { return e2.length < e1.length; } bool IncreasingLengths (Edge const& e1, Edge const& e2) { return e2.length > e1.length; } void WriteImage (String const& name, Mat const& image) { try{ imwrite( name, image ); } catch (runtime_error& ex) { fprintf(stderr, "Exception converting to PNG: %s\n", ex.what()); } } void LoadCloud (int SizeCloud, String const& FileName, vector& PointCloud) { ifstream input( FileName ); string line_data; char comma; while ( getline(input, line_data) ) { stringstream line_stream (line_data); double x,y; if (line_stream >> x >> comma >> y) PointCloud.push_back( P2(x,y) ); } } void load_clouds( String const& InputFolder, vectorconst& file_names, String const& add_ext, vector< vector>& clouds ) { clouds.resize( file_names.size() ); for (size_t f=0; f> x >> y) clouds[f].push_back( P2(x,y) ); } input.close(); } } Point2i ScaleShift(P2 p, double scale, Point2i shift) { return Point2i ( int( scale * p.x() + shift.x ), int( scale * p.y() + shift.y ) ); } Point2i ScaleShift(Point2d p, double scale, Point2i shift) { return Point2i ( int( scale * p.x + shift.x ), int( scale * p.y + shift.y ) ); } void draw_cloud( vectorconst& cloud, int MaxIndex, double scale, Point2d shift, Mat& image ) { for (size_t i=0; ipoint(), scale, shift); circle( image, p, 2, Red, -1); String s = "("+to_string( (int)it->point().x() )+","+to_string( (int)it->point().y() )+")"; putText(image, s, p, FONT_HERSHEY_PLAIN, 1.0, Red); } } void DrawEdge ( P2 v1, P2 v2, double scale, Point2d shift, CvScalar c, Mat& image ) { line( image, ScaleShift( v1, scale, shift), ScaleShift( v2, scale, shift), c, 1); } void DrawEdges ( DT const& Del, double scale, Point2d shift, Mat& image ) { for( FEI it = Del.finite_edges_begin(); it != Del.finite_edges_end(); ++it) DrawEdge ( Vertices(*it).first->point(), Vertices(*it).second->point(), scale, shift, Blue, image); } String Round (double v) { char b[9]; sprintf( b, "%.1f", v ); return string(b); } void DrawFaces ( DT const& Del, double scale, Point2d shift, Mat& image ) { for(FFI iF = Del.finite_faces_begin(); iF != Del.finite_faces_end(); ++iF) { P2 p0 = iF->vertex(0)->point(); P2 p1 = iF->vertex(1)->point(); P2 p2 = iF->vertex(2)->point(); P2 p ( (p0.x()+p1.x()+p2.x())/3, (p0.y()+p1.y()+p2.y())/3 ); String s = to_string( iF->info().index ) + "," + Round( iF->info().birth ); putText(image, s, ScaleShift(p , scale, shift), FONT_HERSHEY_PLAIN, 1.0, Black); //P2 p01 ( (p0.x()+p1.x())/2, (p0.y()+p1.y())/2 ); //putText(image, to_string(iF->info().index), ScaleShift(p , scale, shift), FONT_HERSHEY_PLAIN, 1.0, Black); } } void DrawTriangulation (DT const& Del, double scale, Point2d shift, Mat& image) { //DrawFaces( Del, scale, shift, image ); DrawEdges( Del, scale, shift, image ); //DrawVertices( Del, scale, shift, image ); } bool FindCloudBox ( vectorconst& PointCloud, pair& CloudBox ) { CloudBox.first = Point2d (1e+64, 1e+64); CloudBox.second = Point2d (-1e+64, -1e+64); for (size_t i=0; i CloudBox.second.x) CloudBox.second.x = PointCloud[i].x(); if (PointCloud[i].y() < CloudBox.first.y) CloudBox.first.y = PointCloud[i].y(); if (PointCloud[i].y() > CloudBox.second.y) CloudBox.second.y = PointCloud[i].y(); } return true; } bool FindCloudBox ( vector< pair >const& PointCloud, pair& CloudBox ) { CloudBox.first = Point2d (1e+64, 1e+64); CloudBox.second = Point2d (-1e+64, -1e+64); for (size_t i=0; i CloudBox.second.x) CloudBox.second.x = PointCloud[i].second.x(); if (PointCloud[i].second.y() < CloudBox.first.y) CloudBox.first.y = PointCloud[i].second.y(); if (PointCloud[i].second.y() > CloudBox.second.y) CloudBox.second.y = PointCloud[i].second.y(); } return true; } int FindRoot (int node, vectorconst& FaceHandles) { int next = FaceHandles[node]->info().uplink; if (next == node) return node; return FindRoot( next, FaceHandles ); } bool is_acute (K::Triangle_2 const& Triangle, double& radius) { P2 p = circumcenter( Triangle.vertex(0), Triangle.vertex(1), Triangle.vertex(2) ); //radius = distance ( p, Triangle.vertex(0) ); radius = sqrt( squared_distance( p, Triangle.vertex(0) ) ); if ( Triangle.bounded_side(p) == ON_BOUNDED_SIDE ) return true; return false; } class Life { public: int index; double birth; double death; double span; int edge; // index of critical edge in DelEdges Life (int i, double b, double d, int e) { index = i; birth = b; death = d; span = d-b; edge = e; } }; class Region { public: int index; // index of this region in Map int edge; // index of the critical edge in DelEdges that created this region double birth; double death; double span; vector core; // indices of triangles that were last alive before this region died int heir; // index of the root triangle in the older region that absorbed this region int supr; // index of the region (in Map) defined by the triangle heir, computed at the end Region (int i, double b, double d, vectorconst& c, int h, int s, int e) { index = i; birth = b; death = d; span = d-b; core = c; heir = h; supr = s; edge = e; } }; bool DecreasingSpans (Region const& r1, Region const& r2) { return r1.span >= r2.span; } void DrawHopes (vectorconst& DelEdges, vectorconst& NegEdges, vectorconst& PosEdges, double scale, Point2d shift, Mat& iHopes) { for (size_t i=0; ipoint(), DelEdges[NegEdges[i]].end2->point(),scale,shift,Black,iHopes); for (size_t i=0; ipoint(), DelEdges[PosEdges[i]].end2->point(), scale, shift, Red,iHopes); } void DrawMap (vectorconst& FaceHandles, vectorconst& Map, double scale, Point2d shift, Mat& image) { int ind = -1; for (int j=0; jvertex(0)->point(), scale, shift ); Poly[1] = ScaleShift( iF->vertex(1)->point(), scale, shift ); Poly[2] = ScaleShift( iF->vertex(2)->point(), scale, shift ); //cout<<"\nR"<vertex(0)->point()<<")("<vertex(1)->point()<<")("<vertex(2)->point()<<")"; fillConvexPoly( image, Poly, 3, c ); //P2 p ( (p0.x()+p1.x()+p2.x())/3, (p0.y()+p1.y()+p2.y())/3 ); //String s = "R" + to_string(j) + "," + to_string( iF->info().index ); //putText(image, s, ScaleShift(p , scale, shift), FONT_HERSHEY_PLAIN, 1.0, Black); } } } void FindBoundary (int nRegions, vectorconst& Map, vector& DelEdges) { vector regions( nRegions ); for (int i=0; iconst& DelEdges, double scale, Point2d shift, Mat& image) { for (size_t e=0; epoint(); P2 p2 = DelEdges[e].end2->point(); line( image, ScaleShift( p1, scale, shift ), ScaleShift( p2, scale, shift ), Black, 2 ); } } void DrawDiagram (vectorconst& Persistence, int iAbove, double CritLength, double MaxRadius, double scale, Point2i shift, Mat& image) { size_t nDots = Persistence.size(); double d = MaxRadius; Point Poly[4]; double s = Persistence[iAbove].span, c = 0.5*CritLength, y = 0; if (iAbove>0) y = Persistence[iAbove-1].span; Poly[0] = ScaleShift( Point2d( 0, d - s ), scale, shift); Poly[1] = ScaleShift( Point2d( 0, d - y ), scale, shift); Poly[2] = ScaleShift( Point2d( d - y, 0 ), scale, shift); Poly[3] = ScaleShift( Point2d( d - s, 0 ), scale, shift); fillConvexPoly( image, Poly, 4, Yellow); /* Prepare VerSubDiagram int iRight = -1; double xRight = 1e+8; for (int i=iAbove; i c) if (Persistence[i].birth < xRight) { xRight = Persistence[i].birth; iRight = i; } if ( iRight < 0 ) // Draw triangular VerSubDiagram { Poly[0] = ScaleShift( Point2d( c, d-s-c), scale,shift); Poly[1] = ScaleShift( Point2d( c, 0 ), scale, shift); Poly[2] = ScaleShift( Point2d( d-s, 0 ), scale, shift); fillConvexPoly( image, Poly, 3, Lime); } else { // Draw VerSubDiagram as a trapezium double r = Persistence[iRight].birth; Poly[0] = ScaleShift( Point2d( c, d-s-c), scale, shift); Poly[1] = ScaleShift( Point2d( c, 0 ), scale, shift); Poly[2] = ScaleShift( Point2d( r, 0 ), scale, shift); Poly[3] = ScaleShift( Point2d( r, d-s-r), scale, shift); fillConvexPoly( image, Poly, 4, Lime); }*/ for (size_t i=0; i c) size = 2; if (i p2.value; } bool IncreasingValues (IndexValue const& p1, IndexValue const& p2) { return p1.value < p2.value; } void BuildStaircase ( vectorconst& Persistence, int ind, vector& Staircase) { size_t nValues = Persistence.size(); vector Endpoints ( 2*(nValues-ind) ); for (size_t i=ind; iconst& P) { for (int j=0; j vertices; vector< pair > edges; // pairs of indices of vertices vector edgelengths; vector< vector > vedges; // indices of edges around a vertex Graph() {} Graph( vectorconst& DelEdges, vectorconst& EdgeIndices, int nVertices ) { vertices.resize (nVertices); vedges.resize (nVertices); edges.resize( EdgeIndices.size() ); edgelengths.resize( EdgeIndices.size() ); for (int i=0; iinfo(); edges[i].second = e.end2->info(); edgelengths[i] = e.length; vertices[ e.end1->info() ] = e.end1->point(); vertices[ e.end2->info() ] = e.end2->point(); vedges[ e.end1->info() ].push_back( i ); vedges[ e.end2->info() ].push_back( i ); } } Graph (String type, int size) { if (type=="star") { if (size<2) size = 2; vertices.resize( size+1 ); vertices[0] = P2 (0,0); edges.resize( size ); edgelengths.resize( size ); double angle = 2.0 * M_PI / size; for(int i=1; i<=size; i++) { edges[i-1] = make_pair( 0, i ); edgelengths [i-1] = 1; double x = cos( i * angle ); double y = sin( i * angle ); vertices[i] = P2 (x,y); } } else if (type=="wheel") { if (size<3) size = 3; vertices.resize( size+1 ); vertices[0] = P2 (0,0); edges.resize( 2*size ); edgelengths.resize( 2*size ); double angle = 2.0 * M_PI / size; double side = 2 * sin ( angle/2 ); //cout<<" side = "<& PointCloud) { if ( edges.size() == 0) {/* for(int i=0;i=vedges[v1].size()"<e) vedges[i][j]--; else if (vedges[i][j]==e) cout<<" vedges["< v2) edges[i].first--; else if (edges[i].first == v2) cout<<" edges["< v2) edges[i].second--; else if (edges[i].second == v2) cout<<" edges["< file_names = { "sc99.phi35.Er45.0Rr6.0", "sc98.phi35.Er37.5Rr5.0", "sc38.phi35.Er3.75Rr0.5", "sc29.phi35.Er9.375Rr1.25", "sc28.phi35.Er13.125Rr1.75", "sc11.phi35.Er22.5Rr3.0", "sc2.phi35.Er60.0Rr8.0", "sc1.phi35.Er7.5Rr1.0", "s30.phi35.Er11.5Rr1.5", "s29.phi35.Er15.0Rr2.0", "s28.phi35.Er30.0Rr4.0" }; String add_ext = "_t_10000000.c"; // Load PointCloud vector PointCloud; vector< vector > clouds; if (InputType == "image") { InputImage = imread( InputFolder + ImageFile + "." + FileExt); if( !InputImage.data ) { cout<<"\nFile not found:"< CloudBox; FindCloudBox( PointCloud, CloudBox ); //cout<<"\nCloudBox: first = "<vertex(0)->point().x(); FaceHandles[0] = Del.infinite_face(); // default handle isn't used for external region FaceHandles[0]->info().birth = MaxRadius+1e-2; // external region is born at alpha = MaxRadius FaceHandles[0]->info().index = 0; FaceHandles[0]->info().uplink = 0; FaceHandles[0]->info().live.resize(1); FaceHandles[0]->info().live[0] = 0; // Build vector DelEdges and draw a triangulation vector DelEdges; for(FEI iE = Del.finite_edges_begin(); iE != Del.finite_edges_end(); ++iE) DelEdges.push_back( Edge (*iE) ); Mat iDelaunay = Image.clone(); DrawTriangulation( Del, Scale, Shift, iDelaunay ); WriteImage( sCloud + "DelT.png", iDelaunay ); // Cycle over edges to find all critical values sort( DelEdges.begin(), DelEdges.end(), DecreasingLengths ); double alpha=0; vector Persistence; vector Map; vector NegativeEdges; NegativeEdges.clear(); vector PositiveEdges; PositiveEdges.clear(); int iEdge=0, Links=0, nCases1=0, nCases2=0, nCases3=0, nCases4=0; for (; iEdgelength; int node_u = CurEdge->face1; int node_v = CurEdge->face2; int root_u = FindRoot (node_u, FaceHandles); int root_v = FindRoot (node_v, FaceHandles); //cout<<"\nE="<info(); Node* Node_v = &FaceHandles[node_v]->info(); Node_u->uplink = root_u; // shorten path to root Node_v->uplink = root_v; // shorten path to root Node* Root_u = &FaceHandles[root_u]->info(); Node* Root_v = &FaceHandles[root_v]->info(); double alpha_u = Root_u->birth; //FaceHandles[node_u]->info().birth; double alpha_v = Root_v->birth; if ( (alpha_u==0) && (alpha_v>0) ) // Case 2: node u joins the region of node v { nCases2++; //cout<<" C2: "; if ( node_u != root_u ) cout<<"\n Error2: "<<" u"<uplink = root_v; // root_v becomes parent of root_u Node_u->birth = alpha_v; if ( Root_v->height == 1 ) Root_v->height = 2; // node_u added to the tree at root_v int r = Node_v->bar; // index of the region containing the triangle T_v if ( r >= 0) // the region is already dead { Node_u->bar = r; // node_u joins the dead region of node_v Map[r].core.push_back(node_u); } else Root_v->live.push_back(node_u); // node_u becomes a live triangle at root_v Node_u->live.clear(); } else if ( (alpha_u>0) && (alpha_v==0) ) // symmetric Case 2: node_v joins the region of node_u { nCases2++; //cout<<" C2': "; if ( node_v != root_v ) cout<<"\n Error2: "<<" u"<uplink = root_u; Node_v->birth = alpha_u; if ( Root_u->height == 1 ) Root_u->height = 2; // node_v added to the tree at root_u int r = Node_u->bar; // index the region containing the triangle T_u if ( r >= 0) // the region is already dead { Node_v->bar = r; // node_v joins the dead region of node_u Map[r].core.push_back(node_v); } else Root_u->live.push_back(node_v); // node_v becomes a live triangle at root_u Node_v->live.clear(); } else if ( (alpha_u==0) && (alpha_v==0) ) // Case 3: two right-angled triangles at node_u, node_v { nCases3++; //cout<<" C3: "; if ( node_u != root_u || node_v != root_v ) cout<<"\n E3: "<<" u"<uplink = node_u; // root_u = node_u becomes parent of root_v = node_v if (Node_u->height == 1) Node_u->height = 2; // node_v is now attached to its parent node_u Node_u->birth = alpha; Node_v->birth = alpha; Node_u->live.push_back(node_v); Node_v->live.clear(); } else if ( (alpha_u>0) && (alpha_v>0) ) // Case 4: merge the regions of node_u, node_v { nCases4++; //cout<<" C4: "; double death = std::min(alpha_u,alpha_v); int heir = -1, supr = -1, ind = (int)Map.size(); // index of the newly added region Persistence.push_back( Life( ind, alpha, death, iEdge ) ); // younger class dies and is recorded // Create a new region (in Map) corresponding to a dot in the persistence diagram if (Root_u->birth <= Root_v->birth) // u is younger than v { // set bar index for all live triangles at root_u for (int i=0; ilive.size(); i++) FaceHandles[ Root_u->live[i] ]->info().bar = ind; if (Node_v->bar < 0) heir = node_v; // node_v is still alive and will be the heir else supr = Node_v->bar; // bar index of the already dead region containing T_v Map.push_back( Region( ind, alpha, death, Root_u->live, heir, supr, iEdge ) ); if ( Root_u->height > Root_v->height ) { // u is younger, but higher than v Root_v->uplink = root_u; Root_u->live = Root_v->live; // triangles from Root_v->live are saved to the higher Root_u->live Root_u->birth = Root_v->birth; // the new root now has the earliest birth } else { // u is younger and lower than v Root_u->uplink = root_v; if ( Root_u->height == Root_v->height ) Root_v->height ++; } } else { // v is younger (than u) and dies for (int i=0; ilive.size(); i++) FaceHandles[ Root_v->live[i] ]->info().bar = ind; if (Node_u->bar < 0) heir = node_u; // root_u still alive and will be the heir else supr = Node_u->bar; // bar index of the already dead region containing T_u Map.push_back( Region( ind, alpha, death, Root_v->live, heir, supr, iEdge ) ); if ( Root_u->height >= Root_v->height ) { // v is younger and lower than v Root_v->uplink = root_u; if ( Root_u->height == Root_v->height ) Root_u->height ++; } else { // v is younger, but higher than u Root_u->uplink = root_v; Root_v->live = Root_u->live; Root_v->birth = Root_u->birth; } } } Links++; if ( Links >= nFaces ) break; } cout<<"\nCases1="< DiagonalGaps (nDots); DiagonalGaps[0] = IndexValue( 0, Persistence[0].span ); //smallest gap for(int i=1; i IndicesAbove( nDots ); IndicesAbove[0] = DiagonalGaps[0].index; // index of dots above the 1st widest diagonal gap for(size_t i=1; i DiagSub; DiagSub.insert( DiagSub.begin(), Persistence.begin()+IndicesAbove[DiagGap-1], Persistence.end()); cout<<"\nDiagonal subdiagram above gap"< VerticalGaps (nDiagSub-1); for(int i=0; i IndicesOnLeft(nDiagSub); IndicesOnLeft[0] = VerticalGaps[0].index; // index of dot on the left bound of vgap for(size_t i=1; i CritLength ) CritLength = DelEdges[ PositiveEdges[i] ].length; //cout<<"\nCritLength = "< EdgeIndices; EdgeIndices.insert ( EdgeIndices.begin(), NegativeEdges.begin(), NegativeEdges.end() ); Graph MST (DelEdges, EdgeIndices, nVertices); Mat iMST = Image.clone(); MST.Draw (Scale, Shift, iMST); WriteImage( sCloud + "MST.png", iMST ); EdgeIndices.insert ( EdgeIndices.begin(), PositiveEdges.begin(), PositiveEdges.end() ); Graph Hopes (DelEdges, EdgeIndices, nVertices); Graph SimHopes = Hopes; // Simplify HoPeS while ( SimHopes.CollapseShortestEdge( 0.5 * CritLength ) ) nSimEdges--; cout<<" SimHoPeS has "< Staircase; BuildStaircase ( Persistence, IndicesAbove[DiagGap-1], Staircase ); Mat iStaircase = Image.clone(); DrawStaircase ( Staircase, ShiftImage, SizeImage-2*BorderImage, iStaircase ); WriteImage( sCloud + "Staircase.png", iStaircase ); // Compute probabilities for the number of holes int MaxHoles = 0; for (size_t i=0; i MaxHoles ) MaxHoles = Staircase[i].index; vector Probabilities (MaxHoles+1); for (int i=0; i<=MaxHoles; i++) { Probabilities[i].index = i; Probabilities[i].value = 0; } for (size_t i=0; i NewIndex //sort( Map.begin(), Map.end(), DecreasingSpans ); //for (int f=0; f<=nFaces; f++) cout<<" FH["<info().bar; Print( Persistence ); // Set supr (indices of superior components in Map) for (int k=0; k<=nDots; k++) if (Map[k].supr < 0) { if ( Map[k].heir >= 0 ) Map[k].supr = FaceHandles[ Map[k].heir ]->info().bar; // old index of superior region else cout<<"\n*error1 with heir and supr: k="< NewIndices( nDots+1 ); for (int k=0; k