19 #include <tclap/CmdLine.h> 22 #include <vtkSmartPointer.h> 23 #include <vtkPolyData.h> 24 #include <vtkMultiThreader.h> 25 #include <vtkPolyDataCollection.h> 26 #include <vtkTransformCollection.h> 29 #include <milxModel.h> 31 using namespace TCLAP;
33 typedef std::vector< std::string >::iterator stringiterator;
36 enum operations {none = 0, convert, duplicate, cat, split, scale, decimate, smooth, laplacian, thresholdscalars, clip, flip, diffscalars, copyscalars, diffscalarspairs, statscalars, removescalars, mse, procrustes, icp};
71 int main(
int argc,
char *argv[])
75 milx::PrintInfo(
"--------------------------------------------------------");
80 milx::PrintInfo(
"Australian e-Health Research Centre, CSIRO, Australia.");
81 milx::PrintInfo(
"--------------------------------------------------------\n");
85 CmdLine cmd(
"A diagnostic tool for models/surface operations",
' ',
milx::NumberToString(milx::Version));
88 ValueArg<size_t> threadsArg(
"",
"threads",
"Set he number of global threads to use.",
false,
milx::NumberOfProcessors(),
"Threads");
89 ValueArg<std::string> outputArg(
"o",
"output",
"Output Surface",
false,
"result.vtk",
"Output");
90 ValueArg<std::string> prefixArg(
"p",
"prefix",
"Output prefix for multiple output",
false,
"surface_",
"Output Prefix");
91 ValueArg<std::string> outputFormatArg(
"",
"outputformat",
"Specify the default output format for multiple outputs (vtk, vtp, ply, stl, default: same as input)",
false,
"vtk",
"Output format");
93 ValueArg<float> decimateArg(
"d",
"decimate",
"Decimate all the meshes provided using the Quadric Decimate algorithm with decimation factor.",
false, 0.5,
"Decimate");
94 ValueArg<float> smoothArg(
"",
"smooth",
"Smooth all the meshes provided using the Windowed Sinc Algorithm with iterations.",
false, 18,
"Smooth");
95 ValueArg<float> laplacianArg(
"",
"laplacian",
"Smooth all the meshes provided using the Laplacian Algorithm with iterations.",
false, 18,
"Laplacian");
96 ValueArg<float> scaleArg(
"s",
"scale",
"Scale the coordinates of the points by scale.",
false, 0.9,
"Scale");
97 ValueArg<float> thresholdAboveArg(
"",
"thresholdabove",
"Thresold scalars above value.",
false, 0.0,
"Above");
98 ValueArg<float> thresholdBelowArg(
"",
"thresholdbelow",
"Thresold scalars below value.",
false, 0.0,
"Below");
99 ValueArg<float> clipArg(
"",
"clip",
"Clip model based on scalars value (keeping only parts with value).",
false, 1.0,
"Clip");
100 MultiArg<std::string> componentsArg(
"",
"component",
"Surface is a component of the surfaces.",
false,
"Component");
102 std::vector<size_t> axesAllowed;
103 axesAllowed.push_back(0);
104 axesAllowed.push_back(1);
105 axesAllowed.push_back(2);
106 ValuesConstraint<size_t> allowedAxesVals( axesAllowed );
107 ValueArg<size_t> flipArg(
"f",
"flip",
"Flip the meshes in the axis provided (0: x-axis, 1: y-axis, 2: z-axis).",
false, 0, &allowedAxesVals);
109 SwitchArg partitionArg(
"",
"partitionList",
"Partition the list of surfaces provided into two for operating on one vs the other",
false);
111 SwitchArg duplicateArg(
"",
"duplicate",
"Simply open and save the input file(s). Supports single (-o) or multiple (-p) input.",
false);
112 SwitchArg convertArg(
"c",
"convert",
"Convert the model from the current format to the one given at output (from file extension). Supports single (-o) or multiple (-p) input.",
false);
113 SwitchArg concatenateArg(
"",
"cat",
"Concatenate N surfaces into single mesh with filename provided.",
false);
114 SwitchArg colourConcatenateArg(
"",
"colourcat",
"Concatenate N surfaces into single mesh with filename provided and colour them.",
false);
115 SwitchArg splitArg(
"",
"split",
"Split each surface given components.",
false);
116 SwitchArg diffScalarArg(
"",
"scalardiff",
"Compute the differences in Scalars to the first mesh in list.",
false);
117 SwitchArg statsScalarArg(
"",
"scalarstats",
"Compute statistics of scalars (mean, variance etc. per point) output mesh with stats as arrays.",
false);
118 SwitchArg removeScalarArg(
"",
"scalarremove",
"Remove the scalars.",
false);
119 SwitchArg copyScalarArg(
"",
"scalarcopy",
"Copy the Scalars from first mesh to all others while removing existing ones.",
false);
120 SwitchArg mseArg(
"",
"mse",
"Mean Squared Error of Points in models.",
false);
121 SwitchArg procrustesArg(
"",
"procrustes",
"Similarity alignment of surfaces assuming points have correspondence. Use --rigid if rigid alignment is required.",
false);
122 SwitchArg rigidArg(
"",
"rigid",
"Rigid alignment of surfaces assuming points have correspondence. Use with procrustes or other registration arguments.",
false);
123 SwitchArg icpArg(
"",
"icp",
"Iterative Closest Points alignment of surfaces assuming points don't have correspondence. Last surface in list is used as the reference 'fixed' surface.",
false);
124 SwitchArg saveTransformsArg(
"",
"savetransforms",
"Save the transformation matrix after surface alignment. For use with --icp",
false);
127 UnlabeledMultiArg<std::string> multinames(
"surfaces",
"Surfaces to operate on",
true,
"Surfaces");
130 cmd.add( threadsArg );
131 cmd.add( multinames );
133 cmd.add( outputArg );
134 cmd.add( prefixArg );
135 cmd.add( outputFormatArg );
136 cmd.add( componentsArg );
138 cmd.add( partitionArg );
139 cmd.add( saveTransformsArg );
143 std::vector<Arg*> xorlist;
144 xorlist.push_back(&duplicateArg);
145 xorlist.push_back(&convertArg);
146 xorlist.push_back(&concatenateArg);
147 xorlist.push_back(&colourConcatenateArg);
148 xorlist.push_back(&splitArg);
149 xorlist.push_back(&scaleArg);
150 xorlist.push_back(&decimateArg);
151 xorlist.push_back(&smoothArg);
152 xorlist.push_back(&laplacianArg);
153 xorlist.push_back(&diffScalarArg);
154 xorlist.push_back(&statsScalarArg);
155 xorlist.push_back(&removeScalarArg);
156 xorlist.push_back(©ScalarArg);
157 xorlist.push_back(&mseArg);
158 xorlist.push_back(&procrustesArg);
159 xorlist.push_back(&icpArg);
160 xorlist.push_back(&thresholdAboveArg);
161 xorlist.push_back(&thresholdBelowArg);
162 xorlist.push_back(&clipArg);
163 xorlist.push_back(&flipArg);
167 cmd.parse( argc, argv );
170 const size_t threads = threadsArg.getValue();
172 std::vector<std::string> filenames = multinames.getValue();
174 std::string outputName = outputArg.getValue();
175 const std::string prefixName = prefixArg.getValue();
176 const float decimateFactor = decimateArg.getValue();
177 const float scaleFactor = scaleArg.getValue();
178 const float smoothIterations = smoothArg.getValue();
179 const float laplacianIterations = laplacianArg.getValue();
180 float thresholdAbove = thresholdAboveArg.getValue();
181 float thresholdBelow = thresholdBelowArg.getValue();
182 float clipValue = clipArg.getValue();
183 size_t flipAxis = flipArg.getValue();
184 std::vector<std::string> componentNames = componentsArg.getValue();
187 vtkMultiThreader::SetGlobalDefaultNumberOfThreads(threads);
191 operations operation = none;
192 bool componentsValid =
false;
193 if(duplicateArg.isSet())
197 operation = duplicate;
199 if(convertArg.isSet())
205 if(concatenateArg.isSet() || colourConcatenateArg.isSet())
217 if(componentsArg.isSet())
219 if(!splitArg.isSet())
221 milx::PrintError(
"Components Argument Error: One or more of the operations");
227 for(stringiterator name = componentNames.begin(); name != componentNames.end(); name ++)
228 std::cout << *name <<
", ";
229 std::cout << std::endl;
234 if(!componentsArg.isSet())
236 milx::PrintError(
"Split Argument Error: Components of the given surfaces must be set.");
238 milx::PrintError(
"Set components via the component argument as many times as needed.");
243 componentsValid =
true;
248 milx::PrintInfo(
"Scaling coordinates of each point in the surfaces: ");
251 if(smoothArg.isSet())
257 if(laplacianArg.isSet())
261 operation = laplacian;
263 if(decimateArg.isSet())
267 operation = decimate;
269 if(thresholdAboveArg.isSet() || thresholdBelowArg.isSet())
271 if(!prefixArg.isSet())
273 milx::PrintError(
"Threshold Argument Error: Output Prefix (-p) must be provided.");
277 if(thresholdAboveArg.isSet() && !thresholdBelowArg.isSet())
279 thresholdBelow = -std::numeric_limits<float>::max();
281 else if(!thresholdAboveArg.isSet() && thresholdBelowArg.isSet())
283 thresholdAbove = std::numeric_limits<float>::max();
285 std::cout <<
"Threshold Above Value: " << thresholdAbove << std::endl;
286 std::cout <<
"Threshold Below Value: " << thresholdBelow << std::endl;
289 operation = thresholdscalars;
297 if(diffScalarArg.isSet())
301 operation = diffscalars;
309 if(statsScalarArg.isSet())
313 operation = statscalars;
315 if(removeScalarArg.isSet())
319 operation = removescalars;
321 if(copyScalarArg.isSet())
323 if(filenames.size() == 1)
325 milx::PrintError(
"Argument Error: Need another filename to copy from mesh A to mesh B.");
328 else if(filenames.size() == 2 && !outputArg.isSet())
330 milx::PrintError(
"Argument Error: Use Output (-o) for copying from mesh A to mesh B.");
334 else if(filenames.size() > 2 && !prefixArg.isSet())
336 milx::PrintError(
"Argument Error: Output Prefix (-p) must be provided for more than 2 meshes.");
343 operation = copyscalars;
345 if(rigidArg.isSet() && (!procrustesArg.isSet() && !icpArg.isSet()))
348 milx::PrintError(
"Rigid option can only be used with the Procrustes/ICP option");
351 if(procrustesArg.isSet())
353 if(!prefixArg.isSet())
355 milx::PrintError(
"Procrustes Argument Error: Output Prefix (-p) must be provided.");
361 operation = procrustes;
365 if(!prefixArg.isSet())
367 milx::PrintError(
"ICP Argument Error: Output Prefix (-p) must be provided.");
377 std::vector<std::string> altfilenames;
378 if(partitionArg.isSet())
380 for(
size_t j = filenames.size()/2; j < filenames.size(); j ++)
381 altfilenames.push_back( filenames[j] );
383 for(
size_t j = 0; j < altfilenames.size(); j ++)
384 filenames.pop_back();
387 std::cout <<
"Total Surfaces: " << filenames.size() << std::endl;
388 for(stringiterator name = filenames.begin(); name != filenames.end(); name ++)
389 std::cout << *name <<
", ";
390 std::cout << std::endl;
392 if(partitionArg.isSet())
394 if(!diffScalarArg.isSet())
396 milx::PrintError(
"Partitioning list of surfaces is only supported with the following operations:");
400 if(!prefixArg.isSet())
402 milx::PrintError(
"Partition Surfaces List Argument Error: Output Prefix (-p) must be provided.");
408 milx::PrintInfo(
"Operation will be applied in conjuction with surfaces: ");
409 std::cout <<
"Total Surfaces: " << altfilenames.size() << std::endl;
410 for(stringiterator name = altfilenames.begin(); name != altfilenames.end(); name ++)
411 std::cout << *name <<
", ";
412 std::cout << std::endl;
414 if(diffScalarArg.isSet())
415 operation = diffscalarspairs;
420 std::cerr <<
"Reading Surfaces... ";
421 vtkSmartPointer<vtkPolyDataCollection> collection;
424 std::cerr <<
"Done" << std::endl;
425 std::cout <<
"Read " << collection->GetNumberOfItems() <<
" models" << std::endl;
427 vtkSmartPointer<vtkPolyDataCollection> altcollection;
428 if(partitionArg.isSet())
430 std::cerr <<
"Reading Alterate Surfaces... ";
433 std::cerr <<
"Done" << std::endl;
436 vtkSmartPointer<vtkPolyDataCollection> components;
437 if(componentsArg.isSet() && componentsValid)
439 std::cerr <<
"Reading Components... ";
442 std::cerr <<
"Done" << std::endl;
445 if(colourConcatenateArg.isSet())
448 collection->InitTraversal();
449 for(
int j = 0; j < collection->GetNumberOfItems(); j ++)
451 vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
452 const size_t numPoints = mesh->GetNumberOfPoints();
454 vtkSmartPointer<vtkFloatArray> weights = vtkSmartPointer<vtkFloatArray>::New();
455 weights->SetNumberOfComponents(1);
456 weights->SetNumberOfTuples(numPoints);
457 weights->FillComponent(0, count);
459 mesh->GetPointData()->SetScalars(weights);
466 vtkSmartPointer<vtkTransformCollection> transformCollection = vtkSmartPointer<vtkTransformCollection>::New();
471 bool outputRequired =
true;
472 bool multiOutputRequired =
false;
473 bool standardOperation =
false;
474 vtkSmartPointer<vtkPolyDataCollection> resultCollections;
476 if (collection->GetNumberOfItems() == 1)
478 outputRequired =
true;
479 multiOutputRequired =
false;
483 outputRequired =
false;
484 multiOutputRequired =
true;
487 std::cerr <<
"Applying... ";
491 standardOperation =
true;
495 standardOperation =
true;
500 outputRequired =
true;
501 multiOutputRequired =
false;
506 outputRequired =
false;
511 std::vector< vtkSmartPointer<vtkPolyDataCollection> > splitCollections;
517 typedef std::vector< vtkSmartPointer<vtkPolyDataCollection> >::iterator iterator;
518 stringiterator name = filenames.begin();
519 for(iterator surfaces = splitCollections.begin();
520 surfaces != splitCollections.end();
521 surfaces ++, name ++)
523 std::vector<std::string> splitNames;
525 std::string splitName = prefixName + milx::File::GetBaseName(*name) +
"_";
527 for(stringiterator componentname = componentNames.begin(); componentname != componentNames.end(); componentname ++)
529 splitNames.push_back(splitName + milx::File::GetBaseName(*componentname) +
"." + ext);
530 milx::PrintInfo(
"Wrote " + splitName + milx::File::GetBaseName(*componentname) +
"." + ext);
537 outputRequired =
false;
538 multiOutputRequired =
false;
544 standardOperation =
true;
550 standardOperation =
true;
556 standardOperation =
true;
562 standardOperation =
true;
565 case thresholdscalars:
568 standardOperation =
true;
574 standardOperation =
true;
579 bool xAxis =
false, yAxis =
false, zAxis =
false;
582 else if(flipAxis == 1)
588 standardOperation =
true;
594 outputRequired =
true;
595 multiOutputRequired =
false;
598 case diffscalarspairs:
599 resultCollections = vtkSmartPointer<vtkPolyDataCollection>::New();
602 standardOperation =
true;
603 collection = resultCollections;
608 outputRequired =
true;
609 multiOutputRequired =
false;
615 standardOperation =
true;
621 if(filenames.size() == 2)
623 outputRequired =
true;
624 multiOutputRequired =
false;
625 collection->InitTraversal();
626 collection->GetNextItem();
627 Model.
SetInput(collection->GetNextItem());
630 standardOperation =
true;
638 outputName = prefixName +
"_mean." + ext;
639 outputRequired =
true;
640 multiOutputRequired =
true;
647 standardOperation =
true;
653 std::cerr <<
"Done" << std::endl;
655 if (collection->GetNumberOfItems() == 1 && standardOperation)
657 collection->InitTraversal();
658 Model.
Result() = collection->GetNextItem();
668 if(multiOutputRequired)
670 if(collection->GetNumberOfItems() > 0)
672 const int N = collection->GetNumberOfItems();
675 std::vector<std::string> names;
678 for(stringiterator filename = filenames.begin(); filename != filenames.end() && n < N; filename ++, n ++)
681 if (outputFormatArg.isSet()) {
682 ext = outputFormatArg.getValue();
687 names.push_back(prefixName + milx::File::GetBaseName(*filename) +
"." + ext);
688 milx::PrintInfo(
"Will be writing " + prefixName + milx::File::GetBaseName(*filename) +
"." + ext);
694 if (saveTransformsArg.isSet() && transformCollection->GetNumberOfItems() == collection->GetNumberOfItems())
696 const std::string ext =
"trsf.gz";
697 std::vector<std::string> tnames;
699 for(stringiterator name = names.begin(); name != names.end() && n < N; name ++, n++)
701 tnames.push_back(milx::File::StripFileExtension(*name) +
"." + ext);
void ScalarStatisticsCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the statistics (min, max, variance etc.) of the scalars over the collection assuming the mes...
void ConcatenateCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Concatenates all the models in the collection together into one model.
void ScaleCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType scale)
Scales the coordinates of each point in all the models in the collection.
void PrintError(const std::string msg)
Displays a generic msg to standard error with carriage return.
void DecimateCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType factor)
Decimates all points in all the models in the collection using the Quadric algorithm algorithm...
This program Animates image slices and animates surfaces in the model view for creating movies...
static bool OpenModelCollection(std::vector< std::string > filenames, vtkSmartPointer< vtkPolyDataCollection > &collection)
Opens model files, which can be a VTK XML, Legacy VTK PolyData File (i.e. either a *...
void SplitCollection(vtkSmartPointer< vtkPolyDataCollection > collection, vtkSmartPointer< vtkPolyDataCollection > components, std::vector< vtkSmartPointer< vtkPolyDataCollection > > &splitCollections)
Splits each of the models in the collection into a collection of models.
vtkSmartPointer< vtkPolyData > & Result()
Returns the current model, i.e. the result of the latest operation.
vtkSmartPointer< vtkPolyDataCollection > ProcrustesAlignCollection(vtkSmartPointer< vtkPolyDataCollection > collection, bool rigid=false)
Aligns the collection to the mean mesh (computed internally) of the collection assuming the meshes ha...
void SmoothCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const size_t iterations)
Smoothes all points in all the models in the collection using the Windowed Sinc algorithm.
static bool SaveTransformCollection(std::vector< std::string > filenames, vtkSmartPointer< vtkTransformCollection > collection, const bool ITK=false)
Saves transform files, which can be VTK .trsf or ITK from a collection.
static bool SaveModelCollection(std::vector< std::string > filenames, vtkSmartPointer< vtkPolyDataCollection > collection, const bool binary=false)
Saves model files, which can be a VTK XML, Legacy VTK PolyData File (i.e. either a *...
void SetInput(vtkSmartPointer< vtkPolyData > model)
Assigns the input model to class.
void ScalarThresholdCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType aboveVal, const coordinateType belowVal)
Computes the Threshold of scalar values of meshes in place over the collection wrt the first mesh ass...
static bool SaveModel(const std::string filename, vtkSmartPointer< vtkPolyData > data, const bool binary=false)
Saves a model as a file, which can be a VTK XML or Legacy VTK PolyData File (i.e. either a *...
void PrintInfo(const std::string msg)
Displays a generic msg to standard output with carriage return.
std::string NumberToString(double num, unsigned zeroPad=0)
Number to string converter.
double MeanSquaredErrorCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the MSE of all models in collection accummulatively.
void ScalarCopyCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Copies the scalars over the collection (from the first mesh) assuming the meshes have the same number...
void LaplacianCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const size_t iterations)
Smoothes all points in all the models in the collection using the Laplacian algorithm.
Represents a model (i.e. a model with cells and scalar values) and their common operations. Also allows batch operations on collection of models.
void ScalarRemoveCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Removes the scalars over the collection assuming the meshes have the same number of points...
void FlipCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const bool xAxis, const bool yAxis, const bool zAxis)
Flips all points in all the models in the collection using the axis provided.
static std::string GetFileExtension(const std::string &filename)
Returns the file extension (in lower case) of the given filename.
unsigned NumberOfProcessors()
Number of processors or cores on the machine.
int main(int argc, char *argv[])
void ClipCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType aboveVal, const coordinateType belowVal)
Computes the Clipping of models via the Threshold of scalar values in place over the collection...
void ScalarDifferenceCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the difference in scalars cummulatively over the collection wrt the first mesh assuming the ...
vtkSmartPointer< vtkPolyDataCollection > IterativeClosestPointsAlignCollection(vtkSmartPointer< vtkPolyDataCollection > collection, bool rigid=false, vtkSmartPointer< vtkTransformCollection > tCollection=0)
Aligns the collection to the mean mesh (computed internally) of the collection without needing corres...