Seg3D  2.4
Seg3D is a free volume segmentation and processing tool developed by the NIH Center for Integrative Biomedical Computing at the University of Utah Scientific Computing and Imaging (SCI) Institute.
itkLegendrePolynomialTransform.h
1 /*
2  For more information, please see: http://software.sci.utah.edu
3 
4  The MIT License
5 
6  Copyright (c) 2016 Scientific Computing and Imaging Institute,
7  University of Utah.
8 
9 
10  Permission is hereby granted, free of charge, to any person obtaining a
11  copy of this software and associated documentation files (the "Software"),
12  to deal in the Software without restriction, including without limitation
13  the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  and/or sell copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following conditions:
16 
17  The above copyright notice and this permission notice shall be included
18  in all copies or substantial portions of the Software.
19 
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  DEALINGS IN THE SOFTWARE.
27 */
28 
29 // File : itkLegendrePolynomialTransform.h
30 // Author : Pavel A. Koshevoy
31 // Created : 2006/02/22 15:55
32 // Copyright : (C) 2004-2008 University of Utah
33 // Description : A bivariate centered/normalized Legendre polynomial
34 // transform and helper functions.
35 
36 #ifndef __itkLegendrePolynomialTransform_h
37 #define __itkLegendrePolynomialTransform_h
38 
39 // system includes:
40 #include <iostream>
41 #include <assert.h>
42 
43 // ITK includes:
44 #include <itkTransform.h>
45 #include <itkExceptionObject.h>
46 #include <itkMacro.h>
47 #include <itkImage.h>
48 
49 // local includes:
50 #include <Core/ITKCommon/Transform/itkInverseTransform.h>
51 
52 // VXL includes:
53 #include <vnl/algo/vnl_svd.h>
54 
55 
56 //----------------------------------------------------------------
57 // itk::LegendrePolynomialTransform
58 //
59 // Let
60 // A = (u - uc) / Xmax
61 // B = (v - vc) / Ymax
62 //
63 // where uc, vc correspond to the center of the image expressed in
64 // the coordinate system of the mosaic.
65 //
66 // The transform is defined as
67 // x(u, v) = Xmax * Sa
68 // y(u, v) = Ymax * Sb
69 //
70 // where
71 // Sa = sum(i in [0, N], sum(j in [0, i], a_jk * Pj(A) * Qk(B)));
72 // Sb = sum(i in [0, N], sum(j in [0, i], b_jk * Pj(A) * Qk(B)));
73 //
74 // where k = i - j and (Pj, Qk) are Legendre polynomials
75 // of degree (j, k) respectively.
76 //
77 namespace itk
78 {
79 
80 template < class TScalar = double, unsigned int N = 2 >
82 public Transform<TScalar, 2, 2>
83 {
84 public:
85  // standard typedefs:
87  typedef SmartPointer<Self> Pointer;
88  typedef SmartPointer<const Self> ConstPointer;
89 
90  typedef Transform<TScalar, 2, 2> Superclass;
91 
94  typedef typename Superclass::InverseTransformBaseType InverseTransformBaseType;
95  typedef typename InverseTransformBaseType::Pointer InverseTransformBasePointer;
96 
97  // static constant for the degree of the polynomial:
98  itkStaticConstMacro(Degree, unsigned int, N);
99 
100  // static constant for the number of a_jk (or b_jk) coefficients:
101  itkStaticConstMacro(CoefficientsPerDimension,
102  unsigned int,
103  ((N + 1) * (N + 2)) / 2);
104 
105  // static constant for the length of the parameter vector:
106  itkStaticConstMacro(ParameterVectorLength,
107  unsigned int,
108  (N + 1) * (N + 2));
109 
110  // RTTI:
111  itkTypeMacro(LegendrePolynomialTransform, Transform);
112 
113  // macro for instantiation through the object factory:
114  itkNewMacro(Self);
115 
117  typedef typename Superclass::ScalarType ScalarType;
118 
120  itkStaticConstMacro(InputSpaceDimension, unsigned int, 2);
121  itkStaticConstMacro(OutputSpaceDimension, unsigned int, 2);
122 
124  typedef typename Superclass::NumberOfParametersType NumberOfParametersType;
125 
126  // shortcuts:
127  typedef typename Superclass::ParametersType ParametersType;
128  typedef typename Superclass::JacobianType JacobianType;
129 
130  typedef typename Superclass::InputPointType InputPointType;
131  typedef typename Superclass::OutputPointType OutputPointType;
132 
133  // virtual:
134  virtual OutputPointType TransformPoint(const InputPointType & x) const;
135 
136  // Inverse transformations:
137  // If y = Transform(x), then x = BackTransform(y);
138  // if no mapping from y to x exists, then an exception is thrown.
139  InputPointType BackTransformPoint(const OutputPointType & y) const;
140 
141  // virtual:
142  virtual void SetFixedParameters(const ParametersType & params)
143  { this->m_FixedParameters = params; }
144 
145  // virtual:
146  virtual const ParametersType & GetFixedParameters() const
147  { return this->m_FixedParameters; }
148 
149  // virtual:
150  virtual void SetParameters(const ParametersType & params)
151  { this->m_Parameters = params; }
152 
153  // virtual:
154  virtual const ParametersType & GetParameters() const
155  { return this->m_Parameters; }
156 
157  // virtual:
158  virtual NumberOfParametersType GetNumberOfParameters() const
159  { return ParameterVectorLength; }
160 
161  // virtual:
162 // virtual const JacobianType & GetJacobian(const InputPointType & point) const;
163  virtual void ComputeJacobianWithRespectToParameters( const InputPointType &, JacobianType & ) const;
164 
165  // virtual: return an inverse of this transform.
166  virtual InverseTransformBasePointer GetInverseTransform() const
167  {
168  typedef InverseTransform<Self> InvTransformType;
169  typename InvTransformType::Pointer inv = InvTransformType::New();
170  inv->SetForwardTransform(this);
171  return inv.GetPointer();
172  }
173 
174  // setup the fixed transform parameters:
175  void setup(// image bounding box expressed in the physical space:
176  const double x_min,
177  const double x_max,
178  const double y_min,
179  const double y_max,
180 
181  // normalization parameters:
182  const double Xmax = 0.0,
183  const double Ymax = 0.0)
184  {
185  double & uc_ = this->m_FixedParameters[0];
186  double & vc_ = this->m_FixedParameters[1];
187  double & xmax_ = this->m_FixedParameters[2];
188  double & ymax_ = this->m_FixedParameters[3];
189  double & a00_ = this->m_Parameters[index_a(0, 0)];
190  double & b00_ = this->m_Parameters[index_b(0, 0)];
191 
192  // center of the image:
193  double xc = (x_min + x_max) / 2.0;
194  double yc = (y_min + y_max) / 2.0;
195  uc_ = xc;
196  vc_ = yc;
197 
198  // setup the normalization parameters:
199  if (Xmax != 0.0 && Ymax != 0.0)
200  {
201  xmax_ = Xmax;
202  ymax_ = Ymax;
203  }
204  else
205  {
206  const double w = x_max - x_min;
207  const double h = y_max - y_min;
208 
209  // -1 : 1
210  xmax_ = w / 2.0;
211  ymax_ = h / 2.0;
212  }
213 
214  // setup a00, b00 (local translation parameters):
215  a00_ = xc / xmax_;
216  b00_ = yc / ymax_;
217  }
218 
219  // setup the translation parameters:
220  void setup_translation(// translation is expressed in the physical space:
221  const double tx_Xmax = 0.0,
222  const double ty_Ymax = 0.0)
223  {
224  // incorporate translation into the (uc, vc) fixed parameters:
225  double & uc_ = this->m_FixedParameters[0];
226  double & vc_ = this->m_FixedParameters[1];
227 
228  // FIXME: the signs might be wrong here (20051101):
229  uc_ -= tx_Xmax;
230  vc_ -= ty_Ymax;
231 
232  // FIXME: untested:
233  /*
234  double & a00_ = this->m_Parameters[index_a(0, 0)];
235  double & b00_ = this->m_Parameters[index_b(0, 0)];
236  a00_ -= tx_Xmax / GetXmax();
237  b00_ -= ty_Ymax / GetYmax();
238  */
239  }
240 
241  // helper required for numeric inverse transform calculation;
242  // evaluate F = T(x), J = dT/dx (another Jacobian):
243  void eval(const std::vector<ScalarType> & x,
244  std::vector<ScalarType> & F,
245  std::vector<std::vector<ScalarType> > & J) const;
246 
247  // setup a linear system to solve for the parameters of this
248  // transform such that it maps points uv to xy:
249  void setup_linear_system(const unsigned int start_with_degree,
250  const unsigned int degrees_covered,
251  const std::vector<InputPointType> & uv,
252  const std::vector<OutputPointType> & xy,
253  vnl_matrix<double> & M,
254  vnl_vector<double> & bx,
255  vnl_vector<double> & by) const;
256 
257  // find the polynomial coefficients such that this transform
258  // would map uv to xy:
259  void solve_for_parameters(const unsigned int start_with_degree,
260  const unsigned int degrees_covered,
261  const std::vector<InputPointType> & uv, // mosaic
262  const std::vector<OutputPointType> & xy,// tile
263  ParametersType & params) const;
264 
265  inline void solve_for_parameters(const unsigned int start_with_degree,
266  const unsigned int degrees_covered,
267  const std::vector<InputPointType> & uv,
268  const std::vector<OutputPointType> & xy)
269  {
270  ParametersType params = GetParameters();
271  solve_for_parameters(start_with_degree,
272  degrees_covered,
273  uv,
274  xy,
275  params);
276  SetParameters(params);
277  }
278 
279  // calculate the number of coefficients of a given
280  // degree range (per dimension):
281  inline static unsigned int
282  count_coefficients(const unsigned int start_with_degree,
283  const unsigned int degrees_covered)
284  {
285  return
286  index_a(0, start_with_degree + degrees_covered) -
287  index_a(0, start_with_degree);
288  }
289 
290  // accessors to the warp origin expressed in the mosaic coordinate system:
291  inline const double & GetUc() const
292  { return this->m_FixedParameters[0]; }
293 
294  inline const double & GetVc() const
295  { return this->m_FixedParameters[1]; }
296 
297  // accessors to the normalization parameters Xmax, Ymax:
298  inline const double & GetXmax() const
299  { return this->m_FixedParameters[2]; }
300 
301  inline const double & GetYmax() const
302  { return this->m_FixedParameters[3]; }
303 
304  // generate a mask of shared parameters:
305  static void setup_shared_params_mask(bool shared, std::vector<bool> & mask)
306  {
307  mask.assign(ParameterVectorLength, shared);
308  mask[index_a(0, 0)] = false;
309  mask[index_b(0, 0)] = false;
310  }
311 
312  // Convert the j, k indeces associated with a(j, k) coefficient
313  // into an index that can be used with the parameters array:
314  inline static unsigned int index_a(const unsigned int & j,
315  const unsigned int & k)
316  { return j + ((j + k) * (j + k + 1)) / 2; }
317 
318  inline static unsigned int index_b(const unsigned int & j,
319  const unsigned int & k)
320  { return CoefficientsPerDimension + index_a(j, k); }
321 
322  // virtual: Generate a platform independent name:
323  std::string GetTransformTypeAsString() const
324  {
325  std::string base = Superclass::GetTransformTypeAsString();
326  std::ostringstream name;
327  name << base << '_' << N;
328  return name.str();
329  }
330 
331 protected:
332  LegendrePolynomialTransform();
333 
334  // virtual:
335  void PrintSelf(std::ostream & s, Indent indent) const;
336 
337 private:
338  // disable default copy constructor and assignment operator:
339  LegendrePolynomialTransform(const Self & other);
340  const Self & operator = (const Self & t);
341 
342  // polynomial coefficient accessors:
343  inline const double & a(const unsigned int & j,
344  const unsigned int & k) const
345  { return this->m_Parameters[index_a(j, k)]; }
346 
347  inline const double & b(const unsigned int & j,
348  const unsigned int & k) const
349  { return this->m_Parameters[index_b(j, k)]; }
350 
351 }; // class LegendrePolynomialTransform
352 
353 } // namespace itk
354 
355 
356 #ifndef ITK_MANUAL_INSTANTIATION
357 #include <Core/ITKCommon/Transform/itkLegendrePolynomialTransform.txx>
358 #endif
359 
360 
361 //----------------------------------------------------------------
362 // setup_transform
363 //
364 template <class transform_t>
365 typename transform_t::Pointer
366 setup_transform(const itk::Point<double, 2> & bbox_min,
367  const itk::Point<double, 2> & bbox_max)
368 {
369  double w = bbox_max[0] - bbox_min[0];
370  double h = bbox_max[1] - bbox_min[1];
371  double Umax = w / 2.0;
372  double Vmax = h / 2.0;
373 
374  typename transform_t::Pointer t = transform_t::New();
375  t->setup(bbox_min[0],
376  bbox_max[0],
377  bbox_min[1],
378  bbox_max[1],
379  Umax,
380  Vmax);
381 
382  return t;
383 }
384 
385 
386 //----------------------------------------------------------------
387 // setup_transform
388 //
389 template <class transform_t, class image_t>
390 typename transform_t::Pointer
391 setup_transform(const image_t * image)
392 {
393  typedef typename image_t::IndexType index_t;
394 
395  index_t i00;
396  i00[0] = 0;
397  i00[1] = 0;
398 
399  typename image_t::PointType origin;
400  image->TransformIndexToPhysicalPoint(i00, origin);
401 
402  index_t i11;
403  i11[0] = 1;
404  i11[1] = 1;
405 
406  typename image_t::PointType spacing;
407  image->TransformIndexToPhysicalPoint(i11, spacing);
408  spacing[0] -= origin[0];
409  spacing[1] -= origin[1];
410 
411  typename image_t::SizeType sz =
412  image->GetLargestPossibleRegion().GetSize();
413 
414  typename image_t::PointType bbox_min = origin;
415  typename image_t::PointType bbox_max;
416  bbox_max[0] = bbox_min[0] + spacing[0] * double(sz[0]);
417  bbox_max[1] = bbox_min[1] + spacing[1] * double(sz[1]);
418 
419  return setup_transform<transform_t>(bbox_min, bbox_max);
420 }
421 
422 
423 #endif // __itkLegendrePolynomialTransform_h
Superclass::NumberOfParametersType NumberOfParametersType
Definition: itkLegendrePolynomialTransform.h:124
Superclass::InverseTransformBaseType InverseTransformBaseType
Definition: itkLegendrePolynomialTransform.h:94
Definition: itkNormalizeImageFilterWithMask.h:48
Definition: itkLegendrePolynomialTransform.h:81
Superclass::ScalarType ScalarType
Definition: itkLegendrePolynomialTransform.h:117