TTK
Loading...
Searching...
No Matches
TrackingPostProcessing.h
Go to the documentation of this file.
1
21
22#pragma once
23
24#include <DataTypes.h>
25#include <Debug.h>
26#include <Geometry.h>
27#include <Timer.h>
28#include <Triangulation.h>
29
30// merge-tree
31#include <ExTreeM.h>
32#include <FTMTreePP.h>
34#include <PathCompression.h>
35
36#ifdef TTK_ENABLE_EIGEN
37#include <Eigen/Dense>
38#endif
39
40#include <algorithm>
41#include <array>
42#include <cmath>
43#include <limits>
44#include <map>
45#include <queue>
46#include <unordered_set>
47#include <utility>
48#include <vector>
49
50namespace ttk {
51
52 class TrackingPostProcessing : virtual public Debug {
53
54 public:
58 double ax{0.0}, bx{0.0}, ay{0.0}, by{0.0};
59 int startFrame{0};
60 int endFrame{0};
61 int finalChainId{-1};
63 bool isLinearized{true};
64
65 std::vector<std::pair<int, ttk::SimplexId>> criticalPoints;
66
67 inline double evalX(double t) const {
68 return ax * t + bx;
69 }
70 inline double evalY(double t) const {
71 return ay * t + by;
72 }
73
74 inline ttk::SimplexId getOriginalVertex(int frame) const {
75 for(const auto &cp : criticalPoints) {
76 if(cp.first == frame)
77 return cp.second;
78 }
79 return -1;
80 }
81 };
82
84 struct FuseRecord {
85 int i{-1}, j{-1};
86 int endFrame{0};
87 int startFrame{0};
88 int finalContrib{-1};
89 };
90
92
94 ttk::AbstractTriangulation *triangulation) const {
95 triangulation->preconditionVertexNeighbors();
96 return triangulation->preconditionVertexStars();
97 }
98
99 inline void setInputScalars(const std::vector<void *> &inputScalars) {
100 inputData_ = inputScalars;
101 }
102 inline void setCosCol(double v) {
103 cosCol_ = v;
104 }
105 inline void setMaxRadius(double v) {
106 maxRadius_ = v;
107 }
108 inline void setMaxFrameDist(int v) {
109 maxFrameDist_ = v;
110 minFrameDist_ = -v;
111 }
112
113 inline void setPersistenceThreshold(double v) {
115 }
116 inline void setMaxSurfSize(int v) {
117 maxSurfSize_ = v;
118 }
119 inline void setUseOtsuSimplification(bool v) {
121 }
122 inline void setOtsuBins(int v) {
123 otsuBins_ = v;
124 }
125
126 inline void setBoundaryXMin(double v) {
127 boundaryXMin_ = v;
128 }
129 inline void setBoundaryXMax(double v) {
130 boundaryXMax_ = v;
131 }
132 inline void setBoundaryYMin(double v) {
133 boundaryYMin_ = v;
134 }
135 inline void setBoundaryYMax(double v) {
136 boundaryYMax_ = v;
137 }
138
139 inline void setDoLinearize(bool v) {
140 doLinearize_ = v;
141 }
142 inline void setDoFusion(bool v) {
143 doFusion_ = v;
144 }
145 inline void setDoLinearizeFuse(bool v) {
147 }
148 inline void setDoMergeTree(bool v) {
149 doMergeTree_ = v;
150 }
151 inline void setUseSplitTree(int v) {
152 useSplitTree_ = v;
153 }
154
167 int correctTrajectory(const std::vector<std::vector<int>> &trajTime,
168 const std::vector<std::vector<int>> &trajVertexId,
169 const std::vector<std::vector<double>> &coordsX,
170 const std::vector<std::vector<double>> &coordsY,
171 const std::vector<int> &trajCriticalType,
172 std::vector<LinearTrajectory> &linearTraj,
173 std::vector<LinearTrajectory> &outputTraj,
174 std::vector<FuseRecord> &fuseRecords);
175
186 template <class dataType, class triangulationType>
187 int computeMergeTree(const triangulationType *triangulation,
188 const std::vector<LinearTrajectory> &finalTraj,
189 std::vector<double> &surfMin,
190 std::vector<double> &surfMax,
191 std::vector<double> &surfMean,
192 std::vector<std::vector<int>> &vertexTrajPerFrame);
193
195 template <class dataType, class triangulationType>
196 int execute(const std::vector<std::vector<int>> &trajTime,
197 const std::vector<std::vector<int>> &trajVertexId,
198 const std::vector<std::vector<double>> &coordsX,
199 const std::vector<std::vector<double>> &coordsY,
200 const std::vector<int> &trajCriticalType,
201 std::vector<LinearTrajectory> &linearTraj,
202 std::vector<LinearTrajectory> &finalTraj,
203 std::vector<FuseRecord> &fuseRecords,
204 std::vector<double> &surfMin,
205 std::vector<double> &surfMax,
206 std::vector<double> &surfMean,
207 std::vector<std::vector<int>> &vertexTrajPerFrame,
208 const triangulationType *triangulation);
209
210 protected:
211#ifdef TTK_ENABLE_EIGEN
212 int linearRegression(const std::vector<int> &T,
213 const std::vector<double> &X,
214 const std::vector<double> &Y,
215 LinearTrajectory &traj);
216#endif
217
219 const std::vector<LinearTrajectory> &newTraj,
220 std::vector<std::array<double, 3>> &meanDir);
221
222 int
223 computeSurfaceCellCount(const std::vector<ttk::SimplexId> &surfVertices,
224 const ttk::AbstractTriangulation *triangulation);
225
226 template <class dataType>
227 dataType otsuThresholdLocal(const std::vector<ttk::SimplexId> &verts,
228 const dataType *scalars,
229 const int nbins);
230
231 template <class dataType, class triangulationType>
232 void cleanDarkSegmentInPlace(std::vector<ttk::SimplexId> &segmentVerts,
233 const dataType *scalars,
234 const triangulationType *triangulation,
235 const int otsuBins);
236
237 std::vector<void *> inputData_{};
238
239 double cosCol_{0.9};
240 double maxRadius_{225.0}; // squared pixel distance
243
245 int maxSurfSize_{10000};
247 int otsuBins_{0};
248
249 double boundaryXMin_{0.0};
250 double boundaryXMax_{0.0};
251 double boundaryYMin_{0.0};
252 double boundaryYMax_{0.0};
253
254 bool doLinearize_{true};
255 bool doFusion_{true};
257 bool doMergeTree_{false};
259 };
260
261} // namespace ttk
262
263#ifdef TTK_ENABLE_EIGEN
264inline int
265 ttk::TrackingPostProcessing::linearRegression(const std::vector<int> &T,
266 const std::vector<double> &X,
267 const std::vector<double> &Y,
268 LinearTrajectory &traj) {
269 const int n = static_cast<int>(T.size());
270 if(n < 1)
271 return 0;
272 Eigen::MatrixXd M(n, 2);
273 Eigen::VectorXd vx(n), vy(n);
274 for(int i = 0; i < n; ++i) {
275 M(i, 0) = T[i];
276 M(i, 1) = 1.0;
277 vx(i) = X[i];
278 vy(i) = Y[i];
279 }
280 const Eigen::Vector2d bxv
281 = (M.transpose() * M).ldlt().solve(M.transpose() * vx);
282 const Eigen::Vector2d byv
283 = (M.transpose() * M).ldlt().solve(M.transpose() * vy);
284 traj.ax = bxv[0];
285 traj.bx = bxv[1];
286 traj.ay = byv[0];
287 traj.by = byv[1];
288 traj.finalChainId = -1;
289 return 1;
290}
291#endif
292
294 const std::vector<LinearTrajectory> &newTraj,
295 std::vector<std::array<double, 3>> &meanDir) {
296 const size_t nTraj = newTraj.size();
297 meanDir.assign(nTraj, {0.0, 0.0, 0.0});
298 for(size_t i = 0; i < nTraj; ++i) {
299 const auto &t = newTraj[i];
300 std::array<double, 3> v{t.ax, t.ay, 1.0};
301 const double mag = ttk::Geometry::magnitude<double>(v.data(), 3);
302 if(mag > 0.0) {
304 v.data(), 1.0 / mag, meanDir[i].data(), 3);
305 }
306 }
307 return 1;
308}
309
311 const std::vector<ttk::SimplexId> &surfVertices,
312 const ttk::AbstractTriangulation *triangulation) {
313 std::unordered_set<ttk::SimplexId> cellIds;
314 for(const ttk::SimplexId v : surfVertices) {
315 const ttk::SimplexId starCount = triangulation->getVertexStarNumber(v);
316 for(ttk::SimplexId k = 0; k < starCount; ++k) {
317 ttk::SimplexId ttkCellId;
318 triangulation->getVertexStar(v, k, ttkCellId);
319 int vtkCellId;
320 triangulation->getCellVTKID(ttkCellId, vtkCellId);
321 cellIds.insert(vtkCellId);
322 }
323 }
324 return static_cast<int>(cellIds.size());
325}
326
327template <class dataType>
329 const std::vector<ttk::SimplexId> &verts,
330 const dataType *scalars,
331 const int nbins) {
332 if(verts.empty() || nbins < 2)
333 return dataType{0};
334
335 dataType vmin = scalars[verts[0]];
336 dataType vmax = scalars[verts[0]];
337 for(const auto v : verts) {
338 const auto s = scalars[v];
339 if(s < vmin)
340 vmin = s;
341 if(s > vmax)
342 vmax = s;
343 }
344 if(vmax <= vmin)
345 return vmin;
346
347 std::vector<double> hist(nbins, 0.0);
348 const double minD = static_cast<double>(vmin);
349 const double maxD = static_cast<double>(vmax);
350 const double invRange = 1.0 / (maxD - minD);
351 for(const auto v : verts) {
352 const double s = static_cast<double>(scalars[v]);
353 int b = static_cast<int>(std::floor((s - minD) * invRange * (nbins - 1)));
354 b = std::max(0, std::min(nbins - 1, b));
355 hist[b] += 1.0;
356 }
357 const double total = static_cast<double>(verts.size());
358 for(auto &h : hist)
359 h /= total;
360
361 std::vector<double> omega(nbins, 0.0);
362 std::vector<double> mu(nbins, 0.0);
363 omega[0] = hist[0];
364 mu[0] = 0.0;
365 for(int i = 1; i < nbins; ++i) {
366 omega[i] = omega[i - 1] + hist[i];
367 mu[i] = mu[i - 1] + static_cast<double>(i) * hist[i];
368 }
369 const double muT = mu[nbins - 1];
370
371 int bestK = 0;
372 double bestSigma = -1.0;
373 for(int k = 0; k < nbins; ++k) {
374 const double w0 = omega[k];
375 const double w1 = 1.0 - w0;
376 if(w0 <= 1e-12 || w1 <= 1e-12)
377 continue;
378 const double mu0 = mu[k] / w0;
379 const double mu1 = (muT - mu[k]) / w1;
380 const double sigmaB = w0 * w1 * (mu0 - mu1) * (mu0 - mu1);
381 if(sigmaB > bestSigma) {
382 bestSigma = sigmaB;
383 bestK = k;
384 }
385 }
386 const double t
387 = minD + (static_cast<double>(bestK) / (nbins - 1)) * (maxD - minD);
388 return static_cast<dataType>(t);
389}
390
391template <class dataType, class triangulationType>
393 std::vector<ttk::SimplexId> &segmentVerts,
394 const dataType *scalars,
395 const triangulationType *triangulation,
396 const int otsuBins) {
397 if(segmentVerts.size() < 2)
398 return;
399
400 const dataType T
401 = otsuThresholdLocal<dataType>(segmentVerts, scalars, otsuBins);
402 std::vector<char> inSeg(triangulation->getNumberOfVertices(), 0);
403 std::vector<ttk::SimplexId> kept;
404 kept.reserve(segmentVerts.size());
405
406 for(const auto v : segmentVerts) {
407 if(scalars[v] <= T) {
408 kept.push_back(v);
409 inSeg[v] = 1;
410 }
411 }
412
413 const size_t segSize = segmentVerts.size();
414 const size_t minKeep
415 = std::max<size_t>(2, (size_t)std::ceil(0.10 * (double)segSize));
416 if(kept.size() < minKeep && segSize >= 2) {
417 for(const auto v : kept)
418 inSeg[v] = 0;
419 kept.clear();
420 std::vector<ttk::SimplexId> tmp = segmentVerts;
421 std::sort(tmp.begin(), tmp.end(), [&](ttk::SimplexId a, ttk::SimplexId b) {
422 return scalars[a] < scalars[b];
423 });
424 for(size_t i = 0; i < std::min(minKeep, tmp.size()); ++i) {
425 kept.push_back(tmp[i]);
426 inSeg[tmp[i]] = 1;
427 }
428 }
429 if(kept.empty())
430 return;
431
432 std::vector<char> visited(triangulation->getNumberOfVertices(), 0);
433 std::vector<ttk::SimplexId> bestCC;
434 bestCC.reserve(kept.size());
435 std::queue<ttk::SimplexId> q;
436
437 for(const auto seed : kept) {
438 if(visited[seed])
439 continue;
440 std::vector<ttk::SimplexId> cc;
441 cc.reserve(128);
442 visited[seed] = 1;
443 q.push(seed);
444 while(!q.empty()) {
445 const auto u = q.front();
446 q.pop();
447 cc.push_back(u);
448 const auto deg = triangulation->getVertexNeighborNumber(u);
449 for(ttk::SimplexId i = 0; i < deg; ++i) {
450 ttk::SimplexId nb{};
451 triangulation->getVertexNeighbor(u, i, nb);
452 if(nb < 0 || !inSeg[nb] || visited[nb])
453 continue;
454 visited[nb] = 1;
455 q.push(nb);
456 }
457 }
458 if(cc.size() > bestCC.size())
459 bestCC.swap(cc);
460 }
461 segmentVerts.swap(bestCC);
462}
463
464template <class dataType, class triangulationType>
466 const triangulationType *triangulation,
467 const std::vector<LinearTrajectory> &finalTraj,
468 std::vector<double> &surfMin,
469 std::vector<double> &surfMax,
470 std::vector<double> &surfMean,
471 std::vector<std::vector<int>> &vertexTrajPerFrame) {
472
473 const size_t nTraj = finalTraj.size();
474 surfMin.assign(nTraj, 0.0);
475 surfMax.assign(nTraj, 0.0);
476 surfMean.assign(nTraj, 0.0);
477
478 if(!doMergeTree_ || nTraj == 0 || inputData_.empty()) {
479 vertexTrajPerFrame.clear();
480 return 0;
481 }
482
483 ttk::Timer globalTimer;
484 const ttk::SimplexId nPixels = triangulation->getNumberOfVertices();
485 const int nFrames = static_cast<int>(inputData_.size());
486
487 this->printMsg("Merge-tree (" + std::to_string(nFrames) + " f., "
488 + std::to_string(nPixels) + " v., " + std::to_string(nTraj)
489 + " t.)");
490
491 // Per-frame / per-traj accumulated surface, and per-frame collision flags
492 std::vector<std::vector<double>> trajSurfPerFrame(
493 nFrames, std::vector<double>(nTraj, 0.0));
494 std::vector<std::vector<char>> trajDoublePerFrame(
495 nFrames, std::vector<char>(nTraj, 0));
496
497 vertexTrajPerFrame.assign(nFrames, std::vector<int>(nPixels, -1));
498
499 int globalError = 0;
500
501#ifdef TTK_ENABLE_OPENMP
502#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
503#endif
504 for(int frame = 0; frame < nFrames; ++frame) {
505 if(globalError != 0)
506 continue;
507
508 ttk::Timer frameTimer;
509 auto *scalars = static_cast<dataType *>(inputData_[frame]);
510
511 // --- Topological Simplification ---
512 std::vector<dataType> outScalars(nPixels);
513 std::copy(scalars, scalars + nPixels, outScalars.begin());
514
515 std::vector<ttk::SimplexId> offsets(nPixels);
517 static_cast<size_t>(nPixels), scalars, offsets.data(), 1);
518
519 dataType sMin = scalars[0], sMax = scalars[0];
520 for(ttk::SimplexId i = 1; i < nPixels; ++i) {
521 if(scalars[i] < sMin)
522 sMin = scalars[i];
523 if(scalars[i] > sMax)
524 sMax = scalars[i];
525 }
526 const dataType persThresh = static_cast<dataType>(
527 (sMax - sMin) * (this->persistenceThreshold_ / 100.0));
528
530 lts.setThreadNumber(1);
531 lts.setDebugLevel(0);
532 lts.preconditionTriangulation(
533 const_cast<triangulationType *>(triangulation));
534
535 const int statusSimp = lts.removeNonPersistentExtrema<
536 dataType, ttk::SimplexId, triangulationType>(
537 outScalars.data(), offsets.data(), triangulation, persThresh, true,
539 if(statusSimp != 0) {
540#ifdef TTK_ENABLE_OPENMP
541#pragma omp atomic write
542#endif
543 globalError = -1;
544 continue;
545 }
546
547 // --- Merge tree ---
548 std::vector<ttk::SimplexId> order(nPixels);
550 static_cast<size_t>(nPixels), outScalars.data(), order.data(), 1);
551
552 std::vector<ttk::SimplexId> ascendingManifold(nPixels, -1);
553 std::vector<ttk::SimplexId> descendingManifold(nPixels, -1);
554
555 ttk::PathCompression pathComp;
556 pathComp.setThreadNumber(1);
557 pathComp.setDebugLevel(0);
558 pathComp.setComputeSegmentation(true, true, false);
559
561 ascendingManifold.data(), descendingManifold.data(), nullptr};
562
563 {
564 const int statusPC = pathComp.execute<triangulationType>(
565 om, order.data(), *const_cast<triangulationType *>(triangulation));
566 if(statusPC != 0) {
567#ifdef TTK_ENABLE_OPENMP
568#pragma omp atomic write
569#endif
570 globalError = -1;
571 continue;
572 }
573 }
574
575 std::vector<ttk::SimplexId> orderInv(nPixels);
576 for(ttk::SimplexId i = 0; i < nPixels; ++i)
577 orderInv[i] = nPixels - order[i] - 1;
578
579 auto &localTrajDouble = trajDoublePerFrame[frame];
580 auto &localVertexLabel = vertexTrajPerFrame[frame];
581 std::vector<int> vertexTraj(nPixels, -1);
582
583 auto runTree
584 = [&](const ttk::SimplexId *mtOrder, ttk::SimplexId *mtManifold,
585 ttk::SimplexId *mtScratch) -> bool {
586 std::vector<ttk::SimplexId> segmentation(nPixels, -1);
587 std::vector<char> regionType(nPixels, 0);
588 std::vector<std::pair<ttk::SimplexId, ttk::SimplexId>> persistencePairs;
589 std::map<ttk::SimplexId, int> cpMap;
590 std::vector<ttk::ExTreeM::Branch> branches;
591
592 ttk::ExTreeM exTreeM;
593 exTreeM.setThreadNumber(1);
594 exTreeM.setDebugLevel(0);
595
596 const int statusMT = exTreeM.computePairs<triangulationType>(
597 persistencePairs, cpMap, branches, segmentation.data(),
598 regionType.data(), mtManifold, mtScratch, mtOrder, triangulation,
600 if(statusMT != 1)
601 return false;
602
603 const ttk::SimplexId maxSegId
604 = *std::max_element(segmentation.begin(), segmentation.end());
605 std::vector<std::vector<ttk::SimplexId>> segmentId(maxSegId + 1);
606 for(size_t vId = 0; vId < segmentation.size(); ++vId) {
607 if(regionType[vId] == 0)
608 segmentId[segmentation[vId]].push_back(
609 static_cast<ttk::SimplexId>(vId));
610 }
611
612 std::vector<char> segCleaned(segmentId.size(), 0);
613
614 for(size_t trajId = 0; trajId < nTraj; ++trajId) {
615 const auto &traj = finalTraj[trajId];
616 if(frame < traj.startFrame || frame > traj.endFrame)
617 continue;
618
619 ttk::SimplexId vId = traj.getOriginalVertex(frame);
620 if(vId < 0) {
621 if(!traj.isLinearized)
622 continue;
623 const double x = traj.evalX(frame);
624 if(x < boundaryXMin_ || x > boundaryXMax_ + 1)
625 continue;
626 const double y = traj.evalY(frame);
627 if(y < boundaryYMin_ || y > boundaryYMax_ + 1)
628 continue;
629 const ttk::SimplexId xi = static_cast<ttk::SimplexId>(std::lround(x));
630 const ttk::SimplexId yi = static_cast<ttk::SimplexId>(std::lround(y));
631 vId = xi + yi * (ttk::SimplexId)(boundaryXMax_ - boundaryXMin_ + 1);
632 }
633 if(vId < 0 || vId >= nPixels)
634 continue;
635 if(regionType[vId] != 0)
636 continue;
637
638 const auto segId = segmentation[vId];
639 if(segId < 0 || segId >= (ttk::SimplexId)segmentId.size())
640 continue;
641
642 if(trajSurfPerFrame[frame][trajId] > 0.0)
643 continue;
644
645 if(useOtsuSimplification_ && !segCleaned[segId]
646 && segmentId[segId].size() > 8 && otsuBins_ > 0) {
648 segmentId[segId], scalars, triangulation, otsuBins_);
649 segCleaned[segId] = 1;
650 }
651
652 if(static_cast<int>(segmentId[segId].size()) > maxSurfSize_)
653 continue;
654
655 double surfVal = static_cast<double>(
656 computeSurfaceCellCount(segmentId[segId], triangulation));
657 if(surfVal == 0)
658 surfVal = 1;
659 trajSurfPerFrame[frame][trajId] = surfVal;
660
661 const int currentChainId = finalTraj[trajId].finalChainId;
662
663 for(const auto v : segmentId[segId]) {
664 const int check = vertexTraj[v];
665 if(check == -1) {
666 vertexTraj[v] = static_cast<int>(trajId);
667 } else if(check != static_cast<int>(trajId)) {
668 localTrajDouble[trajId] = 1;
669 if(check >= 0)
670 localTrajDouble[check] = 1;
671 }
672 }
673
674 if(currentChainId >= 0) {
675 std::unordered_set<ttk::SimplexId> dilatedSet;
676 dilatedSet.reserve(segmentId[segId].size() * 4);
677 for(const ttk::SimplexId v : segmentId[segId]) {
678 const ttk::SimplexId starCount
679 = triangulation->getVertexStarNumber(v);
680 for(ttk::SimplexId k = 0; k < starCount; ++k) {
681 ttk::SimplexId cellId;
682 triangulation->getVertexStar(v, k, cellId);
683 const int nCellVerts = triangulation->getCellVertexNumber(cellId);
684 for(int cv = 0; cv < nCellVerts; ++cv) {
685 ttk::SimplexId vDil;
686 triangulation->getCellVertex(cellId, cv, vDil);
687 dilatedSet.insert(vDil);
688 }
689 }
690 }
691
692 for(const ttk::SimplexId v : dilatedSet) {
693 const int prev = localVertexLabel[v];
694 if(prev == -1) {
695 localVertexLabel[v] = currentChainId;
696 } else if(prev != currentChainId && prev != -2) {
697 localVertexLabel[v] = -2;
698 }
699 }
700 }
701 } // trajectory loop
702 return true;
703 };
704
705 bool ok = true;
706 if(useSplitTree_ == 1) {
707 ok = runTree(
708 order.data(), descendingManifold.data(), ascendingManifold.data());
709 } else if(useSplitTree_ == 0) {
710 ok = runTree(
711 orderInv.data(), ascendingManifold.data(), descendingManifold.data());
712 } else {
713 ok = runTree(
714 order.data(), descendingManifold.data(), ascendingManifold.data());
715 if(ok)
716 ok = runTree(
717 orderInv.data(), ascendingManifold.data(), descendingManifold.data());
718 }
719
720 if(!ok) {
721#ifdef TTK_ENABLE_OPENMP
722#pragma omp atomic write
723#endif
724 globalError = -1;
725 continue;
726 }
727 } // frame loop
728
729 if(globalError != 0) {
730 this->printErr("Error in merge-tree frame processing");
731 return -1;
732 }
733
734 for(int frame = 0; frame < nFrames; ++frame) {
735 for(size_t trajId = 0; trajId < nTraj; ++trajId) {
736 if(trajDoublePerFrame[frame][trajId])
737 trajSurfPerFrame[frame][trajId] = 0.0;
738 }
739 }
740
741 // Per-trajectory stat
742#ifdef TTK_ENABLE_OPENMP
743#pragma omp parallel for num_threads(this->threadNumber_)
744#endif
745 for(size_t trajId = 0; trajId < nTraj; ++trajId) {
746 double minVal = std::numeric_limits<double>::max();
747 double maxVal = 0.0;
748 double sum = 0.0;
749 int count = 0;
750 for(int frame = 0; frame < nFrames; ++frame) {
751 const double s = trajSurfPerFrame[frame][trajId];
752 if(s > 0.0) {
753 if(s < minVal)
754 minVal = s;
755 if(s > maxVal)
756 maxVal = s;
757 sum += s;
758 ++count;
759 }
760 }
761 if(count > 0) {
762 surfMin[trajId] = minVal;
763 surfMax[trajId] = maxVal;
764 surfMean[trajId] = sum / static_cast<double>(count);
765 }
766 }
767
768 this->printMsg("Segmentation complete", 1.0, globalTimer.getElapsedTime(),
769 this->threadNumber_);
770 return 0;
771}
772
773template <class dataType, class triangulationType>
775 const std::vector<std::vector<int>> &trajTime,
776 const std::vector<std::vector<int>> &trajVertexId,
777 const std::vector<std::vector<double>> &coordsX,
778 const std::vector<std::vector<double>> &coordsY,
779 const std::vector<int> &trajCriticalType,
780 std::vector<LinearTrajectory> &linearTraj,
781 std::vector<LinearTrajectory> &finalTraj,
782 std::vector<FuseRecord> &fuseRecords,
783 std::vector<double> &surfMin,
784 std::vector<double> &surfMax,
785 std::vector<double> &surfMean,
786 std::vector<std::vector<int>> &vertexTrajPerFrame,
787 const triangulationType *triangulation) {
788
789 ttk::Timer timer;
790
791 this->correctTrajectory(trajTime, trajVertexId, coordsX, coordsY,
792 trajCriticalType, linearTraj, finalTraj, fuseRecords);
793
794 const int numFinal = static_cast<int>(finalTraj.size());
795 surfMin.assign(numFinal, 0.0);
796 surfMax.assign(numFinal, 0.0);
797 surfMean.assign(numFinal, 0.0);
798
799 if(doMergeTree_) {
801 triangulation, finalTraj, surfMin, surfMax, surfMean, vertexTrajPerFrame);
802 } else {
803 vertexTrajPerFrame.clear();
804 }
805
806 this->printMsg("Post-processing complete", 1.0, timer.getElapsedTime(),
807 this->threadNumber_);
808 return 1;
809}
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual int getVertexStar(const SimplexId &vertexId, const int &localStarId, SimplexId &starId) const
virtual SimplexId getVertexStarNumber(const SimplexId &vertexId) const
virtual int getCellVTKID(const int &ttkId, int &vtkId) const
virtual int setThreadNumber(const int threadNumber)
Definition BaseClass.h:80
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
int computePairs(std::vector< std::pair< ttk::SimplexId, ttk::SimplexId > > &persistencePairs, std::map< ttk::SimplexId, int > &cpMap, std::vector< Branch > &branches, ttk::SimplexId *segmentation, char *regionType, ttk::SimplexId *descendingManifold, ttk::SimplexId *tempArray, const ttk::SimplexId *order, const triangulationType *triangulation, const char type)
Definition ExTreeM.h:1399
TTK processing package for the computation of Morse-Smale segmentations using Path Compression.
int execute(OutputSegmentation &outSegmentation, const SimplexId *const orderArray, const triangulationType &triangulation)
Main function for computing the Morse-Smale complex.
void setComputeSegmentation(const bool doAscending, const bool doDescending, const bool doMorseSmale)
double getElapsedTime()
Definition Timer.h:15
int execute(const std::vector< std::vector< int > > &trajTime, const std::vector< std::vector< int > > &trajVertexId, const std::vector< std::vector< double > > &coordsX, const std::vector< std::vector< double > > &coordsY, const std::vector< int > &trajCriticalType, std::vector< LinearTrajectory > &linearTraj, std::vector< LinearTrajectory > &finalTraj, std::vector< FuseRecord > &fuseRecords, std::vector< double > &surfMin, std::vector< double > &surfMax, std::vector< double > &surfMean, std::vector< std::vector< int > > &vertexTrajPerFrame, const triangulationType *triangulation)
correctTrajectory + computeMergeTree.
int computeSurfaceCellCount(const std::vector< ttk::SimplexId > &surfVertices, const ttk::AbstractTriangulation *triangulation)
int computeMeanUnitDirectionLinear(const std::vector< LinearTrajectory > &newTraj, std::vector< std::array< double, 3 > > &meanDir)
void setInputScalars(const std::vector< void * > &inputScalars)
int correctTrajectory(const std::vector< std::vector< int > > &trajTime, const std::vector< std::vector< int > > &trajVertexId, const std::vector< std::vector< double > > &coordsX, const std::vector< std::vector< double > > &coordsY, const std::vector< int > &trajCriticalType, std::vector< LinearTrajectory > &linearTraj, std::vector< LinearTrajectory > &outputTraj, std::vector< FuseRecord > &fuseRecords)
Linearize + (optional) chain input per-trajectory point clouds.
int preconditionTriangulation(ttk::AbstractTriangulation *triangulation) const
int computeMergeTree(const triangulationType *triangulation, const std::vector< LinearTrajectory > &finalTraj, std::vector< double > &surfMin, std::vector< double > &surfMax, std::vector< double > &surfMean, std::vector< std::vector< int > > &vertexTrajPerFrame)
Compute merge-tree-based segmentation per trajectory && per frame.
dataType otsuThresholdLocal(const std::vector< ttk::SimplexId > &verts, const dataType *scalars, const int nbins)
void cleanDarkSegmentInPlace(std::vector< ttk::SimplexId > &segmentVerts, const dataType *scalars, const triangulationType *triangulation, const int otsuBins)
int scaleVector(const T *a, const T factor, T *out, const int &dimension=3)
Definition Geometry.cpp:647
T magnitude(const T *v, const int &dimension=3)
Definition Geometry.cpp:509
TTK base package defining the standard types.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
void preconditionOrderArray(const size_t nVerts, const scalarType *const scalars, SimplexId *const order, const int nThreads=ttk::globalThreadNumber_)
Precondition an order array to be consumed by the base layer API.
Pointers to pre-allocated segmentation point data arrays.
Fusion-link record: trajectory i ends and trajectory j starts.
Linear trajectory: x(t) = ax*t + bx, y(t) = ay*t + by, defined on the inclusive frame range [startFra...
std::vector< std::pair< int, ttk::SimplexId > > criticalPoints
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)