TTK
Loading...
Searching...
No Matches
ttkMergeTreeTemporalReduction.cpp
Go to the documentation of this file.
2
3#include <ttkMergeTreeUtils.h>
5
6#include <vtkInformation.h>
7
8#include <vtkDataArray.h>
9#include <vtkDataSet.h>
10#include <vtkImageData.h>
11#include <vtkObjectFactory.h>
12#include <vtkPointData.h>
13#include <vtkResampleToImage.h>
14#include <vtkTable.h>
15
16#include <ttkUtils.h>
17
18using namespace ttk;
19using namespace ttk::ftm;
20
21// A VTK macro that enables the instantiation of this class via ::New()
22// You do not have to modify this
24
36 this->SetNumberOfInputPorts(1);
37 this->SetNumberOfOutputPorts(2);
38}
39
41
48 int port, vtkInformation *info) {
49 if(port == 0) {
50 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
51 return 1;
52 }
53 return 0;
54}
55
70 int port, vtkInformation *info) {
71 if(port == 0) {
72 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
73 } else if(port == 1) {
74 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable");
75 } else
76 return 0;
77 return 1;
78}
79
92 vtkInformation *ttkNotUsed(request),
93 vtkInformationVector **inputVector,
94 vtkInformationVector *outputVector) {
95 // ------------------------------------------------------------------------------------
96 // --- Get input object from input vector
97 // ------------------------------------------------------------------------------------
98 printMsg("Get input object from input vector", debug::Priority::VERBOSE);
99 auto blocks = vtkMultiBlockDataSet::GetData(inputVector[0], 0);
100
101 // ------------------------------------------------------------------------------------
102 // --- Load blocks
103 // ------------------------------------------------------------------------------------
105 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> inputTrees;
106 loadBlocks(inputTrees, blocks);
107 printMsg("Load blocks done.", debug::Priority::VERBOSE);
108
109 // If we have already computed once but the input has changed
110 if(treesNodes.size() != 0 and inputTrees[0]->GetBlock(0) != treesNodes[0])
111 resetDataVisualization();
112
113 // Run
114 return run<float>(outputVector, inputTrees);
115}
116
117template <class dataType>
119 vtkInformationVector *outputVector,
120 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees) {
121 if(not isDataVisualizationFilled())
122 runCompute<dataType>(inputTrees);
123 runOutput<dataType>(outputVector, inputTrees);
124 return 1;
125}
126
127static std::vector<vtkSmartPointer<vtkDataSet>>
128 preprocessSegmentation(std::vector<vtkDataSet *> &treesSegmentation,
129 bool doResampleToImage = false) {
130 std::vector<vtkSmartPointer<vtkDataSet>> images;
131 for(unsigned int i = 0; i < treesSegmentation.size(); ++i) {
132 if(doResampleToImage) {
133 auto seg = treesSegmentation[i];
134 // auto gridSeg = vtkUnstructuredGrid::SafeDownCast(seg);
135 auto resampleFilter = vtkSmartPointer<vtkResampleToImage>::New();
136 resampleFilter->SetInputDataObject(seg);
137 resampleFilter->SetUseInputBounds(true);
138 // resampleFilter->SetSamplingDimensions(100, 100, 100);
139 resampleFilter->Update();
140 auto resampleFilterOut = resampleFilter->GetOutput();
141 // images.push_back(resampleFilterOut);
143 image->DeepCopy(resampleFilterOut);
144 images.emplace_back(image);
145 } else {
147 image.TakeReference(treesSegmentation[i]);
148 images.emplace_back(image);
149 }
150 }
151 return images;
152}
153
154template <class dataType>
156 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees) {
157 // ------------------------------------------------------------------------------------
158 // --- Construct trees
159 // ------------------------------------------------------------------------------------
160 printMsg("Construct trees", debug::Priority::VERBOSE);
161
162 const int numInputs = inputTrees.size();
163
164 setDataVisualization(numInputs);
165
166 std::vector<MergeTree<dataType>> intermediateMTrees(numInputs);
167 constructTrees<dataType>(
168 inputTrees, intermediateMTrees, treesNodes, treesArcs, treesSegmentation);
169
170 // L2 distance preprocessing
171 if(useL2Distance_) {
172 auto images = preprocessSegmentation(treesSegmentation, DoResampleToImage);
173 fieldL2_ = std::vector<std::vector<double>>(images.size());
174 for(size_t i = 0; i < images.size(); ++i) {
175 auto array = images[i]->GetPointData()->GetArray("Scalars");
176 for(vtkIdType j = 0; j < array->GetNumberOfTuples(); ++j)
177 fieldL2_[i].emplace_back(array->GetTuple1(j));
178 }
179 }
180
181 // Load time variable if needed
182 timeVariable_.clear();
184 timeVariable_ = std::vector<double>(inputTrees.size());
185 for(size_t i = 0; i < inputTrees.size(); ++i) {
186 for(int j = 0; j < 3; ++j) {
187 if(j != 2 or inputTrees[i]->GetNumberOfBlocks() > 2) {
188 auto array = inputTrees[i]->GetBlock(j)->GetFieldData()->GetArray(
189 TimeVariableName.c_str());
190 if(array) {
191 timeVariable_[i] = array->GetTuple1(0);
192 break;
193 }
194 }
195 }
196 }
197 }
198
199 // ------------------------------------------------------------------------------------
200 // --- Call base
201 // ------------------------------------------------------------------------------------
202 printMsg("Call base", debug::Priority::VERBOSE);
203
204 std::vector<MergeTree<dataType>> allMT_T;
205
206 removed = execute<dataType>(intermediateMTrees, emptyTreeDistances, allMT_T);
207 treesNodeCorrMesh = getTreesNodeCorr();
208
209 int indexRemoved = 0;
210 for(size_t i = 0; i < intermediateMTrees.size(); ++i) {
211 if((int)i != removed[indexRemoved]) {
212 MergeTree<double> keyFrame;
213 mergeTreeTemplateToDouble<dataType>(intermediateMTrees[i], keyFrame);
214 keyFrames.emplace_back(keyFrame);
215 } else
216 ++indexRemoved;
217 }
218
219 return 1;
220}
221
222template <class dataType>
224 vtkInformationVector *outputVector,
225 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees) {
226 bool const OutputSegmentation = (inputTrees[0]->GetNumberOfBlocks() == 3);
227 // ------------------------------------------------------------------------------------
228 // --- Create output
229 // ------------------------------------------------------------------------------------
230 auto output_keyFrames = vtkMultiBlockDataSet::GetData(outputVector, 0);
231 auto output_table = vtkTable::GetData(outputVector, 1);
232
233 // ------------------------------------------
234 // --- Trees output
235 // -----------------------------------------
236 std::vector<int> keyFramesIndex;
237 int indexRemoved = 0;
238 for(size_t i = 0; i < inputTrees.size(); ++i)
239 if((int)i != removed[indexRemoved]) {
240 keyFramesIndex.emplace_back(i);
241 } else
242 ++indexRemoved;
243
244 std::vector<vtkUnstructuredGrid *> treesNodesT;
245 std::vector<vtkUnstructuredGrid *> treesArcsT;
246 std::vector<vtkDataSet *> treesSegmentationT;
247 std::vector<std::vector<int>> treesNodeCorrMeshT;
248 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> inputTreesT;
249 for(size_t i = 0; i < keyFramesIndex.size(); ++i) {
250 treesNodesT.emplace_back(treesNodes[keyFramesIndex[i]]);
251 treesArcsT.emplace_back(treesArcs[keyFramesIndex[i]]);
252 treesSegmentationT.emplace_back(treesSegmentation[keyFramesIndex[i]]);
253 treesNodeCorrMeshT.emplace_back(treesNodeCorrMesh[keyFramesIndex[i]]);
254 inputTreesT.emplace_back(inputTrees[keyFramesIndex[i]]);
255 }
256 treesNodes.swap(treesNodesT);
257 treesArcs.swap(treesArcsT);
258 treesSegmentation.swap(treesSegmentationT);
259 treesNodeCorrMesh.swap(treesNodeCorrMeshT);
260 inputTrees.swap(inputTreesT);
261
262 std::vector<MergeTree<dataType>> keyFramesT;
263 mergeTreesDoubleToTemplate<dataType>(keyFrames, keyFramesT);
264 std::vector<FTMTree_MT *> keyFramesTree;
265 mergeTreeToFTMTree<dataType>(keyFramesT, keyFramesTree);
266
267 output_keyFrames->SetNumberOfBlocks((OutputSegmentation ? 3 : 2));
268 vtkSmartPointer<vtkMultiBlockDataSet> const vtkBlockNodes
270 vtkBlockNodes->SetNumberOfBlocks(keyFramesT.size());
271 output_keyFrames->SetBlock(0, vtkBlockNodes);
274 vtkBlockArcs->SetNumberOfBlocks(keyFramesT.size());
275 output_keyFrames->SetBlock(1, vtkBlockArcs);
276 if(OutputSegmentation) {
279 vtkBlockSegs->SetNumberOfBlocks(keyFramesT.size());
280 output_keyFrames->SetBlock(2, vtkBlockSegs);
281 }
282
283 double prevXMax = 0;
284 for(size_t i = 0; i < keyFramesT.size(); ++i) {
285 vtkSmartPointer<vtkUnstructuredGrid> const vtkOutputNode1
287 vtkSmartPointer<vtkUnstructuredGrid> const vtkOutputArc1
289 vtkSmartPointer<vtkUnstructuredGrid> const vtkOutputSegmentation1
291
293 visuMaker.setShiftMode(2); // Line
294 visuMaker.setVtkOutputNode(vtkOutputNode1);
295 visuMaker.setVtkOutputArc(vtkOutputArc1);
296 visuMaker.setVtkOutputSegmentation(vtkOutputSegmentation1);
297 visuMaker.setOutputSegmentation(OutputSegmentation);
298 visuMaker.setTreesNodes(treesNodes);
299 visuMaker.copyPointData(treesNodes[i], treesNodeCorrMesh[i]);
300 visuMaker.setTreesNodeCorrMesh(treesNodeCorrMesh);
301 visuMaker.setTreesSegmentation(treesSegmentation);
302 visuMaker.setPrintTreeId(i);
303 visuMaker.setPrintClusterId(0);
304 visuMaker.setPrevXMaxOffset(prevXMax);
305 visuMaker.setDebugLevel(this->debugLevel_);
306 visuMaker.makeTreesOutput<dataType>(keyFramesTree);
307 prevXMax = visuMaker.getPrevXMax();
308
309 // Field data
310 vtkOutputNode1->GetFieldData()->ShallowCopy(treesNodes[i]->GetFieldData());
311 vtkOutputArc1->GetFieldData()->ShallowCopy(treesArcs[i]->GetFieldData());
312 if(treesSegmentation[i] and OutputSegmentation)
313 vtkOutputSegmentation1->GetFieldData()->ShallowCopy(
314 treesSegmentation[i]->GetFieldData());
315
316 // Construct multiblock
317 vtkMultiBlockDataSet::SafeDownCast(output_keyFrames->GetBlock(0))
318 ->SetBlock(i, vtkOutputNode1);
319 vtkMultiBlockDataSet::SafeDownCast(output_keyFrames->GetBlock(1))
320 ->SetBlock(i, vtkOutputArc1);
321 if(OutputSegmentation)
322 vtkMultiBlockDataSet::SafeDownCast(output_keyFrames->GetBlock(2))
323 ->SetBlock(i, vtkOutputSegmentation1);
324 }
325 // Add input parameters to field data
326 vtkNew<vtkIntArray> vtkAssignmentSolver{};
327 vtkAssignmentSolver->SetName("AssignmentSolver");
328 vtkAssignmentSolver->InsertNextTuple1(assignmentSolverID_);
329 output_keyFrames->GetFieldData()->AddArray(vtkAssignmentSolver);
330
331 // ------------------------------------------
332 // --- Table
333 // ------------------------------------------
334 vtkNew<vtkIntArray> treeIds{};
335 treeIds->SetName("treeID");
336 treeIds->SetNumberOfTuples(removed.size());
337 vtkNew<vtkDoubleArray> coef{};
338 coef->SetName("Alpha");
339 coef->SetNumberOfTuples(removed.size());
340 vtkNew<vtkIntArray> index1Id{};
341 index1Id->SetName("Index1");
342 index1Id->SetNumberOfTuples(removed.size());
343 vtkNew<vtkIntArray> index2Id{};
344 index2Id->SetName("Index2");
345 index2Id->SetNumberOfTuples(removed.size());
346 vtkNew<vtkIntArray> index1IdR{};
347 index1IdR->SetName("Index1_R");
348 index1IdR->SetNumberOfTuples(removed.size());
349 vtkNew<vtkIntArray> index2IdR{};
350 index2IdR->SetName("Index2_R");
351 index2IdR->SetNumberOfTuples(removed.size());
352 int keyFrameCpt = 0;
353 for(size_t i = 0; i < removed.size(); ++i) {
354 while(removed[i] > keyFramesIndex[keyFrameCpt])
355 ++keyFrameCpt;
356 int const index1 = keyFramesIndex[keyFrameCpt - 1];
357 int const index2 = keyFramesIndex[keyFrameCpt];
358 double const alpha = computeAlpha(index1, removed[i], index2);
359 coef->SetTuple1(i, alpha);
360 index1Id->SetTuple1(i, index1);
361 index2Id->SetTuple1(i, index2);
362 treeIds->SetTuple1(i, removed[i]);
363 index1IdR->SetTuple1(i, keyFrameCpt - 1);
364 index2IdR->SetTuple1(i, keyFrameCpt);
365 }
366 output_table->AddColumn(treeIds);
367 output_table->AddColumn(coef);
368 output_table->AddColumn(index1Id);
369 output_table->AddColumn(index2Id);
370 output_table->AddColumn(index1IdR);
371 output_table->AddColumn(index2IdR);
372
373 // ------------------------------------------
374 treesNodes.swap(treesNodesT);
375 treesArcs.swap(treesArcsT);
376 treesSegmentation.swap(treesSegmentationT);
377 treesNodeCorrMesh.swap(treesNodeCorrMeshT);
378 inputTrees.swap(inputTreesT);
379
380 return 1;
381}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
TTK VTK-filter that wraps the ttk::MergeTreeTemporalReduction module.
int run(vtkInformationVector *outputVector, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees)
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
int runOutput(vtkInformationVector *outputVector, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees)
~ttkMergeTreeTemporalReduction() override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int runCompute(std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees)
void setTreesSegmentation(std::vector< vtkDataSet * > &segmentation)
void copyPointData(vtkUnstructuredGrid *treeNodes, std::vector< int > &nodeCorrT)
void setVtkOutputSegmentation(vtkDataSet *vtkSegmentation)
void setTreesNodeCorrMesh(std::vector< std::vector< int > > &nodeCorrMesh)
void makeTreesOutput(FTMTree_MT *tree1)
void setVtkOutputArc(vtkUnstructuredGrid *vtkArc)
void setVtkOutputNode(vtkUnstructuredGrid *vtkNode)
void setTreesNodes(std::vector< vtkUnstructuredGrid * > &nodes)
int debugLevel_
Definition Debug.h:379
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
std::vector< std::vector< int > > getTreesNodeCorr()
double computeAlpha(int index1, int middleIndex, int index2)
std::vector< std::vector< double > > fieldL2_
void loadBlocks(std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, vtkMultiBlockDataSet *blocks)
The Topology ToolKit.
vtkStandardNewMacro(ttkMergeTreeTemporalReduction)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)