Transformation.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2008-2015 Imperial College London
5  * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
6  * Copyright 2013-2015 Andreas Schuh
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef MIRTK_Transformation_H
22 #define MIRTK_Transformation_H
23 
24 #include "mirtk/TransformationConfig.h" // for client code
25 
26 #include "mirtk/Observable.h"
27 
28 #include "mirtk/Status.h"
29 #include "mirtk/BSpline.h"
30 #include "mirtk/Cfstream.h"
31 #include "mirtk/Indent.h"
32 #include "mirtk/PointSet.h"
33 #include "mirtk/Matrix.h"
34 #include "mirtk/Vector3D.h"
35 #include "mirtk/GenericImage.h"
36 
37 #include "mirtk/TransformationType.h"
38 #include "mirtk/TransformationJacobian.h"
39 
40 
41 namespace mirtk {
42 
43 
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 // Abstract transformation class
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 /**
50  * Abstract base class for general transformations.
51  *
52  * This is the abstract base class which defines a common interface for all
53  * transformations. Each derived class has to implement at least the abstract
54  * methods and some of the virtual ones. Most other methods call these virtual
55  * methods and should not be required to be overwritten in subclasses.
56  *
57  * The second time argument to the interface methods corresponds to the time
58  * of the untransformed source image. It is only considered by some 3D+t
59  * transformations, in particular those which parameterize the transformation
60  * using a non-stationary velocity field.
61  */
62 class Transformation : public Observable
63 {
64  mirtkAbstractMacro(Transformation);
65 
66 public:
67 
68  /// Type of transformation parameter value
69  typedef double DOFValue;
70 
71  /// Type of transforamtion parameter status
72  typedef Status DOFStatus;
73 
74 protected:
75 
76  /// Number of transformation parameters
78 
79  /// Value of each transformation parameter
80  DOFValue *_Param;
81 
82  /// Status of each transformation parameter (Active or Passive)
83  DOFStatus *_Status;
84 
85  // ---------------------------------------------------------------------------
86  // Construction/Destruction
87 
88  /// Default constructor
89  Transformation(int = 0);
90 
91  /// Copy constructor
93 
94  /// Copy constructor
95  Transformation(const Transformation &, int);
96 
97  /// Initialize transformation parameters
98  void InitializeDOFs(int);
99 
100  /// Copy transformation parameters (DoFs) and their status
101  void InitializeDOFs(const Transformation &, int = -1);
102 
103 public:
104 
105  /// Static constructor. This function returns a pointer to a concrete
106  /// new transformation of the specified type (e.g., TRANSFORMATION_RIGID).
108  static Transformation *New(unsigned int type) {
109  return New(static_cast<TransformationType>(type));
110  }
111 
112  /// Static constructor. This function returns a pointer to a concrete
113  /// transformation by copying the transformation passed to it.
114  static Transformation *New(const Transformation *);
115 
116  /// Static constructor. This function returns a pointer to a concrete
117  /// transformation by reading the transformation parameters from a file
118  /// and creating the appropriate transformation.
119  static Transformation *New(const char *);
120 
121  /// Default destructor.
122  virtual ~Transformation();
123 
124  // ---------------------------------------------------------------------------
125  // Transformation parameters (DoFs)
126 
127  /// Copy active transformation parameters (DoFs) from given
128  /// transformation if possible and return \c false, otherwise
129  virtual bool CopyFrom(const Transformation *);
130 
131  /// Get number of transformation parameters
132  virtual int NumberOfDOFs() const;
133 
134  /// Get number of active transformation parameters
135  int NumberOfActiveDOFs() const;
136 
137  /// Get number of passive transformation parameters
138  int NumberOfPassiveDOFs() const;
139 
140  /// Get norm of the gradient vector
141  virtual double DOFGradientNorm(const double *) const;
142 
143  /// Put value of transformation parameter
144  virtual void Put(int, double);
145 
146  /// Put values of transformation parameters
147  virtual void Put(const DOFValue *);
148 
149  /// Add change to transformation parameters
150  virtual void Add(const DOFValue *);
151 
152  /// Update transformation parameters given parametric gradient
153  virtual double Update(const DOFValue *);
154 
155  /// Get value of transformation parameter
156  virtual double Get(int) const;
157 
158  /// Get values of transformation parameters
159  virtual void Get(DOFValue *) const;
160 
161  /// Put status of transformation parameter
162  virtual void PutStatus(int, DOFStatus);
163 
164  /// Get status of transformation parameter
165  virtual DOFStatus GetStatus(int) const;
166 
167  /// Checks whether transformation depends on the same vector of parameters
168  virtual bool HasSameDOFsAs(const Transformation *) const;
169 
170  /// Checks whether the transformation is an identity mapping
171  virtual bool IsIdentity() const;
172 
173  /// Gets the spatial bounding box for a transformation parameter in image coordinates.
174  /// The last parameter specifies what fraction of the bounding box to return.
175  /// The default is 1 which equals 100% of the bounding box.
176  virtual bool DOFBoundingBox(const Image *, int, int &, int &, int &,
177  int &, int &, int &, double = 1) const;
178 
179  /// Reset transformation
180  virtual void Reset();
181 
182  // ---------------------------------------------------------------------------
183  // Approximation
184 
185  /// Evaluates RMS error of transformation compared to another
186  double EvaluateRMSError(const ImageAttributes &, const Transformation *) const;
187 
188  /// Evaluates RMS error of transformation compared to given displacement field
189  ///
190  /// This overloaded version of EvaluateRMSError is recommended for displacement
191  /// fields defined on a regular lattice. It does not require memory for the
192  /// explicit storage of the locations of each displacement vector. Moreover,
193  /// if this transformation requires the caching of the displacements, the other
194  /// overloads are either very slow or cannot be used.
195  double EvaluateRMSError(const ImageAttributes &, double *, double *) const;
196 
197  /// Evaluates RMS error of transformation compared to given displacement field
198  ///
199  /// This overloaded version of EvaluateRMSError is recommended for displacement
200  /// fields defined on a regular lattice. It does not require memory for the
201  /// explicit storage of the locations of each displacement vector. Moreover,
202  /// if this transformation requires the caching of the displacements, the other
203  /// overloads are either very slow or cannot be used.
204  double EvaluateRMSError(const ImageAttributes &, double *, double *, double *) const;
205 
206  /// Evaluates RMS error of transformation compared to displacement field
207  double EvaluateRMSError(const double *, const double *, const double *, double,
208  double *, double *, double *, int no) const;
209 
210  /// Evaluates RMS error of transformation compared to given displacement field
211  double EvaluateRMSError(const double *, const double *, const double *, const double *,
212  double *, double *, double *, int no) const;
213 
214  /// Approximate another transformation and return approximation error
215  virtual double Approximate(const ImageAttributes &, const Transformation *,
216  int = 1, double = .0);
217 
218  /// Approximate displacements: This function takes a set of points and a set
219  /// of displacements and finds a transformation which approximates these
220  /// displacements. After approximation, the displacements are replaced by the
221  /// residual displacement errors at the points.
222  virtual double Approximate(GenericImage<double> &, int = 1, double = .0);
223 
224  /// Approximate displacements: This function takes a set of points and a set
225  /// of displacements and finds a transformation which approximates these
226  /// displacements. After approximation, the displacements are replaced by the
227  /// residual displacement errors at the points.
228  virtual double Approximate(const ImageAttributes &, double *, double *, double *,
229  int = 1, double = .0);
230 
231  /// Approximate displacements: This function takes a set of points and a set
232  /// of displacements and finds a transformation which approximates these
233  /// displacements. After approximation, the displacements are replaced by the
234  /// residual displacement errors at the points.
235  virtual double Approximate(const double *, const double *, const double *,
236  double *, double *, double *, int,
237  int = 1, double = .0);
238 
239  /// Approximate displacements: This function takes a set of points and a set
240  /// of displacements and finds a transformation which approximates these
241  /// displacements. After approximation, the displacements are replaced by the
242  /// residual displacement errors at the points.
243  virtual double Approximate(const double *, const double *, const double *, const double *,
244  double *, double *, double *, int,
245  int = 1, double = .0);
246 
247  /// Approximate another transformation and return approximation error
248  virtual double ApproximateAsNew(const ImageAttributes &, const Transformation *,
249  int = 1, double = .0);
250 
251  /// Approximate displacements: This function takes a set of points and a set
252  /// of displacements and finds a !new! transformation which approximates these
253  /// displacements. After approximation, the displacements are replaced by the
254  /// residual displacement errors at the points.
255  virtual double ApproximateAsNew(GenericImage<double> &, int = 1, double = .0);
256 
257  /// Approximate displacements: This function takes a set of points and a set
258  /// of displacements and finds a !new! transformation which approximates these
259  /// displacements. After approximation, the displacements are replaced by the
260  /// residual displacement errors at the points.
261  virtual double ApproximateAsNew(const ImageAttributes &, double *, double *, double *,
262  int = 1, double = .0);
263 
264  /// Approximate displacements: This function takes a set of points and a set
265  /// of displacements and finds a !new! transformation which approximates these
266  /// displacements. After approximation, the displacements are replaced by the
267  /// residual displacement errors at the points.
268  virtual double ApproximateAsNew(const double *, const double *, const double *,
269  double *, double *, double *, int,
270  int = 1, double = .0);
271 
272  /// Approximate displacements: This function takes a set of points and a set
273  /// of displacements and finds a !new! transformation which approximates these
274  /// displacements. After approximation, the displacements are replaced by the
275  /// residual displacement errors at the points.
276  virtual double ApproximateAsNew(const double *, const double *, const double *, const double *,
277  double *, double *, double *, int,
278  int = 1, double = .0);
279 
280  /// Finds gradient of approximation error: This function takes a set of points
281  /// and a set of errors and finds a gradient to minimize the L2 norm of the error.
282  virtual void ApproximateGradient(const ImageAttributes &,
283  const double *, const double *, const double *,
284  double *, double = 1.0) const;
285 
286  /// Finds gradient of approximation error: This function takes a set of points
287  /// and a set of errors and finds a gradient to minimize the L2 norm of the error.
288  virtual void ApproximateGradient(const double *, const double *, const double *,
289  const double *, const double *, const double *, int,
290  double *, double = 1.0) const;
291 
292  /// Finds gradient of approximation error: This function takes a set of points
293  /// and a set of errors and finds a gradient to minimize the L2 norm of the error.
294  virtual void ApproximateGradient(const double *, const double *, const double *, const double *,
295  const double *, const double *, const double *, int,
296  double *, double = 1.0) const;
297 
298  /// Approximate displacements: This function takes a set of points and a set
299  /// of displacements and finds !new! parameters such that the resulting
300  /// transformation approximates the displacements as good as possible.
301  virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
302  const double *, const double *, const double *, int);
303 
304  /// Finds gradient of approximation error: This function takes a set of points
305  /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
306  /// which minimizes the L2 norm of the approximation error and adds it to the
307  /// input gradient with the given weight.
308  virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
309  const double *, const double *, const double *, int,
310  double *, double = 1.0) const;
311 
312  // ---------------------------------------------------------------------------
313  // Parameters (non-DoFs)
314 
315  // Import other overloads
316  using Observable::Parameter;
317 
318  /// Set named (non-DoF) parameter from value as string
319  virtual bool Set(const char *, const char *);
320 
321  /// Get (non-DoF) parameters as key/value as string map
322  virtual ParameterList Parameter() const;
323 
324  // ---------------------------------------------------------------------------
325  // Point transformation
326 
327  /// Whether the caching of the transformation displacements is required
328  /// (or preferred) by this transformation. For some transformations such as
329  /// those parameterized by velocities, caching of the displacements for
330  /// each target voxel results in better performance or is needed for example
331  /// for the scaling and squaring method.
332  virtual bool RequiresCachingOfDisplacements() const;
333 
334  /// Transforms a single point using the global transformation component only
335  virtual void GlobalTransform(double &, double &, double &, double = 0, double = NaN) const = 0;
336 
337  /// Transforms a single point using the local transformation component only
338  virtual void LocalTransform(double &, double &, double &, double = 0, double = NaN) const = 0;
339 
340  /// Transforms a single point
341  virtual void Transform(double &, double &, double &, double = 0, double = NaN) const = 0;
342 
343  /// Transforms a single point
344  virtual void Transform(Point &, double = 0, double = NaN) const;
345 
346  /// Transforms a set of points
347  virtual void Transform(PointSet &, double = 0, double = NaN) const;
348 
349  /// Transforms a set of points
350  virtual void Transform(int, double *, double *, double *, double = 0, double = NaN) const;
351 
352  /// Transforms a set of points
353  virtual void Transform(int, double *, double *, double *, const double *, double = NaN) const;
354 
355  /// Transforms world coordinates of image voxels
356  virtual void Transform(WorldCoordsImage &, double = NaN) const;
357 
358  /// Calculates the displacement of a single point using the global transformation component only
359  virtual void GlobalDisplacement(double &, double &, double &, double = 0, double = NaN) const;
360 
361  /// Calculates the displacement of a single point using the local transformation component only
362  virtual void LocalDisplacement(double &, double &, double &, double = 0, double = NaN) const;
363 
364  /// Calculates the displacement of a single point
365  virtual void Displacement(double &, double &, double &, double = 0, double = NaN) const;
366 
367  /// Calculates the displacement at specified lattice points
368  ///
369  /// \attention The displacements are computed at the positions after applying the
370  /// current displacements at each point. These displacements are then
371  /// added to the current displacements. Therefore, set the input
372  /// displacements to zero if only interested in the displacements of
373  /// this transformation at the lattice points.
374  virtual void Displacement(const ImageAttributes &, double *, double *, double *) const;
375 
376  /// Calculates the displacement vectors for a whole image domain
377  virtual void Displacement(GenericImage<double> &, double = NaN, const WorldCoordsImage * = NULL) const;
378 
379  /// Calculates the displacement vectors for a whole image domain
380  virtual void Displacement(GenericImage<float> &, double = NaN, const WorldCoordsImage * = NULL) const;
381 
382  /// Calculates the displacement vectors for a whole image domain
383  ///
384  /// \attention The displacements are computed at the positions after applying the
385  /// current displacements at each voxel. These displacements are then
386  /// added to the current displacements. Therefore, set the input
387  /// displacements to zero if only interested in the displacements of
388  /// this transformation at the voxel positions.
389  virtual void Displacement(GenericImage<double> &, double, double, const WorldCoordsImage * = NULL) const;
390 
391  /// Calculates the displacement vectors for a whole image domain
392  ///
393  /// \attention The displacements are computed at the positions after applying the
394  /// current displacements at each voxel. These displacements are then
395  /// added to the current displacements. Therefore, set the input
396  /// displacements to zero if only interested in the displacements of
397  /// this transformation at the voxel positions.
398  virtual void Displacement(GenericImage<float> &, double, double, const WorldCoordsImage * = NULL) const;
399 
400  /// Whether this transformation implements a more efficient update of a given
401  /// displacement field given the desired change of a transformation parameter
402  virtual bool CanModifyDisplacement(int = -1) const;
403 
404  /// Updates the displacement vectors for a whole image domain
405  ///
406  /// \param[in] dof Transformation parameter.
407  /// \param[in] dv Change of transformation parameter value.
408  /// \param[in,out] dx Displacement field to be updated.
409  /// \param[in] t Time point of start point.
410  /// \param[in] t0 Time point of end point.
411  /// \param[in] i2w Pre-computed world coordinates.
412  virtual void DisplacementAfterDOFChange(int dof, double dv,
414  double t, double t0 = NaN,
415  const WorldCoordsImage *i2w = NULL) const;
416 
417  /// Transforms a single point using the inverse of the global transformation only
418  virtual void GlobalInverse(double &, double &, double &, double = 0, double = NaN) const;
419 
420  /// Transforms a single point using the inverse of the local transformation only
421  virtual bool LocalInverse(double &, double &, double &, double = 0, double = NaN) const;
422 
423  /// Transforms a single point using the inverse of the transformation
424  virtual bool Inverse(double &, double &, double &, double = 0, double = NaN) const;
425 
426  /// Transforms a single point using the inverse of the transformation
427  virtual bool Inverse(Point &, double = 0, double = NaN) const;
428 
429  /// Transforms a set of points using the inverse of the transformation
430  ///
431  /// \returns Number of points at which transformation is non-invertible.
432  virtual int Inverse(PointSet &, double = 0, double = NaN) const;
433 
434  /// Calculates the displacement of a single point using the inverse of the global transformation only
435  virtual void GlobalInverseDisplacement(double &, double &, double &, double = 0, double = NaN) const;
436 
437  /// Calculates the displacement of a single point using the inverse of the local transformation only
438  virtual bool LocalInverseDisplacement(double &, double &, double &, double = 0, double = NaN) const;
439 
440  /// Calculates the displacement of a single point using the inverse of the transformation
441  virtual bool InverseDisplacement(double &, double &, double &, double = 0, double = NaN) const;
442 
443  /// Calculates the inverse displacement at specified lattice points
444  ///
445  /// \attention The displacements are computed at the positions after applying the
446  /// current displacements at each point. These displacements are then
447  /// added to the current displacements. Therefore, set the input
448  /// displacements to zero if only interested in the displacements of
449  /// this transformation at the lattice points.
450  ///
451  /// \returns Number of points at which transformation is non-invertible.
452  virtual int InverseDisplacement(const ImageAttributes &, double *, double *, double *) const;
453 
454  /// Calculates the inverse displacement vectors for a whole image domain
455  ///
456  /// \returns Number of points at which transformation is non-invertible.
457  virtual int InverseDisplacement(GenericImage<double> &, double = NaN, const WorldCoordsImage * = NULL) const;
458 
459  /// Calculates the inverse displacement vectors for a whole image domain
460  ///
461  /// \returns Number of points at which transformation is non-invertible.
462  virtual int InverseDisplacement(GenericImage<float> &, double = NaN, const WorldCoordsImage * = NULL) const;
463 
464  /// Calculates the inverse displacement vectors for a whole image domain
465  ///
466  /// \attention The displacements are computed at the positions after applying the
467  /// current displacements at each voxel. These displacements are then
468  /// added to the current displacements. Therefore, set the input
469  /// displacements to zero if only interested in the displacements of
470  /// this transformation at the voxel positions.
471  ///
472  /// \returns Number of points at which transformation is non-invertible.
473  virtual int InverseDisplacement(GenericImage<double> &, double, double, const WorldCoordsImage * = NULL) const;
474 
475  /// Calculates the inverse displacement vectors for a whole image domain
476  ///
477  /// \attention The displacements are computed at the positions after applying the
478  /// current displacements at each voxel. These displacements are then
479  /// added to the current displacements. Therefore, set the input
480  /// displacements to zero if only interested in the displacements of
481  /// this transformation at the voxel positions.
482  ///
483  /// \returns Number of points at which transformation is non-invertible.
484  virtual int InverseDisplacement(GenericImage<float> &, double, double, const WorldCoordsImage * = NULL) const;
485 
486  // ---------------------------------------------------------------------------
487  // Derivatives
488 
489  /// Calculates the Jacobian of the global transformation w.r.t world coordinates
490  virtual void GlobalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
491 
492  /// Calculates the Jacobian of the local transformation w.r.t world coordinates
493  virtual void LocalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
494 
495  /// Calculates the Jacobian of the transformation w.r.t world coordinates
496  virtual void Jacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
497 
498  /// Calculates the determinant of the Jacobian of the global transformation w.r.t world coordinates
499  virtual double GlobalJacobian(double, double, double, double = 0, double = NaN) const;
500 
501  /// Calculates the determinant of the Jacobian of the local transformation w.r.t world coordinates
502  virtual double LocalJacobian(double, double, double, double = 0, double = NaN) const;
503 
504  /// Calculates the determinant of the Jacobian of the transformation w.r.t world coordinates
505  virtual double Jacobian(double, double, double, double = 0, double = NaN) const;
506 
507  /// Calculates the Hessian for each component of the global transformation w.r.t world coordinates
508  virtual void GlobalHessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
509 
510  /// Calculates the Hessian for each component of the local transformation w.r.t world coordinates
511  virtual void LocalHessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
512 
513  /// Calculates the Hessian for each component of the transformation w.r.t world coordinates
514  virtual void Hessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
515 
516  /// Calculates the Jacobian of the transformation w.r.t a transformation parameter
517  virtual void JacobianDOFs(double [3], int, double, double, double, double = 0, double = NaN) const;
518 
519  /// Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w.r.t. a transformation parameter
520  virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double = 0, double = NaN) const;
521 
522  /// Applies the chain rule to convert spatial non-parametric gradient
523  /// to a gradient w.r.t the parameters of this transformation.
524  ///
525  /// If the transformation itself is non-parametric, the gradient will be passed through
526  /// unchanged. The default implementation uses the full Jacobian matrix computed for each
527  /// DoF separately (i.e., calls JacobianDOFs for each DoF).
528  ///
529  /// For 4D transformations, the temporal coordinate t used for the computation of the Jacobian
530  /// of the transformation w.r.t the transformation parameters for all spatial (x, y, z) voxel
531  /// coordinates in world units, is assumed to correspond to the temporal origin of the given
532  /// gradient image. For 4D transformations parameterized by velocities, a second time for the
533  /// upper integration bound can be provided as last argument to this method. This last
534  /// argument is ignored by transformations parameterized by displacements.
535  ///
536  /// \sa ImageSimilarityMetric::EvaluateGradient
537  virtual void ParametricGradient(const GenericImage<double> *, double *,
538  const WorldCoordsImage *,
539  const WorldCoordsImage *,
540  double = NaN, double = 1) const;
541 
542  /// Applies the chain rule to convert spatial non-parametric gradient
543  /// to a gradient w.r.t the parameters of this transformation.
544  void ParametricGradient(const GenericImage<double> *, double *,
545  const WorldCoordsImage *,
546  double = NaN, double = 1) const;
547 
548  /// Applies the chain rule to convert spatial non-parametric gradient
549  /// to a gradient w.r.t the parameters of this transformation.
550  void ParametricGradient(const GenericImage<double> *, double *,
551  double = NaN, double = 1) const;
552 
553  /// Applies the chain rule to convert spatial non-parametric gradient
554  /// to a gradient w.r.t the parameters of this transformation.
555  virtual void ParametricGradient(const GenericImage<double> **, int, double *,
556  const WorldCoordsImage *,
557  const WorldCoordsImage *,
558  const double * = NULL, double = 1) const;
559 
560  /// Applies the chain rule to convert spatial non-parametric gradient
561  /// to a gradient w.r.t the parameters of this transformation.
562  void ParametricGradient(const GenericImage<double> **, int, double *,
563  const WorldCoordsImage *,
564  const double * = NULL, double = 1) const;
565 
566  /// Applies the chain rule to convert spatial non-parametric gradient
567  /// to a gradient w.r.t the parameters of this transformation.
568  void ParametricGradient(const GenericImage<double> **, int, double *,
569  const double * = NULL, double = 1) const;
570 
571  /// Applies the chain rule to convert point-wise non-parametric gradient
572  /// to a gradient w.r.t the parameters of this transformation.
573  virtual void ParametricGradient(const PointSet &, const Vector3D<double> *,
574  double *, double = 0, double = NaN, double = 1) const;
575 
576  // ---------------------------------------------------------------------------
577  // I/O
578 
579  /// Prints information about the transformation
580  void Print(Indent = 0) const;
581 
582  /// Prints information about the transformation
583  virtual void Print(ostream &os, Indent = 0) const = 0;
584 
585  /// Reads a transformation from a file
586  virtual void Read(const char *);
587 
588  /// Writes a transformation to a file
589  virtual void Write(const char *) const;
590 
591  /// Reads a transformation from a file stream
592  virtual Cifstream &Read(Cifstream &);
593 
594  /// Writes a transformation to a file stream
595  virtual Cofstream &Write(Cofstream &) const;
596 
597  /// Whether magic number in header of given file
598  static bool CheckHeader(const char *);
599 
600  /// Whether this transformation can read a file of specified type (i.e. format)
601  virtual bool CanRead(TransformationType) const;
602 
603 protected:
604 
605  /// Reads transformation parameters from a file stream
607 
608  /// Writes transformation parameters to a file stream
609  virtual Cofstream &WriteDOFs(Cofstream &) const;
610 
611 public:
612 
613  // ---------------------------------------------------------------------------
614  // Others
615 
616  /// Returns type ID corresponding to transformations of the named class
617  static TransformationType TypeOfClass(const char *);
618 
619  /// Returns type ID of the instantiated transformation class
620  virtual TransformationType TypeOfClass() const;
621 
622  /// Verifies that the transformation is well constructed
623  /// according to class-specific rules
624  virtual void Verify();
625 
626 };
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 // Auxiliary macros for transformation implementation
630 ////////////////////////////////////////////////////////////////////////////////
631 
632 // -----------------------------------------------------------------------------
633 #define mirtkAbstractTransformationMacro(name) \
634  mirtkAbstractMacro(name)
635 
636 // -----------------------------------------------------------------------------
637 #define mirtkTransformationMacro(name) \
638  mirtkObjectMacro(name)
639 
640 ////////////////////////////////////////////////////////////////////////////////
641 // Inline definitions
642 ////////////////////////////////////////////////////////////////////////////////
643 
644 // =============================================================================
645 // Transformation parameters
646 // =============================================================================
647 
648 // -----------------------------------------------------------------------------
650 {
651  return _NumberOfDOFs;
652 }
653 
654 // -----------------------------------------------------------------------------
656 {
657  int nactive = 0;
658  for (int dof = 0; dof < this->NumberOfDOFs(); ++dof) {
659  if (this->GetStatus(dof) == Active) ++nactive;
660  }
661  return nactive;
662 }
663 
664 // -----------------------------------------------------------------------------
666 {
667  return this->NumberOfDOFs() - this->NumberOfActiveDOFs();
668 }
669 
670 // -----------------------------------------------------------------------------
671 inline double Transformation::DOFGradientNorm(const double *gradient) const
672 {
673  double norm, max = .0;
674  for (int dof = 0; dof < _NumberOfDOFs; ++dof) {
675  norm = abs(gradient[dof]);
676  if (norm > max) max = norm;
677  }
678  return max;
679 }
680 
681 // -----------------------------------------------------------------------------
682 inline void Transformation::Put(int idx, double x)
683 {
684  if (_Param[idx] != static_cast<DOFValue>(x)) {
685  _Param[idx] = static_cast<DOFValue>(x);
686  this->Changed(true);
687  }
688 }
689 
690 // -----------------------------------------------------------------------------
691 inline double Transformation::Get(int idx) const
692 {
693  return static_cast<double>(_Param[idx]);
694 }
695 
696 // -----------------------------------------------------------------------------
697 inline void Transformation::Put(const DOFValue *x)
698 {
699  for (int idx = 0; idx < _NumberOfDOFs; ++idx) {
700  if (_Param[idx] != x[idx]) {
701  _Param[idx] = x[idx];
702  this->Changed(true);
703  }
704  }
705 }
706 
707 // -----------------------------------------------------------------------------
708 inline void Transformation::Add(const DOFValue *dx)
709 {
710  for (int idx = 0; idx < _NumberOfDOFs; ++idx) {
711  if (dx[idx] != .0) {
712  _Param[idx] += dx[idx];
713  this->Changed(true);
714  }
715  }
716 }
717 
718 // -----------------------------------------------------------------------------
719 inline double Transformation::Update(const DOFValue *dx)
720 {
721  double delta, max_delta = .0;
722  for (int idx = 0; idx < _NumberOfDOFs; ++idx) {
723  _Param[idx] += dx[idx];
724  delta = abs(dx[idx]);
725  if (delta > max_delta) max_delta = delta;
726  }
727  if (max_delta > .0) this->Changed(true);
728  return max_delta;
729 }
730 
731 // -----------------------------------------------------------------------------
732 inline void Transformation::Get(DOFValue *x) const
733 {
734  memcpy(x, _Param, _NumberOfDOFs * sizeof(DOFValue));
735 }
736 
737 // -----------------------------------------------------------------------------
738 inline void Transformation::PutStatus(int idx, DOFStatus s)
739 {
740  _Status[idx] = s;
741 }
742 
743 // -----------------------------------------------------------------------------
745 {
746  return _Status[idx];
747 }
748 
749 // -----------------------------------------------------------------------------
751 {
752  return (_Param == t->_Param);
753 }
754 
755 // -----------------------------------------------------------------------------
756 inline bool HaveSameDOFs(const Transformation *t1, const Transformation *t2)
757 {
758  // If the virtual HasSameDOFsAs function was not overriden by the specialized
759  // type of one transformation, it is assumed that it uses the _Param memory to
760  // store its transformation parameters. However, the other transformation
761  // might be a specialized type which does not make use of it. In this case,
762  // even if the two _Param pointers do not reference the same memory, the two
763  // transformations may still use the same parameters because the other
764  // transformation directly or indirectly wraps this transformation. Therefore,
765  // the check with the transformations exchanged and the boolean OR (not AND).
766  return t1->HasSameDOFsAs(t2) || t2->HasSameDOFsAs(t1);
767 }
768 
769 // -----------------------------------------------------------------------------
770 inline bool Transformation::IsIdentity() const
771 {
772  for (int i = 0; i < this->NumberOfDOFs(); ++i) {
773  if (this->Get(i) != .0) return false;
774  }
775  return true;
776 }
777 
778 // -----------------------------------------------------------------------------
779 inline bool Transformation
780 ::DOFBoundingBox(const Image *image, int, int &i1, int &j1, int &k1,
781  int &i2, int &j2, int &k2, double fraction) const
782 {
783  i1 = j1 = k1 = 0;
784  i2 = image->X() - 1, j2 = image->Y() -1, k2 = image->Z() - 1;
785  return !image->IsEmpty();
786 }
787 
788 // =============================================================================
789 // Point transformation
790 // =============================================================================
791 
792 // -----------------------------------------------------------------------------
794 {
795  return false;
796 }
797 
798 // -----------------------------------------------------------------------------
799 inline void Transformation::Transform(Point &p, double t, double t0) const
800 {
801  this->Transform(p._x, p._y, p._z, t, t0);
802 }
803 
804 // -----------------------------------------------------------------------------
805 inline void Transformation::Transform(PointSet &pset, double t, double t0) const
806 {
807  for (int i = 0; i < pset.Size(); i++) this->Transform(pset(i), t, t0);
808 }
809 
810 // -----------------------------------------------------------------------------
811 inline bool Transformation::Inverse(Point &p, double t, double t0) const
812 {
813  return this->Inverse(p._x, p._y, p._z, t, t0);
814 }
815 
816 // -----------------------------------------------------------------------------
817 inline int Transformation::Inverse(PointSet &pset, double t, double t0) const
818 {
819  int n = 0;
820  for (int i = 0; i < pset.Size(); ++i) {
821  if (!this->Inverse(pset(i), t, t0)) ++n;
822  }
823  return n;
824 }
825 
826 // -----------------------------------------------------------------------------
827 inline void Transformation::GlobalDisplacement(double &x, double &y, double &z, double t, double t0) const
828 {
829  const double u = x;
830  const double v = y;
831  const double w = z;
832 
833  this->GlobalTransform(x, y, z, t, t0);
834 
835  x -= u;
836  y -= v;
837  z -= w;
838 }
839 
840 // -----------------------------------------------------------------------------
841 inline void Transformation::LocalDisplacement(double &x, double &y, double &z, double t, double t0) const
842 {
843  const double u = x;
844  const double v = y;
845  const double w = z;
846 
847  this->LocalTransform(x, y, z, t, t0);
848 
849  x -= u;
850  y -= v;
851  z -= w;
852 }
853 
854 // -----------------------------------------------------------------------------
855 inline void Transformation::Displacement(double &x, double &y, double &z, double t, double t0) const
856 {
857  const double u = x;
858  const double v = y;
859  const double w = z;
860 
861  this->Transform(x, y, z, t, t0);
862 
863  x -= u;
864  y -= v;
865  z -= w;
866 }
867 
868 // -----------------------------------------------------------------------------
869 inline void Transformation::GlobalInverseDisplacement(double &x, double &y, double &z, double t, double t0) const
870 {
871  const double u = x;
872  const double v = y;
873  const double w = z;
874 
875  this->GlobalInverse(x, y, z, t, t0);
876 
877  x -= u;
878  y -= v;
879  z -= w;
880 }
881 
882 // -----------------------------------------------------------------------------
883 inline bool Transformation::LocalInverseDisplacement(double &x, double &y, double &z, double t, double t0) const
884 {
885  const double u = x;
886  const double v = y;
887  const double w = z;
888 
889  bool ok = this->LocalInverse(x, y, z, t, t0);
890 
891  x -= u;
892  y -= v;
893  z -= w;
894 
895  return ok;
896 }
897 
898 // -----------------------------------------------------------------------------
899 inline bool Transformation::InverseDisplacement(double &x, double &y, double &z, double t, double t0) const
900 {
901  const double u = x;
902  const double v = y;
903  const double w = z;
904 
905  bool ok = this->Inverse(x, y, z, t, t0);
906 
907  x -= u;
908  y -= v;
909  z -= w;
910 
911  return ok;
912 }
913 
914 // =============================================================================
915 // Derivatives
916 // =============================================================================
917 
918 // -----------------------------------------------------------------------------
919 inline void Transformation::GlobalJacobian(Matrix &, double, double, double, double, double) const
920 {
921  cerr << this->NameOfClass() << "::GlobalJacobian: Not implemented" << endl;
922  exit(1);
923 }
924 
925 // -----------------------------------------------------------------------------
926 inline void Transformation::LocalJacobian(Matrix &, double, double, double, double, double) const
927 {
928  cerr << this->NameOfClass() << "::LocalJacobian: Not implemented" << endl;
929  exit(1);
930 }
931 
932 // -----------------------------------------------------------------------------
933 inline void Transformation::Jacobian(Matrix &, double, double, double, double, double) const
934 {
935  cerr << this->NameOfClass() << "::Jacobian: Not implemented" << endl;
936  exit(1);
937 }
938 
939 // -----------------------------------------------------------------------------
940 inline void Transformation::DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double, double) const
941 {
942  cerr << this->NameOfClass() << "::DeriveJacobianWrtDOF: Not implemented" << endl;
943  exit(1);
944 }
945 
946 // -----------------------------------------------------------------------------
947 inline double Transformation::GlobalJacobian(double x, double y, double z, double t, double t0) const
948 {
949  Matrix jac(3, 3);
950  this->GlobalJacobian(jac, x, y, z, t, t0);
951  return jac.Det3x3();
952 }
953 
954 // -----------------------------------------------------------------------------
955 inline double Transformation::LocalJacobian(double x, double y, double z, double t, double t0) const
956 {
957  Matrix jac(3, 3);
958  this->LocalJacobian(jac, x, y, z, t, t0);
959  return jac.Det3x3();
960 }
961 
962 // -----------------------------------------------------------------------------
963 inline double Transformation::Jacobian(double x, double y, double z, double t, double t0) const
964 {
965  Matrix jac(3, 3);
966  this->Jacobian(jac, x, y, z, t, t0);
967  return jac.Det3x3();
968 }
969 
970 // -----------------------------------------------------------------------------
971 inline void Transformation::GlobalHessian(Matrix [3], double, double, double, double, double) const
972 {
973  cerr << this->NameOfClass() << "::GlobalHessian: Not implemented" << endl;
974  exit(1);
975 }
976 
977 // -----------------------------------------------------------------------------
978 inline void Transformation::LocalHessian(Matrix [3], double, double, double, double, double) const
979 {
980  cerr << this->NameOfClass() << "::LocalHessian: Not implemented" << endl;
981  exit(1);
982 }
983 
984 // -----------------------------------------------------------------------------
985 inline void Transformation::Hessian(Matrix [3], double, double, double, double, double) const
986 {
987  cerr << this->NameOfClass() << "::Hessian: Not implemented" << endl;
988  exit(1);
989 }
990 
991 // -----------------------------------------------------------------------------
992 inline void Transformation::JacobianDOFs(double [3], int, double, double, double, double, double) const
993 {
994  cerr << this->NameOfClass() << "::JacobianDOFs: Not implemented" << endl;
995  exit(1);
996 }
997 
998 // -----------------------------------------------------------------------------
999 inline void Transformation
1001  const WorldCoordsImage *i2w, double t0, double w) const
1002 {
1003  this->ParametricGradient(in, out, i2w, NULL, t0, w);
1004 }
1005 
1006 // -----------------------------------------------------------------------------
1007 inline void Transformation
1008 ::ParametricGradient(const GenericImage<double> *in, double *out, double t0, double w) const
1009 {
1010  this->ParametricGradient(in, out, NULL, NULL, t0, w);
1011 }
1012 
1013 // -----------------------------------------------------------------------------
1014 inline void Transformation
1015 ::ParametricGradient(const GenericImage<double> **in, int n, double *out,
1016  const WorldCoordsImage *i2w, const WorldCoordsImage *wc,
1017  const double *t0, double w) const
1018 {
1019  for (int i = 0; i < n; ++i) {
1020  this->ParametricGradient(in[i], out, i2w, wc, t0 ? t0[i] : 1.0, w);
1021  }
1022 }
1023 
1024 // -----------------------------------------------------------------------------
1025 inline void Transformation
1026 ::ParametricGradient(const GenericImage<double> **in, int n, double *out,
1027  const WorldCoordsImage *i2w, const double *t0, double w) const
1028 {
1029  this->ParametricGradient(in, n, out, i2w, NULL, t0, w);
1030 }
1031 
1032 // -----------------------------------------------------------------------------
1033 inline void Transformation
1034 ::ParametricGradient(const GenericImage<double> **in, int n, double *out, const double *t0, double w) const
1035 {
1036  this->ParametricGradient(in, n, out, NULL, NULL, t0, w);
1037 }
1038 
1039 // =============================================================================
1040 // Others
1041 // =============================================================================
1042 
1043 // -----------------------------------------------------------------------------
1044 inline void Transformation::Print(Indent indent) const
1045 {
1046  this->Print(cout, indent);
1047 }
1048 
1049 // -----------------------------------------------------------------------------
1051 {
1052  return Transformation::TypeOfClass(this->NameOfClass());
1053 }
1054 
1055 ////////////////////////////////////////////////////////////////////////////////
1056 // Auxiliary functions
1057 ////////////////////////////////////////////////////////////////////////////////
1058 
1059 // -----------------------------------------------------------------------------
1060 /// Check whether a named file is an MIRTK transformation file
1061 ///
1062 /// \param[in] name File name.
1063 ///
1064 /// \returns Whether the named file exists and stores an MIRTK transformation.
1065 bool IsTransformation(const char *name);
1066 
1067 
1068 } // namespace mirtk
1069 
1070 #endif // MIRTK_Transformation_H
virtual void GlobalInverse(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the inverse of the global transformation only.
virtual void GlobalHessian(Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the global transformation w.r.t world coordinates...
virtual void Reset()
Reset transformation.
virtual ParameterList Parameter() const
Get (non-DoF) parameters as key/value as string map.
virtual void ApproximateDOFs(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int)
double EvaluateRMSError(const ImageAttributes &, const Transformation *) const
Evaluates RMS error of transformation compared to another.
static Transformation * New(TransformationType)
virtual void PutStatus(int, DOFStatus)
Put status of transformation parameter.
virtual void GlobalDisplacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the global transformation component only...
virtual DOFStatus GetStatus(int) const
Get status of transformation parameter.
virtual void ApproximateGradient(const ImageAttributes &, const double *, const double *, const double *, double *, double=1.0) const
virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double=0, double=NaN) const
Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w...
double Det3x3() const
Calculate determinant of a 3x3 matrix.
Definition: Matrix.h:1019
bool IsEmpty() const
Whether image is uninitialized.
Definition: BaseImage.h:1283
double DOFValue
Type of transformation parameter value.
virtual ~Transformation()
Default destructor.
virtual bool CopyFrom(const Transformation *)
virtual void Verify()
virtual void JacobianDOFs(double [3], int, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the transformation w.r.t a transformation parameter.
double _x
x coordinate of Point
Definition: Point.h:46
virtual bool LocalInverseDisplacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the inverse of the local transformation only...
virtual int NumberOfDOFs() const
Get number of transformation parameters.
virtual void LocalDisplacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the local transformation component only...
bool IsTransformation(const char *name)
virtual void LocalHessian(Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the local transformation w.r.t world coordinates...
DOFStatus * _Status
Status of each transformation parameter (Active or Passive)
int NumberOfActiveDOFs() const
Get number of active transformation parameters.
virtual bool InverseDisplacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the inverse of the transformation.
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
virtual double Update(const DOFValue *)
Update transformation parameters given parametric gradient.
virtual void Put(int, double)
Put value of transformation parameter.
virtual void LocalTransform(double &, double &, double &, double=0, double=NaN) const =0
Transforms a single point using the local transformation component only.
int _NumberOfDOFs
Number of transformation parameters.
virtual void Write(const char *) const
Writes a transformation to a file.
Status
Enumeration of common states for entities such as objective function parameters.
Definition: Status.h:28
virtual void Add(const DOFValue *)
Add change to transformation parameters.
Definition: IOConfig.h:41
virtual double Approximate(const ImageAttributes &, const Transformation *, int=1, double=.0)
Approximate another transformation and return approximation error.
virtual bool HasSameDOFsAs(const Transformation *) const
Checks whether transformation depends on the same vector of parameters.
virtual void Jacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the transformation w.r.t world coordinates.
void InitializeDOFs(int)
Initialize transformation parameters.
virtual bool DOFBoundingBox(const Image *, int, int &, int &, int &, int &, int &, int &, double=1) const
DOFValue * _Param
Value of each transformation parameter.
virtual TransformationType TypeOfClass() const
Returns type ID of the instantiated transformation class.
int NumberOfPassiveDOFs() const
Get number of passive transformation parameters.
virtual void Displacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point.
virtual void GlobalTransform(double &, double &, double &, double=0, double=NaN) const =0
Transforms a single point using the global transformation component only.
virtual void DisplacementAfterDOFChange(int dof, double dv, GenericImage< double > &dx, double t, double t0=NaN, const WorldCoordsImage *i2w=NULL) const
int Y() const
Returns the number of voxels in the y-direction.
Definition: BaseImage.h:880
virtual Cifstream & ReadDOFs(Cifstream &, TransformationType)
Reads transformation parameters from a file stream.
Status DOFStatus
Type of transforamtion parameter status.
Transformation(int=0)
Default constructor.
virtual bool CanRead(TransformationType) const
Whether this transformation can read a file of specified type (i.e. format)
int X() const
Returns the number of voxels in the x-direction.
Definition: BaseImage.h:874
virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int, double *, double=1.0) const
virtual void Transform(double &, double &, double &, double=0, double=NaN) const =0
Transforms a single point.
virtual void Read(const char *)
Reads a transformation from a file.
static bool CheckHeader(const char *)
Whether magic number in header of given file.
virtual double ApproximateAsNew(const ImageAttributes &, const Transformation *, int=1, double=.0)
Approximate another transformation and return approximation error.
virtual bool CanModifyDisplacement(int=-1) const
virtual const char * NameOfClass() const =0
Get name of class, which this object is an instance of.
virtual void GlobalInverseDisplacement(double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the inverse of the global transformation only...
void Size(int)
Definition: PointSet.h:434
virtual bool LocalInverse(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the inverse of the local transformation only.
virtual double DOFGradientNorm(const double *) const
Get norm of the gradient vector.
virtual ParameterList Parameter() const
Get parameter name/value pairs.
Definition: Object.h:139
virtual bool RequiresCachingOfDisplacements() const
virtual bool Set(const char *, const char *)
Set named (non-DoF) parameter from value as string.
double _z
z coordinate of Point
Definition: Point.h:48
virtual bool Inverse(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the inverse of the transformation.
double _y
y coordinate of Point
Definition: Point.h:47
virtual void LocalJacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
virtual void GlobalJacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the global transformation w.r.t world coordinates.
void Print(Indent=0) const
Prints information about the transformation.
virtual void Hessian(Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the transformation w.r.t world coordinates.
virtual Cofstream & WriteDOFs(Cofstream &) const
Writes transformation parameters to a file stream.
virtual double Get(int) const
Get value of transformation parameter.
int Z() const
Returns the number of voxels in the z-direction.
Definition: BaseImage.h:886
virtual bool IsIdentity() const
Checks whether the transformation is an identity mapping.
virtual void ParametricGradient(const GenericImage< double > *, double *, const WorldCoordsImage *, const WorldCoordsImage *, double=NaN, double=1) const