23 #include "itkPSMCommandLineClass.h" 24 #include "itkImageFileReader.h" 25 #include "itkImageFileWriter.h" 27 #include "itkPSMImplicitSurfaceImageFilter.h" 28 #include "itkExceptionObject.h" 29 #include "itkDOMNode.h" 30 #include "itkDOMNodeXMLWriter.h" 31 #include "itkTranslationTransform.h" 32 #include "itkImageRegionIteratorWithIndex.h" 33 #include "itkNearestNeighborInterpolateImageFunction.h" 34 #include "itkResampleImageFilter.h" 35 #include "itkChangeInformationImageFilter.h" 36 #include "itkNumericTraits.h" 41 static void RandomGaussian(
double n,
double mean,
double sigma, std::vector<double> & r)
43 double r2, x = 0, y = 0;
44 for(
int i = 0; i < n; i++)
48 while(r2 >= 1.0 || r2 == 0)
50 x = 2.0 *
static_cast<double>(rand()) /
51 static_cast<double>(RAND_MAX) - 1.0;
52 y = 2.0 *
static_cast<double>(rand()) /
53 static_cast<double>(RAND_MAX) - 1.0;
56 r[i] = mean + sigma * y * sqrt(-2.0 * log(r2) / r2);
65 static double Slope(
const std::vector<double>& x,
const std::vector<double>& y)
67 if(x.size() != y.size())
69 std::cerr <<
"Error! Vectors are not the same length." << std::endl;
74 double avgX = std::accumulate(x.begin(), x.end(), 0.0) / n;
75 double avgY = std::accumulate(y.begin(), y.end(), 0.0) / n;
77 double numerator = 0.0;
78 double denominator = 0.0;
80 for(
int i=0; i<n; ++i)
82 numerator += (x[i] - avgX) * (y[i] - avgY);
83 denominator += (x[i] - avgX) * (x[i] - avgX);
88 std::cerr <<
"Error! Divide by zero." << std::endl;
92 double b1 = numerator / denominator;
96 double sumXY = 0.0, sum_squareX = 0.0, sum_squareY = 0.0;
97 for(
int i=0; i<n; i++)
100 sum_squareX += x[i] * x[i];
101 sum_squareY += y[i] * y[i];
104 double r_xy = sumXY / sqrt(sum_squareX * sum_squareY);
105 std::cout <<
"\nCorrelation coefficient = " << r_xy << std::endl;
106 std::cout <<
"Coefficient of determination = " << (r_xy * r_xy) << std::endl;
112 static void Center(itk::Image<float, 2> *input)
114 typedef itk::Image<float, 2> ImageType;
115 ImageType::PixelType m_BackgroundValue = itk::NumericTraits< ImageType::PixelType >::Zero;
117 ImageType::PointType lower;
118 ImageType::PointType upper;
119 ImageType::PointType ul_physical_coords;
120 input->TransformIndexToPhysicalPoint(input->GetBufferedRegion().GetIndex(), lower);
121 input->TransformIndexToPhysicalPoint(input->GetBufferedRegion().GetIndex()
122 + input->GetBufferedRegion().GetSize(), upper);
123 for (
unsigned int i = 0; i < 2; i++)
125 ul_physical_coords[i] = -(lower[i] + upper[i]) / 2.0;
130 input->SetOrigin(ul_physical_coords);
133 itk::ImageRegionIteratorWithIndex<ImageType> oit(input, input->GetBufferedRegion());
136 itk::Array<double> params(2);
139 itk::Point<double, 2> point;
140 for (; ! oit.IsAtEnd(); ++oit)
142 if (oit.Get() != m_BackgroundValue)
145 input->TransformIndexToPhysicalPoint(oit.GetIndex(), point);
146 for (
unsigned int i = 0; i < 2; i++) { params[i] += point[i]; }
152 for (
unsigned int i = 0; i < 2; i++)
154 params[i] = params[i] / count;
158 itk::TranslationTransform<double,2>::Pointer trans
159 = itk::TranslationTransform<double,2>::New();
160 trans->SetParameters(params);
162 itk::NearestNeighborInterpolateImageFunction<ImageType,double>::Pointer
163 interp = itk::NearestNeighborInterpolateImageFunction<ImageType,double>::New();
165 itk::ResampleImageFilter<ImageType, ImageType>::Pointer resampler
166 = itk::ResampleImageFilter<ImageType, ImageType>::New();
167 resampler->SetOutputParametersFromImage(input);
168 resampler->SetTransform(trans);
169 resampler->SetInterpolator(interp);
170 resampler->SetInput(input);
176 static bool abs_compare(
double a,
double b)
178 return (std::abs(a) < std::abs(b));
182 int itkPSMCommandLineClass2DTest(
int argc,
char* argv[] )
184 std::string output_path =
"";
185 std::string input_path_prefix =
"";
186 std::string errstring =
"";
190 std::cout <<
"Wrong number of arguments. \nUse: " 191 <<
"itkPSMCommandLineClass2DTest [output_path] [input_path]\n" 192 <<
"Note that input_path will be prefixed to any file names and paths in the xml parameter file.\n" 199 output_path = std::string(argv[1]);
204 input_path_prefix = std::string(argv[2]);
210 typedef itk::Image< unsigned char, 2 > ImageType;
211 typedef itk::Image<float, 2> DTImageType;
214 ImplicitSurfaceImageFilterType::Pointer implicitSurfaceFilter = ImplicitSurfaceImageFilterType::New();
218 int number_of_ellipses = 10;
224 double sigma_intercept = ((double)rand()) / ((
double)RAND_MAX) * 9.9 + 2.0;
225 std::cout <<
"sigma_intercept: " << sigma_intercept << std::endl;
227 std::vector<double> radius_minor, radius_major;
228 radius_minor.resize(number_of_ellipses);
229 radius_major.resize(number_of_ellipses);
232 itk::RandomGaussian(number_of_ellipses, r1, sigma_intercept, radius_minor);
233 itk::RandomGaussian(number_of_ellipses, r2, sigma_intercept, radius_major);
235 for(
int i=0; i<radius_major.size(); i++)
237 std::cout <<
"Input_R: " << radius_major[i] <<
" Input_r: " << radius_minor[i] << std::endl;
241 itk::DOMNode::Pointer inputDOMObject = itk::DOMNode::New();
242 inputDOMObject->SetName(
"psm_project" );
245 itk::DOMNode::Pointer data_node = itk::DOMNode::New();
246 data_node->SetName(
"data" );
247 inputDOMObject->AddChildAtEnd( data_node );
250 itk::DOMNode::Pointer distance_trans_node = itk::DOMNode::New();
251 distance_trans_node->SetName(
"distance_transforms" );
252 data_node->AddChildAtEnd( distance_trans_node );
255 itk::DOMNode::Pointer model_node = itk::DOMNode::New();
256 model_node->SetName(
"model" );
257 data_node->AddChildAtEnd( model_node );
260 std::string att =
"optimized";
263 model_node->SetAttribute(
"name", att );
266 itk::DOMNode::Pointer opt_node = itk::DOMNode::New();
267 opt_node->SetName(
"optimization" );
268 inputDOMObject->AddChildAtEnd( opt_node );
271 int num_of_scales = 8, reg_ds = 5000, max_iter = 1000;
272 double reg_init = 10.0, reg_final = 2.0, tol = 0.01;
273 fs << itk::ClearContent << num_of_scales;
274 opt_node->SetAttribute(
"number_of_scales", fs );
276 for(
int i=0; i<num_of_scales; i++)
279 itk::DOMNode::Pointer scale_node = itk::DOMNode::New();
280 scale_node->SetName(
"scale" );
281 fs << itk::ClearContent << i;
282 scale_node->SetAttribute(
"number", fs );
283 fs << itk::ClearContent << reg_init;
284 scale_node->SetAttribute(
"regularization_initial", fs );
285 fs << itk::ClearContent << reg_final;
286 scale_node->SetAttribute(
"regularization_final", fs );
287 fs << itk::ClearContent << reg_ds;
288 scale_node->SetAttribute(
"regularization_decayspan", fs );
289 fs << itk::ClearContent << tol;
290 scale_node->SetAttribute(
"tolerance", fs );
291 fs << itk::ClearContent << max_iter;
292 scale_node->SetAttribute(
"maximum_iterations", fs );
294 opt_node->AddChildAtEnd( scale_node );
298 double isosurface_value = 0.5;
301 typedef itk::ImageRegionIteratorWithIndex<ImageType> OutputIteratorType;
303 std::cout <<
"Writing ellipse distance transforms..." << std::endl;
305 for(
int i=0; i<number_of_ellipses; i++)
308 ImageType::Pointer ellipseImage = ImageType::New();
309 ImageType::SizeType regionSize;
313 ImageType::IndexType regionIndex;
317 ImageType::RegionType region;
318 region.SetSize(regionSize);
319 region.SetIndex(regionIndex);
321 ImageType::SpacingType spacing;
324 ellipseImage->SetSpacing( spacing );
325 ellipseImage->SetRegions(region);
326 ellipseImage->Allocate();
328 ellipseImage->FillBuffer(0);
330 double r = radius_minor[i];
331 double R = radius_major[i];
333 OutputIteratorType it( ellipseImage, ellipseImage->GetRequestedRegion() );
336 ImageType::IndexType index;
338 for(
int y=-r; y<=r; y++)
340 for(
int x=-R; x<=R; x++)
342 if(x*x*r*r + y*y*R*R <= r*r*R*R)
346 it.SetIndex( index );
347 it.Set( itk::NumericTraits<ImageType::PixelType>::max() );
353 implicitSurfaceFilter->SetSmoothingSigma(sigma);
354 implicitSurfaceFilter->SetIsosurfaceValue(isosurface_value);
355 implicitSurfaceFilter->SetInput(ellipseImage);
356 implicitSurfaceFilter->Update();
359 itk::Center(implicitSurfaceFilter->GetOutput());
361 std::string str =
"ellipse";
362 typedef itk::ImageFileWriter< DTImageType > WriterType;
363 WriterType::Pointer writer = WriterType::New();
364 std::ostringstream ss;
366 std::string iname = output_path + str +
"_DT_Test" + ss.str() +
".nrrd";
367 writer->SetFileName( iname.c_str() );
368 writer->SetInput( implicitSurfaceFilter->GetOutput() );
373 distance_trans_node->AddTextChildAtEnd( iname );
376 std::string opt_name = str +
"_" + ss.str() +
"_optimized.lpts";
377 model_node->AddTextChildAtEnd( opt_name );
382 std::string outputXMLFileName =
"PSMCommandLineClass2DTest.xml";
383 std::string projectFileName = output_path + outputXMLFileName;
384 itk::DOMNodeXMLWriter::Pointer writer_xml = itk::DOMNodeXMLWriter::New();
385 writer_xml->SetInput( inputDOMObject );
386 writer_xml->SetFileName( projectFileName.c_str() );
387 writer_xml->Update();
392 psmClass->
Run(
"PSMCommandLineClass2DTest.xml", output_path, output_path );
394 CommandLineClassType::EntropyModelFilterType::Pointer filter = psmClass->GetPSMFilter();
396 std::vector<double> output_x_coord;
397 std::vector<double> output_y_coord;
398 std::vector<double> output_radius_minor;
399 std::vector<double> output_radius_major;
401 for (
unsigned int d=0; d<filter->GetParticleSystem()->GetNumberOfDomains(); d++)
403 for (
unsigned int ind=0; ind<filter->GetParticleSystem()->GetNumberOfParticles(d); ind++)
405 output_x_coord.push_back( filter->GetParticleSystem()->GetPosition(ind,d)[0] );
406 output_y_coord.push_back( filter->GetParticleSystem()->GetPosition(ind,d)[1] );
409 output_radius_minor.push_back( std::abs(*std::max_element(output_y_coord.begin(), output_y_coord.end(), abs_compare)) );
410 output_radius_major.push_back( std::abs(*std::max_element(output_x_coord.begin(), output_x_coord.end(), abs_compare)) );
411 output_x_coord.clear();
412 output_y_coord.clear();
415 std::cout <<
"\nR: major ellipse radius r: minor ellipse radius" << std::endl;
416 for(
int i=0; i<radius_major.size(); i++)
418 std::cout <<
"Input_R: " << radius_major[i] <<
" Input_r: " << radius_minor[i] << std::endl;
421 std::cout <<
"\nInput R_mean = " << r2 << std::endl;
422 std::cout <<
"Input R_std_dev = " << sigma_intercept << std::endl;
423 std::cout <<
"Input r_mean = " << r1 << std::endl;
424 std::cout <<
"Input r_std_dev = " << sigma_intercept << std::endl;
427 double sl = itk::Slope(radius_major, radius_minor);
428 std::cout <<
"Regression line slope at input = " << sl <<
"\n" << std::endl;
430 for(
int i=0; i<output_radius_minor.size(); i++)
432 std::cout <<
"Output_R: " << output_radius_major[i] <<
" Output_r: " << output_radius_minor[i] << std::endl;
436 double mean_R_output = std::accumulate(output_radius_major.begin(), output_radius_major.end(), 0.0) / number_of_ellipses;
437 double mean_r_output = std::accumulate(output_radius_minor.begin(), output_radius_minor.end(), 0.0) / number_of_ellipses;
439 double sq_sum_R = std::inner_product(output_radius_major.begin(), output_radius_major.end(), output_radius_major.begin(), 0.0);
440 double stdev_R = std::sqrt((sq_sum_R / output_radius_major.size()) - (mean_R_output * mean_R_output) );
442 std::cout <<
"\nOutput R_mean = " << mean_R_output << std::endl;
443 std::cout <<
"Output R_std_dev = " << stdev_R << std::endl;
445 double sq_sum_r = std::inner_product(output_radius_minor.begin(), output_radius_minor.end(), output_radius_minor.begin(), 0.0);
446 double stdev_r = std::sqrt((sq_sum_r / output_radius_minor.size()) - (mean_r_output * mean_r_output) );
448 std::cout <<
"Output r_mean = " << mean_r_output << std::endl;
449 std::cout <<
"Output r_std_dev = " << stdev_r << std::endl;
451 sl = itk::Slope(output_radius_major, output_radius_minor);
452 std::cout <<
"Regression line slope for output = " << sl <<
"\n" << std::endl;
455 catch(itk::ExceptionObject &e)
457 std::cerr <<
"ITK exception with description: " << e.GetDescription()
458 <<
"\n at location:" << e.GetLocation()
459 <<
"\n in file:" << e.GetFile() << std::endl;
465 errstring =
"Unknown exception thrown";
This filter generates an antialiased and smoothed signed distance transform from the input label map ...
void Run(const char *fname, std::string input_path_prefix, std::string output_path)
This class provides a command line tool to run the Particle Shape Modeling. It runs the optimization ...