Libs/Mesh/ParticleBasedSurfaceReconstruction_InputParams.h
Classes
Name | |
---|---|
class | InputParams |
Source code
#ifndef INPUTPARAMS_H
#define INPUTPARAMS_H
#include "tinyxml.h"
#include "Utils.h"
#include <Libs/Utils/StringUtils.h>
#include <sys/stat.h> // for mkdir
#ifdef WIN32
#include <direct.h>
#endif
class InputParams
{
public:
// correspondence model parameters
int number_of_particles ;
bool do_procrustes;
bool do_procrustes_scaling;
const float pi = std::acos(-1.0);
// where to save output files:
// WarpToMeanSpace: the template (DT, dense and sparse shapes) and warped DT
// WarpToSubjectSpace: the warped dense mean to each individual subject
// MoveAlongPCAModes: the warped dense mean to samples from the shape space sampled along individual pca modes
// WarpToMeanSpaceWithPreviewMeshQC: same as WarpToMeanSpace but the resulting mesh is QCed via preview mesh processing tools
std::string out_prefix;
std::string out_path;
// used in case of WarpToSubjectSpace or MoveAlongPCAModes
std::string mean_prefix;
std::string mean_path;
std::string template_dense_mesh;
std::string template_sparse_points;
std::string template_good_indices;
bool use_template_mesh;
// parameters for mesh QC via preview
bool qcFixWinding;
bool qcDoLaplacianSmoothingBeforeDecimation;
bool qcDoLaplacianSmoothingAfterDecimation;
float qcSmoothingLambda;
int qcSmoothingIterations;
float qcDecimationPercentage;
float K;
// this is number of particles to be used to build the warp, their choice will be based on the ranking if point files are provided -->
// otherwise, the choice will be random
int number_of_correspondences_in_warp;
// attributes that can be used to help quantifying the quality of each correspondence, e.g. sulcal depth for the brains
int number_of_attributes;
std::string attributes_prefix;
std::vector< std::string> attribute_labels;
// isosurface extraction parameters
float levelsetValue ;
float targetReduction;
float featureAngle ;
int lsSmootherIterations;
int meshSmootherIterations;
bool preserveTopology ;
bool display ;
float glyph_radius ;
float maximum_variance_captured;
int mode_index;
int number_of_modes;
float maximum_std_dev;
int number_of_samples_per_mode;
float normalAngle;
bool usePairwiseNormalsDifferencesForGoodBad;
bool use_tps_transform;
bool use_bspline_interpolation;
// input files
std::vector< std::string > localPointsFilenames;
std::vector< std::string > worldPointsFilenames; // optional, wpts from shapeworks (procrustes in this tool need more debuging)
std::vector< std::string > distanceTransformFilenames;
std::vector< std::string > attributeFilenames;
//std::vector< std::string > landmarksFilenames;
InputParams(){
// correspondence model parameters
number_of_particles = -1;
do_procrustes = true;
do_procrustes_scaling = true;
number_of_correspondences_in_warp = -1;
number_of_attributes = 0;
K = -1;
// isosurface parameters
levelsetValue = 0.5; // to make sure no holes (don't use strict 0.0 since this will isosurface a mean distance transform - i.e. having non-zero isosurface)
targetReduction = 0.01; // percentage to decimate
featureAngle = 30; // in degrees
lsSmootherIterations = 1; // number of iterations to smooth the levelset
meshSmootherIterations = 1; // number of iterations to smooth the initial mesh
preserveTopology = true;
qcFixWinding = true;
qcDoLaplacianSmoothingBeforeDecimation = true;
qcDoLaplacianSmoothingAfterDecimation = true;
qcSmoothingLambda = 0.5;
qcSmoothingIterations = 1;
qcDecimationPercentage = 0.5;
display = true;
glyph_radius = 1;
maximum_variance_captured = 0.95;
number_of_modes = -1; // max variance captured will be used to determine number of modes
mode_index = -1; // if this is given >=0 and < nSamples, this particular mode will be generated
maximum_std_dev = 2.0;
number_of_samples_per_mode = 10;
normalAngle = pi/2.0;
usePairwiseNormalsDifferencesForGoodBad = false;
use_tps_transform = false;
use_bspline_interpolation = false;
localPointsFilenames.clear();
worldPointsFilenames.clear();
distanceTransformFilenames.clear();
attribute_labels.clear();
use_template_mesh = false;
}
int readParams(char* infilename, int mode ) // 0 - WarpToMeanSpace, 1 - WarpToSubjectSpace, 2 - MoveAlongPCAModes, 3 - WarpToMeanSpaceWithPreviewMeshQC
{
// read parameters
TiXmlDocument doc(infilename);
bool loadOkay = doc.LoadFile();
if (loadOkay)
{
TiXmlHandle docHandle( &doc );
TiXmlElement *elem;
std::istringstream inputsBuffer;
std::string filename("/dev/null\0");
// reconstruction template parameters
elem = docHandle.FirstChild( "use_tps_transform" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? use_tps_transform = true : use_tps_transform = false;
}
elem = docHandle.FirstChild( "use_bspline_interpolation" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? use_bspline_interpolation = true : use_bspline_interpolation = false;
}
if (mode == 0 || mode == 3 || mode == 1) // WarpToMeanSpace or WarpToMeanSpaceWithPreviewMeshQC or WarpToSubject
{
// Compile the list of input files.
elem = docHandle.FirstChild( "local_point_files" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
while (inputsBuffer >> filename)
{
localPointsFilenames.push_back(filename);
}
inputsBuffer.clear();
inputsBuffer.str("");
}
else
{
std::cerr << "No local points to process!" << std::endl;
return EXIT_FAILURE;
}
}
if (mode == 0 || mode == 3 || mode == 2) // WarpToMeanSpace or WarpToMeanSpaceWithPreviewMeshQC or MoveAlongPCAModes
{
elem = docHandle.FirstChild( "world_point_files" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
while (inputsBuffer >> filename)
{
worldPointsFilenames.push_back(filename);
}
inputsBuffer.clear();
inputsBuffer.str("");
}
else
{
std::cerr << "No world points (wpts) to process .. procrustes will be used for the given lpts" << std::endl;
}
}
if (mode == 0 || mode == 3) // WarpToMeanSpace or WarpToMeanSpaceWithPreviewMeshQC
{
elem = docHandle.FirstChild( "distance_transform_files" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
while (inputsBuffer >> filename)
{
distanceTransformFilenames.push_back(filename);
}
inputsBuffer.clear();
inputsBuffer.str("");
}
else
{
std::cerr << "No distance transforms to process!" << std::endl;
return EXIT_FAILURE;
}
//Praful
elem = docHandle.FirstChild("number_of_clusters").Element();
if (elem)
{
K = atof(elem->GetText());
}
else
{
std::cout<<"Warning: All shapes will be used to generate mean distance transform (could be slower)!"<<std::endl;
}
}
elem = docHandle.FirstChild( "out_prefix" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> out_prefix;
inputsBuffer.clear();
inputsBuffer.str("");
}
else
{
std::cerr << "No out_prefix provided ...!" << std::endl;
return EXIT_FAILURE;
}
if (mode == 1 || mode == 2) // WarpToSubjectSpace or MoveAlongPCAModes
{
elem = docHandle.FirstChild( "mean_prefix" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> mean_prefix;
inputsBuffer.clear();
inputsBuffer.str("");
use_template_mesh = false;
}
else
{
bool dense_given = false;
bool sparse_given = false;
elem = docHandle.FirstChild( "template_dense_mesh" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> template_dense_mesh;
inputsBuffer.clear();
inputsBuffer.str("");
dense_given = true;
}
elem = docHandle.FirstChild( "template_sparse_points" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> template_sparse_points;
inputsBuffer.clear();
inputsBuffer.str("");
sparse_given = true;
}
elem = docHandle.FirstChild( "template_good_indices" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> template_good_indices;
inputsBuffer.clear();
inputsBuffer.str("");
}
if(dense_given && sparse_given)
{
std::cout << "No mean_prefix provide, the given template shape will be used ...!" << std::endl;
use_template_mesh = true;
}
else
{
std::cerr << "Neither a mean_prefix nor a template mesh (sparse and dense) is provided ...!" << std::endl;
return EXIT_FAILURE;
}
}
}
elem = docHandle.FirstChild( "number_of_particles" ).Element();
if (elem)
{
number_of_particles = atoi( elem->GetText() );
}
elem = docHandle.FirstChild( "number_of_correspondences_in_warp" ).Element();
if (elem)
{
number_of_correspondences_in_warp = atoi( elem->GetText() );
}
else
{
std::cerr << "No number_of_correspondences_in_warp provided, all good correspondences will be used to build the warp ...!" << std::endl;
}
if (mode == 0 || mode == 3) // WarpToMeanSpace or WarpToMeanSpaceWithPreviewMeshQC
{
elem = docHandle.FirstChild( "number_of_attributes" ).Element();
if (elem)
{
number_of_attributes = atoi( elem->GetText() );
}
elem = docHandle.FirstChild( "attributes_prefix" ).Element();
if (elem)
{
inputsBuffer.str(elem->GetText());
inputsBuffer >> attributes_prefix;
inputsBuffer.clear();
inputsBuffer.str("");
}
else
{
if(number_of_attributes > 0)
{
std::cerr << "No attributes_prefix provided ...!" << std::endl;
return EXIT_FAILURE;
}
}
elem = docHandle.FirstChild( "attribute_labels" ).Element();
if (!elem)
{
if(number_of_attributes > 0)
{
std::cerr << "No attribute files have been specified" << std::endl;
return EXIT_FAILURE;
}
}
else
{
inputsBuffer.str(elem->GetText());
while (inputsBuffer >> filename)
{
attribute_labels.push_back(filename);
}
inputsBuffer.clear();
inputsBuffer.str("");
}
elem = docHandle.FirstChild( "do_procrustes" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? do_procrustes = true : do_procrustes = false;
}
elem = docHandle.FirstChild( "do_procrustes_scaling" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? do_procrustes_scaling = true : do_procrustes_scaling = false;
}
// read levelset value if given
elem = docHandle.FirstChild( "levelsetValue" ).Element();
if (elem)
{
levelsetValue = atof( elem->GetText() );
}
// read target reduction value if given
elem = docHandle.FirstChild( "targetReduction" ).Element();
if (elem)
{
targetReduction = atof( elem->GetText() );
}
// read feature angle value if given
elem = docHandle.FirstChild( "featureAngle" ).Element();
if (elem)
{
featureAngle = atof( elem->GetText() );
}
// read normal angle value if given
elem = docHandle.FirstChild( "normalAngle" ).Element();
if (elem)
{
normalAngle = atof( elem->GetText() )*pi/180.0;
}
elem = docHandle.FirstChild( "usePairwiseNormalsDifferencesForGoodBad" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? usePairwiseNormalsDifferencesForGoodBad = true : usePairwiseNormalsDifferencesForGoodBad = false;
}
// read number of iterations for levelset smoother if given
elem = docHandle.FirstChild( "lsSmootherIterations" ).Element();
if (elem)
{
lsSmootherIterations = atoi( elem->GetText() );
}
// read number of iterations for mesh smoother if given
elem = docHandle.FirstChild( "meshSmootherIterations" ).Element();
if (elem)
{
meshSmootherIterations = atoi( elem->GetText() );
}
// check if topology changes are allowed
elem = docHandle.FirstChild( "preserveTopology" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? preserveTopology = true : preserveTopology = false;
}
}
// check if we want to display the computed template
elem = docHandle.FirstChild( "display" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? display = true : display = false;
}
elem = docHandle.FirstChild( "glyph_radius" ).Element();
if (elem)
{
glyph_radius = atof( elem->GetText() );
}
if (mode == 0 || mode == 3) // WarpToMeanSpace or WarpToMeanSpaceWithPreviewMeshQC
{
// Make sure lists are the same size.
if (localPointsFilenames.size() != distanceTransformFilenames.size())
{
std::cerr << "local points file list size does not match distance transform file list size!" << std::endl;
return EXIT_FAILURE;
}
}
if (mode == 2) // MoveAlongPCAModes
{
elem = docHandle.FirstChild( "maximum_variance_captured" ).Element();
if (elem)
{
maximum_variance_captured = atof( elem->GetText() );
}
elem = docHandle.FirstChild( "maximum_std_dev" ).Element();
if (elem)
{
maximum_std_dev = atof( elem->GetText() );
}
elem = docHandle.FirstChild( "number_of_samples_per_mode" ).Element();
if (elem)
{
number_of_samples_per_mode = atoi( elem->GetText() );
}
elem = docHandle.FirstChild( "mode_index" ).Element();
if (elem)
{
mode_index = atoi( elem->GetText() );
}
elem = docHandle.FirstChild( "number_of_modes" ).Element();
if (elem)
{
number_of_modes = atoi( elem->GetText() );
}
}
if (mode == 3) // WarpToMeanSpaceWithPreviewMeshQC
{
elem = docHandle.FirstChild( "qcFixWinding" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? qcFixWinding = true : qcFixWinding = false;
}
elem = docHandle.FirstChild( "qcDoLaplacianSmoothingBeforeDecimation" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? qcDoLaplacianSmoothingBeforeDecimation = true : qcDoLaplacianSmoothingBeforeDecimation = false;
}
elem = docHandle.FirstChild( "qcDoLaplacianSmoothingAfterDecimation" ).Element();
if (elem)
{
atoi(elem->GetText()) > 0 ? qcDoLaplacianSmoothingAfterDecimation = true : qcDoLaplacianSmoothingAfterDecimation = false;
}
elem = docHandle.FirstChild( "qcSmoothingLambda" ).Element();
if (elem)
{
qcSmoothingLambda = atof( elem->GetText() );
}
elem = docHandle.FirstChild( "qcSmoothingIterations" ).Element();
if (elem)
{
qcSmoothingIterations = atoi( elem->GetText() );
}
elem = docHandle.FirstChild( "qcDecimationPercentage" ).Element();
if (elem)
{
qcDecimationPercentage = atof( elem->GetText() );
}
}
if (number_of_particles <= 0)
{
std::cerr << "Invalide number of particles, it should be > 0 ...!" << std::endl;
return EXIT_FAILURE;
}
if(number_of_correspondences_in_warp <= 0)
number_of_correspondences_in_warp = number_of_particles;
if(number_of_correspondences_in_warp > number_of_particles)
{
number_of_correspondences_in_warp = number_of_particles;
std::cerr << "number_of_correspondences_in_warp exceeds the total number of particles, all correspondences will be used to build the warp ...!" << std::endl;
}
// create the directory where the results should be, in case it is not there
out_path = shapeworks::StringUtils::getPath(out_prefix);
// if(use_tps_transform)
// out_path = out_path + "TPS";
// else
// out_path = out_path + "RBF";
out_prefix = out_path + "/" + shapeworks::StringUtils::getFilename(out_prefix);
// remove the output if it already exists to remove any historical results, just in case
// std::string cmdStr = "rm -rf " + out_path;
// std::system(cmdStr.c_str());
#ifdef WIN32
int mkdirStatus = _mkdir(out_path.c_str());
#else
int mkdirStatus = mkdir(out_path.c_str(), S_IRWXU);
#endif
// copy the current param file to the output to keep track of the parameters that generated this output
std::string cmdStr = "cp " + std::string(infilename) + " " + out_path;
std::system(cmdStr.c_str());
if (mode == 1 || mode == 2) // WarpToSubjectSpace or MoveAlongPCAModes
{
// create the directory where the results should be, in case it is not there
mean_path = shapeworks::StringUtils::getPath(mean_prefix) + "/" ;
// if(use_tps_transform)
// mean_path = mean_path + "TPS";
// else
// mean_path = mean_path + "RBF";
mean_prefix = mean_path + shapeworks::StringUtils::getFilename(mean_prefix);
}
}
return EXIT_SUCCESS;
}
};
#endif // INPUTPARAMS_H
Updated on 2022-03-31 at 09:51:19 -0600