Shapeworks Studio  2.1
Shape analysis software suite
itkPSMEntropyMixedEffectsModelFilterTest.cxx
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #include <iostream>
19 #include <sstream>
20 #include "itkImage.h"
21 #include "itkImageFileReader.h"
22 #include "itkPSMEntropyMixedEffectsModelFilter.h"
23 #include "itkPSMProjectReader.h"
24 #include "itkCommand.h"
25 
26 namespace itk{
27 
28  class MyMixedEffectsIterationCommand : public itk::Command
29  {
30  public:
33  typedef Command Superclass;
34  typedef SmartPointer< Self > Pointer;
35  typedef SmartPointer< const Self > ConstPointer;
36 
37  typedef Image<float, 3> ImageType;
38 
41 
43  itkNewMacro(Self);
44 
46  virtual void Execute(Object *caller, const EventObject &)
47  {
49  = static_cast<PSMEntropyMixedEffectsModelFilter<ImageType> *>(caller);
50 
51  // Print every 10 iterations
52  // if (o->GetNumberOfElapsedIterations() % 10 != 0) return;
53 
54  std::cout << "Iteration # " << o->GetNumberOfElapsedIterations() << std::endl;
55  std::cout << " Eigenmode variances: ";
56  for (unsigned int i = 0; i < o->GetShapePCAVariances().size(); i++)
57  {
58  std::cout << o->GetShapePCAVariances()[i] << " ";
59  }
60  std::cout << std::endl;
61  std::cout << " Regularization = " << o->GetRegularizationConstant() << std::endl;
62  }
63  virtual void Execute(const Object *, const EventObject &)
64  {
65  std::cout << "SHOULDN'T BE HERE" << std::endl;
66  }
67 
68  protected:
71  private:
72  MyMixedEffectsIterationCommand(const Self &); //purposely not implemented
73  void operator=(const Self &); //purposely not implemented
74  };
75 
76 } // end namespace itk
77 
79 int itkPSMEntropyMixedEffectsModelFilterTest(int argc, char* argv[] )
80 {
81  bool passed = true;
82  std::string errstring = "";
83  std::string output_path = "";
84  std::string input_path_prefix = "";
85 
86  // Check for proper arguments
87  if (argc < 2)
88  {
89  std::cout << "Wrong number of arguments. \nUse: "
90  << "itkPSMEntropyMixedEffectsModelFilterTest parameter_file [output_path] [input_path]\n"
91  << "See itk::PSMParameterFileReader for documentation on the parameter file format."
92  << std::endl;
93  return EXIT_FAILURE;
94  }
95 
96  if (argc >2)
97  {
98  output_path = std::string(argv[2]);
99  }
100 
101  if (argc >3)
102  {
103  input_path_prefix = std::string(argv[3]);
104  }
105 
106  typedef itk::Image<float, 3> ImageType;
107 
108  try
109  {
110  // Read the project parameters
111  itk::PSMProjectReader::Pointer xmlreader =
112  itk::PSMProjectReader::New();
113  xmlreader->SetFileName(argv[1]);
114  xmlreader->Update();
115 
116  itk::PSMProject::Pointer project = xmlreader->GetOutput();
117 
118  // Create the modeling filter and set up the optimization.
119  itk::PSMEntropyMixedEffectsModelFilter<ImageType>::Pointer P
121 
122  // Setup the Callback function that is executed after each
123  // iteration of the solver.
124  itk::MyMixedEffectsIterationCommand::Pointer mycommand = itk::MyMixedEffectsIterationCommand::New();
125  P->AddObserver(itk::IterationEvent(), mycommand);
126 
127  // Load the distance transforms
128  const std::vector<std::string> &dt_files = project->GetDistanceTransforms();
129  std::cout << "Reading distance transforms ..." << std::endl;
130  for (unsigned int i = 0; i < dt_files.size(); i++)
131  {
132  itk::ImageFileReader<ImageType>::Pointer reader =
133  itk::ImageFileReader<ImageType>::New();
134  reader->SetFileName(input_path_prefix + dt_files[i]);
135  reader->Update();
136 
137  std::cout << " " << (input_path_prefix + dt_files[i]) << std::endl;
138 
139  P->SetInput(i,reader->GetOutput());
140  }
141  std::cout << "Done!" << std::endl;
142 
143  // Load the model initialization. It should be specified as a model with a name.
144  /*const std::vector<std::string> &pt_files = project->GetModel(std::string("initialization"));
145  std::cout << "Reading the initial model correspondences ..." << std::endl;
146  for (unsigned int i = 0; i < pt_files.size(); i++)
147  {
148  // Read the points for this file and add as a list
149  std::vector<itk::PSMEntropyMixedEffectsModelFilter<ImageType>::PointType> c;
150 
151  int counter = 0;
152  // Open the ascii file.
153  std::ifstream in( (input_path_prefix + pt_files[i]).c_str() );
154  if ( !in )
155  {
156  errstring += "Could not open point file for input.";
157  passed = false;
158  break;
159  }
160 
161  // Read all of the points, one point per line.
162  while (in)
163  {
164  itk::PSMEntropyMixedEffectsModelFilter<ImageType>::PointType pt;
165 
166  for (unsigned int d = 0; d < 3; d++)
167  {
168  in >> pt[d];
169  }
170  c.push_back(pt);
171  counter++;
172  }
173  // this algorithm pushes the last point twice
174  c.pop_back();
175  // std::cout << "Read " << counter-1 << " points. " << std::endl;
176  in.close();
177 
178  P->SetInputCorrespondencePoints(i,c);
179 
180  std::cout << " " << pt_files[i] << std::endl;
181  }
182  std::cout << "Done!" << std::endl;*/
183 
184  // Read the explanatory variables (e.g. time)
185  std::vector<double> expl;
186  if (project->HasVariables("explanatory_variables"))
187  {
188  expl = project->GetVariables("explanatory_variables");
189 
190  if (expl.size() < dt_files.size())
191  {
192  errstring += "There are fewer explanatory variables than input files";
193  passed = false;
194  }
195  else // set the explanatory variables
196  {
197  std::cout << "Setting variables" << std::endl;
198  P->SetVariables(expl);
199  }
200  }
201  else
202  {
203  errstring += "No explanatory variables were present for the regression.";
204  passed = false;
205  }
206 
207  // Read some parameters from the file or provide defaults
208  /*double regularization_initial = 100.0f;
209  double regularization_final = 5.0f;
210  double regularization_decayspan = 2000.0f;
211  double tolerance = 1.0e-8;
212  unsigned int maximum_iterations = 20000;
213  unsigned int num_individuals = 1;
214 
215  if ( project->HasOptimizationAttribute("regularization_initial") )
216  regularization_initial = project->GetOptimizationAttribute("regularization_initial");
217  if ( project->HasOptimizationAttribute("regularization_final") )
218  regularization_final = project->GetOptimizationAttribute("regularization_final");
219  if ( project->HasOptimizationAttribute("regularization_decayspan") )
220  regularization_decayspan = project->GetOptimizationAttribute("regularization_decayspan");
221  if ( project->HasOptimizationAttribute("tolerance") )
222  tolerance = project->GetOptimizationAttribute("tolerance");
223  if ( project->HasOptimizationAttribute("maximum_iterations") )
224  maximum_iterations = static_cast<unsigned int>(project->GetOptimizationAttribute("maximum_iterations"));
225  if ( project->HasOptimizationAttribute("num_individuals") )
226  num_individuals = static_cast<unsigned int>(project->GetOptimizationAttribute("num_individuals"));
227 
228  std::cout << "Optimization parameters: " << std::endl;
229  std::cout << " regularization_initial = " << regularization_initial << std::endl;
230  std::cout << " regularization_final = " << regularization_final << std::endl;
231  std::cout << " regularization_decayspan = " << regularization_decayspan << std::endl;
232  std::cout << " tolerance = " << tolerance << std::endl;
233  std::cout << " maximum_iterations = " << maximum_iterations << std::endl;*/
234 
235  // Setting scales to 9 produces 256 points at the output.
236  unsigned int number_of_scales = 6;
237  // Set default parameters for the optimization scales
238  std::vector<double> regularization_initial(number_of_scales);
239  std::vector<double> regularization_final(number_of_scales);
240  std::vector<double> regularization_decayspan(number_of_scales);
241  std::vector<double> tolerance(number_of_scales);
242  std::vector<unsigned int> maximum_iterations(number_of_scales);
243  unsigned int num_individuals = 4;
244 
245  std::cout << "Setting default optimization parameters for scales..." << std::endl;
246  for (unsigned int i = 0; i < number_of_scales; i++)
247  {
248  std::cout << "Scale #" << i << " :" << std::endl;
249  regularization_initial[i] = 10.0;
250  std::cout << " regularization_initial = " << regularization_initial[i] << std::endl;
251  regularization_final[i] = 1.0;
252  std::cout << " regularization_final = " << regularization_final[i] << std::endl;
253  regularization_decayspan[i] = 1000;
254  std::cout << " regularization_decayspan = " << regularization_decayspan[i] << std::endl;
255  tolerance[i] = 0.1;
256  std::cout << " tolerance = " << tolerance[i] << std::endl;
257  maximum_iterations[i] = 20;
258  std::cout << " maximum_iterations = " << maximum_iterations[i] << std::endl;
259  /*if(this->m_Project->HasProcrustes() == true)
260  {
261  // Set the Procrustes interval for each scale
262  unsigned int procrustes_interval = 10;
263  m_ProcrustesInterval[i] = procrustes_interval;
264  std::cout << " procrustes_interval = " << procrustes_interval << std::endl;
265  }*/
266  }
267 
268  // Set the parameters and Run the optimization.
269  P->SetNumberOfScales(number_of_scales);
270  P->SetMaximumNumberOfIterations(maximum_iterations);
271  P->SetRegularizationInitial(regularization_initial);
272  P->SetRegularizationFinal(regularization_final);
273  P->SetRegularizationDecaySpan(regularization_decayspan);
274  P->SetTolerance(tolerance);
275  P->SetNumIndividuals(num_individuals);
276 
277  std::cout << " num_individuals = " << P->GetNumIndividuals() << std::endl;
278 
279  // Read the number of timepoints per individual
280  if (project->HasVariables("timepts_per_individual"))
281  {
282  std::vector<double> tp = project->GetVariables("timepts_per_individual");
283  vnl_vector<int> timepts; timepts.set_size(tp.size());
284  for(int i = 0; i < timepts.size(); i++)
285  timepts[i] = static_cast<int>(tp[i]);
286 
287  if (timepts.size() != num_individuals)
288  {
289  errstring += "Number of individuals and timepts associated dont match!";
290  passed = false;
291  }
292  else // set the timepts variables
293  {
294  std::cout << "Setting variables" << std::endl;
295  P->SetTimePointsPerIndividual(timepts);
296  }
297  }
298  else
299  {
300  errstring += "No timepts variables were present.";
301  passed = false;
302  }
303 
304  // Update parameters
305  P->Update();
306 
307  // if (P->GetNumberOfElapsedIterations() >= maximum_iterations)
308  // {
309  // errstring += "Optimization did not converge based on tolerance criteria.\n";
310  // passed = false;
311  // }
312 
313 
314  const std::vector<std::string> &out_files = project->GetModel(std::string("optimized"));
315  if (out_files.size() != P->GetParticleSystem()->GetNumberOfDomains())
316  {
317  errstring += "Number of output files does not match the number of particle domains (inputs).";
318  passed = false;
319  }
320  // Print out points for domain d
321  if (passed == true)
322  {
323  for (unsigned int d = 0; d < P->GetParticleSystem()->GetNumberOfDomains(); d++)
324  {
325  // Open the output file.
326  std::string fname = output_path + out_files[d];
327  std::ofstream out( fname.c_str() );
328  if ( !out )
329  {
330  errstring += "Could not open point file for output: ";
331  }
332  else
333  {
334  for (unsigned int j = 0; j < P->GetParticleSystem()->GetNumberOfParticles(d); j++)
335  {
336  for (unsigned int i = 0; i < 3; i++)
337  {
338  out << P->GetParticleSystem()->GetPosition(j,d)[i] << " ";
339  }
340  out << std::endl;
341  }
342  }
343  }
344  }
345 
346  std::vector<double>::iterator it_expl;
347  vnl_vector<double> output_intercept_slope;
348  vnl_vector<double>::iterator output_it;
349  double min_expl = *std::min_element(expl.begin(), expl.end());
350  double max_expl = *std::max_element(expl.begin(), expl.end());
351  int step = 4;
352  int file_count = 0;
353  //for(it_expl = expl.begin(); it_expl != expl.end(); ++it_expl)
354  for(int i = 0; i < step; i++)
355  {
356  double value = min_expl + i*((max_expl - min_expl)/(step - 1));
357  output_intercept_slope = P->GetShapeMatrix()->ComputeMean(value);
358  std::ostringstream ss;
359  ss << file_count;
360  std::string fname = output_path + "Intercept+TimexSlope" + "_" + ss.str() + ".lpts";
361  std::ofstream out(fname.c_str());
362  if ( !out )
363  {
364  errstring += "Could not open point file for output: ";
365  }
366  else
367  {
368  int counter = 0;
369  for(output_it = output_intercept_slope.begin(); output_it != output_intercept_slope.end(); ++output_it)
370  {
371  out << *output_it << ' ';
372  counter++;
373  if(counter == 3)
374  {
375  out << std::endl;
376  counter = 0;
377  }
378  }
379  }
380  file_count++;
381  }
382  }
383  catch(itk::ExceptionObject &e)
384  {
385  errstring = "ITK exception with description: " + std::string(e.GetDescription())
386  + std::string("\n at location:") + std::string(e.GetLocation())
387  + std::string("\n in file:") + std::string(e.GetFile());
388  passed = false;
389  }
390  catch(...)
391  {
392  errstring = "Unknown exception thrown";
393  passed = false;
394  }
395 
396  if (passed)
397  {
398  std::cout << "All tests passed" << std::endl;
399  return EXIT_SUCCESS;
400  }
401  else
402  {
403  std::cout << "Test failed with the following error:" << std::endl;
404  std::cout << errstring << std::endl;
405  return EXIT_FAILURE;
406  }
407 }
void SetMaximumNumberOfIterations(const std::vector< unsigned int > &n)
itkTypeMacro(MyMixedEffectsIterationCommand, Command)
void SetNumberOfScales(unsigned int n)
unsigned int GetNumberOfElapsedIterations() const
This class decorates the base PSMEntropyModelFilter class with some additional methods for setting ex...
const std::vector< double > & GetShapePCAVariances() const
void SetRegularizationInitial(const std::vector< double > &v)
void SetInput(const std::string &s, itk::DataObject *o)
virtual void Execute(Object *caller, const EventObject &)
void SetTolerance(const std::vector< double > &v)