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.
itkGridTransform.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 #ifndef __itkGridTransform_h
30 #define __itkGridTransform_h
31 
32 // system includes:
33 #include <math.h>
34 #include <iostream>
35 
36 // ITK includes:
37 #include <itkTransform.h>
38 #include <itkExceptionObject.h>
39 #include <itkIdentityTransform.h>
40 #include <itkMacro.h>
41 #include <itkImage.h>
42 
43 // local includes:
44 #include <Core/ITKCommon/Transform/itkDiscontinuousTransform.h>
45 
46 
47 //----------------------------------------------------------------
48 // itk::GridTransform
49 //
50 namespace itk
51 {
52 
53 class GridTransform : public Transform<double, 2, 2>
54 {
55 public:
56  // standard typedefs:
57  typedef GridTransform Self;
58  typedef SmartPointer<Self> Pointer;
59  typedef SmartPointer<const Self> ConstPointer;
60 
61  typedef Transform<double, 2, 2> Superclass;
62 
65  typedef Superclass::InverseTransformBaseType InverseTransformBaseType;
66  typedef InverseTransformBaseType::Pointer InverseTransformBasePointer;
67 
68  // RTTI:
69  itkTypeMacro(GridTransform, Transform);
70 
71  // macro for instantiation through the object factory:
72  itkNewMacro(Self);
73 
75  typedef double ScalarType;
76 
78  itkStaticConstMacro(InputSpaceDimension, unsigned int, 2);
79  itkStaticConstMacro(OutputSpaceDimension, unsigned int, 2);
80 
81  // shortcuts:
82  typedef Superclass::ParametersType ParametersType;
83  typedef Superclass::JacobianType JacobianType;
84 
85  typedef Superclass::InputPointType InputPointType;
86  typedef Superclass::OutputPointType OutputPointType;
87 
88  // virtual:
89  virtual OutputPointType TransformPoint(const InputPointType & x) const
90  {
91  OutputPointType y;
92  if (is_inverse())
93  {
94  pnt2d_t uv;
95  uv[0] = (x[0] - transform_.tile_min_[0]) / transform_.tile_ext_[0];
96  uv[1] = (x[1] - transform_.tile_min_[1]) / transform_.tile_ext_[1];
97  transform_.transform_inv(uv, y);
98  }
99  else
100  {
101  transform_.transform(x, y);
102  y[0] *= transform_.tile_ext_[0];
103  y[1] *= transform_.tile_ext_[1];
104  y[0] += transform_.tile_min_[0];
105  y[1] += transform_.tile_min_[1];
106  }
107 
108  // ITK does not handle NaN numbers:
109  if (y[0] != y[0])
110  {
111  y[0] = std::numeric_limits<double>::max();
112  y[1] = y[0];
113  }
114 
115  return y;
116  }
117 
118  // Inverse transformations:
119  // If y = Transform(x), then x = BackTransform(y);
120  // if no mapping from y to x exists, then an exception is thrown.
121  InputPointType BackTransformPoint(const OutputPointType & y) const
122  {
123  InputPointType x;
124  if (is_inverse())
125  {
126  transform_.transform(y, x);
127  x[0] *= transform_.tile_ext_[0];
128  x[1] *= transform_.tile_ext_[1];
129  x[0] += transform_.tile_min_[0];
130  x[1] += transform_.tile_min_[1];
131  }
132  else
133  {
134  pnt2d_t uv;
135  uv[0] = (y[0] - transform_.tile_min_[0]) / transform_.tile_ext_[0];
136  uv[1] = (y[1] - transform_.tile_min_[1]) / transform_.tile_ext_[1];
137  transform_.transform_inv(uv, x);
138  }
139 
140  // ITK does not handle NaN numbers:
141  if (x[0] != x[0])
142  {
143  x[0] = std::numeric_limits<double>::max();
144  x[1] = x[0];
145  }
146 
147  return x;
148  }
149 
150  // virtual:
151  virtual void SetFixedParameters(const ParametersType & params)
152  { this->m_FixedParameters = params; }
153 
154  // virtual:
155  virtual const ParametersType & GetFixedParameters() const
156  {
157  ParametersType params = this->m_FixedParameters;
158 
159  params[1] = transform_.rows_;
160  params[2] = transform_.cols_;
161  params[3] = transform_.tile_min_[0];
162  params[4] = transform_.tile_min_[1];
163  params[5] = transform_.tile_ext_[0];
164  params[6] = transform_.tile_ext_[1];
165 
166  // update the parameters vector:
167  GridTransform * fake = const_cast<GridTransform *>(this);
168  fake->m_FixedParameters = params;
169  return this->m_FixedParameters;
170  }
171 
172  // virtual:
173  virtual void SetParameters(const ParametersType & params)
174  {
175  this->m_Parameters = params;
176 
177  size_t rows = int(this->m_FixedParameters[1]);
178  size_t cols = int(this->m_FixedParameters[2]);
179 
180  pnt2d_t tile_min;
181  tile_min[0] = this->m_FixedParameters[3];
182  tile_min[1] = this->m_FixedParameters[4];
183 
184  pnt2d_t tile_max;
185  tile_max[0] = tile_min[0] + this->m_FixedParameters[5];
186  tile_max[1] = tile_min[1] + this->m_FixedParameters[6];
187 
188  std::vector<pnt2d_t> xy((rows + 1) * (cols + 1));
189 
190  unsigned int num_points = xy.size();
191 // assert(2 * num_points == params.size());
192  if (2 * num_points != params.size())
193  {
194  itkExceptionMacro(<< "xy size does not match number of parameters");
195  }
196 
197  for (unsigned int i = 0; i < num_points; i++)
198  {
199  xy[i][0] = params[i * 2];
200  xy[i][1] = params[i * 2 + 1];
201  }
202 
203  transform_.setup(rows,
204  cols,
205  tile_min,
206  tile_max,
207  xy);
208  }
209 
210  // virtual:
211  virtual const ParametersType & GetParameters() const
212  {
213  ParametersType params(GetNumberOfParameters());
214  unsigned int num_pts = params.size() / 2;
215  unsigned int num_cols = (transform_.cols_ + 1);
216  for (unsigned int i = 0; i < num_pts; i++)
217  {
218  unsigned int row = i / num_cols;
219  unsigned int col = i % num_cols;
220 
221  const pnt2d_t & xy = transform_.vertex(row, col).xy_;
222  unsigned int idx = 2 * i;
223  params[idx] = xy[0];
224  params[idx + 1] = xy[1];
225  }
226 
227  // update the parameters vector:
228  GridTransform * fake = const_cast<GridTransform *>(this);
229  fake->m_Parameters = params;
230  return this->m_Parameters;
231  }
232 
233  // virtual:
234  virtual NumberOfParametersType GetNumberOfParameters(void) const
235  { return 2 * transform_.grid_.mesh_.size(); }
236 
237  // virtual: return an inverse of this transform.
238  virtual InverseTransformBasePointer GetInverseTransform() const
239  {
240  GridTransform::Pointer inv = GridTransform::New();
241  inv->setup(transform_, !is_inverse());
242  return inv.GetPointer();
243  }
244 
245  // setup the transform:
246  void setup(const the_grid_transform_t & transform,
247  const bool & is_inverse = false)
248  {
249  transform_ = transform;
250  GetParameters();
251  GetFixedParameters();
252 // this->m_Jacobian.SetSize(2, GetNumberOfParameters());
253  this->m_FixedParameters[0] = is_inverse ? 1.0 : 0.0;
254  }
255 
256  // inverse transform flag check:
257  inline bool is_inverse() const
258  { return this->m_FixedParameters[0] != 0.0; }
259 
260 // // virtual:
261 // virtual
262 // const JacobianType &
263 // GetJacobian(const InputPointType & point) const
264 // {
265 // // FIXME: 20061227 -- this function was written and not tested:
266 //
267 // // these scales are necessary to account for the fact that
268 // // the_grid_transform_t expects uv in the [0,1]x[0,1] range,
269 // // where as we remap it into the image tile physical coordinates
270 // // according to tile_min_ and tile_ext_:
271 // double Su = transform_.tile_ext_[0];
272 // double Sv = transform_.tile_ext_[1];
273 //
274 // unsigned int idx[3];
275 // double jac[12];
276 // this->m_Jacobian.SetSize(2, GetNumberOfParameters());
277 // this->m_Jacobian.Fill(0.0);
278 // if (transform_.jacobian(point, idx, jac))
279 // {
280 // for (unsigned int i = 0; i < 3; i++)
281 // {
282 // unsigned int addr = idx[i] * 2;
283 // this->m_Jacobian(0, addr) = Su * jac[i * 2];
284 // this->m_Jacobian(0, addr + 1) = Su * jac[i * 2 + 1];
285 // this->m_Jacobian(1, addr) = Sv * jac[i * 2 + 6];
286 // this->m_Jacobian(1, addr + 1) = Sv * jac[i * 2 + 7];
287 // }
288 // }
289 //
290 // return this->m_Jacobian;
291 // }
292 
293  virtual
294  void
295  ComputeJacobianWithRespectToParameters( const InputPointType &point, JacobianType &jacobian ) const
296  {
297  // FIXME: 20061227 -- this function was written and not tested:
298 
299  // these scales are necessary to account for the fact that
300  // the_grid_transform_t expects uv in the [0,1]x[0,1] range,
301  // where as we remap it into the image tile physical coordinates
302  // according to tile_min_ and tile_ext_:
303  double Su = transform_.tile_ext_[0];
304  double Sv = transform_.tile_ext_[1];
305 
306  unsigned int idx[3];
307  double jac[12];
308  jacobian.SetSize(2, GetNumberOfParameters());
309  jacobian.Fill(0.0);
310  if (transform_.jacobian(point, idx, jac))
311  {
312  for (unsigned int i = 0; i < 3; i++)
313  {
314  unsigned int addr = idx[i] * 2;
315  jacobian(0, addr) = Su * jac[i * 2];
316  jacobian(0, addr + 1) = Su * jac[i * 2 + 1];
317  jacobian(1, addr) = Sv * jac[i * 2 + 6];
318  jacobian(1, addr + 1) = Sv * jac[i * 2 + 7];
319  }
320  }
321  }
322 
323 protected:
324  GridTransform():
325 // Superclass(2, 0)
326  Superclass(0)
327  {
328  this->m_FixedParameters.SetSize(7);
329 
330  // initialize the inverse flag:
331  this->m_FixedParameters[0] = 0.0;
332 
333  // grid size:
334  this->m_FixedParameters[1] = 0.0;
335  this->m_FixedParameters[2] = 0.0;
336 
337  // tile bbox:
338  this->m_FixedParameters[3] = std::numeric_limits<double>::max();
339  this->m_FixedParameters[4] = this->m_FixedParameters[3];
340  this->m_FixedParameters[5] = -(this->m_FixedParameters[3]);
341  this->m_FixedParameters[6] = -(this->m_FixedParameters[3]);
342  }
343 
344 private:
345  // disable default copy constructor and assignment operator:
346  GridTransform(const Self & other);
347  const Self & operator = (const Self & t);
348 
349 public:
350  // the actual transform:
351  the_grid_transform_t transform_;
352 
353 }; // class GridTransform
354 
355 } // namespace itk
356 
357 
358 #endif // __itkGridTransform_h
itkStaticConstMacro(InputSpaceDimension, unsigned int, 2)
Definition: itkNormalizeImageFilterWithMask.h:48
Superclass::InverseTransformBaseType InverseTransformBaseType
Definition: itkGridTransform.h:65
Definition: itkGridTransform.h:53
Definition: itkDiscontinuousTransform.h:186
double ScalarType
Definition: itkGridTransform.h:75