67 inline double evalX(
double t)
const {
70 inline double evalY(
double t)
const {
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);
186 template <
class dataType,
class triangulationType>
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);
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);
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);
219 const std::vector<LinearTrajectory> &newTraj,
220 std::vector<std::array<double, 3>> &meanDir);
226 template <
class dataType>
228 const dataType *scalars,
231 template <
class dataType,
class triangulationType>
233 const dataType *scalars,
234 const triangulationType *triangulation,
393 std::vector<ttk::SimplexId> &segmentVerts,
394 const dataType *scalars,
395 const triangulationType *triangulation,
396 const int otsuBins) {
397 if(segmentVerts.size() < 2)
402 std::vector<char> inSeg(triangulation->getNumberOfVertices(), 0);
403 std::vector<ttk::SimplexId> kept;
404 kept.reserve(segmentVerts.size());
406 for(
const auto v : segmentVerts) {
407 if(scalars[v] <= T) {
413 const size_t segSize = segmentVerts.size();
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)
420 std::vector<ttk::SimplexId> tmp = segmentVerts;
422 return scalars[a] < scalars[b];
424 for(
size_t i = 0; i < std::min(minKeep, tmp.size()); ++i) {
425 kept.push_back(tmp[i]);
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;
437 for(
const auto seed : kept) {
440 std::vector<ttk::SimplexId> cc;
445 const auto u = q.front();
448 const auto deg = triangulation->getVertexNeighborNumber(u);
451 triangulation->getVertexNeighbor(u, i, nb);
452 if(nb < 0 || !inSeg[nb] || visited[nb])
458 if(cc.size() > bestCC.size())
461 segmentVerts.swap(bestCC);
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) {
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);
479 vertexTrajPerFrame.clear();
484 const ttk::SimplexId nPixels = triangulation->getNumberOfVertices();
485 const int nFrames =
static_cast<int>(
inputData_.size());
487 this->
printMsg(
"Merge-tree (" + std::to_string(nFrames) +
" f., "
488 + std::to_string(nPixels) +
" v., " + std::to_string(nTraj)
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));
497 vertexTrajPerFrame.assign(nFrames, std::vector<int>(nPixels, -1));
501#ifdef TTK_ENABLE_OPENMP
502#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
504 for(
int frame = 0; frame < nFrames; ++frame) {
509 auto *scalars =
static_cast<dataType *
>(
inputData_[frame]);
512 std::vector<dataType> outScalars(nPixels);
513 std::copy(scalars, scalars + nPixels, outScalars.begin());
515 std::vector<ttk::SimplexId> offsets(nPixels);
517 static_cast<size_t>(nPixels), scalars, offsets.data(), 1);
519 dataType sMin = scalars[0], sMax = scalars[0];
521 if(scalars[i] < sMin)
523 if(scalars[i] > sMax)
526 const dataType persThresh =
static_cast<dataType
>(
530 lts.setThreadNumber(1);
531 lts.setDebugLevel(0);
532 lts.preconditionTriangulation(
533 const_cast<triangulationType *
>(triangulation));
535 const int statusSimp =
lts.removeNonPersistentExtrema<
537 outScalars.data(), offsets.data(), triangulation, persThresh,
true,
539 if(statusSimp != 0) {
540#ifdef TTK_ENABLE_OPENMP
541#pragma omp atomic write
548 std::vector<ttk::SimplexId> order(nPixels);
550 static_cast<size_t>(nPixels), outScalars.data(), order.data(), 1);
552 std::vector<ttk::SimplexId> ascendingManifold(nPixels, -1);
553 std::vector<ttk::SimplexId> descendingManifold(nPixels, -1);
561 ascendingManifold.data(), descendingManifold.data(),
nullptr};
564 const int statusPC = pathComp.
execute<triangulationType>(
565 om, order.data(), *
const_cast<triangulationType *
>(triangulation));
567#ifdef TTK_ENABLE_OPENMP
568#pragma omp atomic write
575 std::vector<ttk::SimplexId> orderInv(nPixels);
577 orderInv[i] = nPixels - order[i] - 1;
579 auto &localTrajDouble = trajDoublePerFrame[frame];
580 auto &localVertexLabel = vertexTrajPerFrame[frame];
581 std::vector<int> vertexTraj(nPixels, -1);
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;
596 const int statusMT = exTreeM.
computePairs<triangulationType>(
597 persistencePairs, cpMap, branches, segmentation.data(),
598 regionType.data(), mtManifold, mtScratch, mtOrder, triangulation,
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(
612 std::vector<char> segCleaned(segmentId.size(), 0);
614 for(
size_t trajId = 0; trajId < nTraj; ++trajId) {
615 const auto &traj = finalTraj[trajId];
616 if(frame < traj.startFrame || frame > traj.endFrame)
621 if(!traj.isLinearized)
623 const double x = traj.evalX(frame);
626 const double y = traj.evalY(frame);
633 if(vId < 0 || vId >= nPixels)
635 if(regionType[vId] != 0)
638 const auto segId = segmentation[vId];
642 if(trajSurfPerFrame[frame][trajId] > 0.0)
646 && segmentId[segId].size() > 8 &&
otsuBins_ > 0) {
648 segmentId[segId], scalars, triangulation,
otsuBins_);
649 segCleaned[segId] = 1;
652 if(
static_cast<int>(segmentId[segId].size()) >
maxSurfSize_)
655 double surfVal =
static_cast<double>(
659 trajSurfPerFrame[frame][trajId] = surfVal;
661 const int currentChainId = finalTraj[trajId].finalChainId;
663 for(
const auto v : segmentId[segId]) {
664 const int check = vertexTraj[v];
666 vertexTraj[v] =
static_cast<int>(trajId);
667 }
else if(check !=
static_cast<int>(trajId)) {
668 localTrajDouble[trajId] = 1;
670 localTrajDouble[check] = 1;
674 if(currentChainId >= 0) {
675 std::unordered_set<ttk::SimplexId> dilatedSet;
676 dilatedSet.reserve(segmentId[segId].size() * 4);
679 = triangulation->getVertexStarNumber(v);
682 triangulation->getVertexStar(v, k, cellId);
683 const int nCellVerts = triangulation->getCellVertexNumber(cellId);
684 for(
int cv = 0; cv < nCellVerts; ++cv) {
686 triangulation->getCellVertex(cellId, cv, vDil);
687 dilatedSet.insert(vDil);
693 const int prev = localVertexLabel[v];
695 localVertexLabel[v] = currentChainId;
696 }
else if(prev != currentChainId && prev != -2) {
697 localVertexLabel[v] = -2;
708 order.data(), descendingManifold.data(), ascendingManifold.data());
711 orderInv.data(), ascendingManifold.data(), descendingManifold.data());
714 order.data(), descendingManifold.data(), ascendingManifold.data());
717 orderInv.data(), ascendingManifold.data(), descendingManifold.data());
721#ifdef TTK_ENABLE_OPENMP
722#pragma omp atomic write
729 if(globalError != 0) {
730 this->
printErr(
"Error in merge-tree frame processing");
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;
742#ifdef TTK_ENABLE_OPENMP
743#pragma omp parallel for num_threads(this->threadNumber_)
745 for(
size_t trajId = 0; trajId < nTraj; ++trajId) {
746 double minVal = std::numeric_limits<double>::max();
750 for(
int frame = 0; frame < nFrames; ++frame) {
751 const double s = trajSurfPerFrame[frame][trajId];
762 surfMin[trajId] = minVal;
763 surfMax[trajId] = maxVal;
764 surfMean[trajId] = sum /
static_cast<double>(count);
769 this->threadNumber_);
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) {
792 trajCriticalType, linearTraj, finalTraj, fuseRecords);
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);
801 triangulation, finalTraj, surfMin, surfMax, surfMean, vertexTrajPerFrame);
803 vertexTrajPerFrame.clear();
807 this->threadNumber_);
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 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 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.