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