File: itkAdvancedTransform.h

package info (click to toggle)
elastix 5.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 42,480 kB
  • sloc: cpp: 68,403; lisp: 4,118; python: 1,013; xml: 182; sh: 177; makefile: 33
file content (340 lines) | stat: -rw-r--r-- 14,274 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkTransform.h,v $
  Date:      $Date: 2008-06-29 12:58:58 $
  Version:   $Revision: 1.64 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef itkAdvancedTransform_h
#define itkAdvancedTransform_h

#include "itkTransform.h"
#include "itkMatrix.h"
#include "itkFixedArray.h"
#include <cassert>

namespace itk
{

/** \class AdvancedTransform
 * \brief Transform maps points, vectors and covariant vectors from an input
 * space to an output space.
 *
 * This abstract class define the generic interface for a geometrical
 * transformation from one space to another. The class provides methods
 * for mapping points, vectors and covariant vectors from the input space
 * to the output space.
 *
 * Given that transformation are not necessarily invertible, this basic
 * class does not provide the methods for back transformation. Back transform
 * methods are implemented in derived classes where appropriate.
 *
 * \par Registration Framework Support
 * Typically a Transform class has several methods for setting its
 * parameters. For use in the registration framework, the parameters must
 * also be represented by an array of doubles to allow communication
 * with generic optimizers. The Array of transformation parameters is set using
 * the SetParameters() method.
 *
 * Another requirement of the registration framework is the computation
 * of the Jacobian of the transform T. In general, an ImageToImageMetric
 * requires the knowledge of this Jacobian in order to compute the metric
 * derivatives. The Jacobian is a matrix whose element are the partial
 * derivatives of the transformation with respect to the array of parameters
 * mu that defines the transform, evaluated at a point p: dT/dmu(p).
 *
 * If penalty terms are included in the registration, the transforms also
 * need to implement other derivatives of T. Often, penalty terms are functions
 * of the spatial derivatives of T. Therefore, e.g. the SpatialJacobian dT/dx
 * and the SpatialHessian d^2T/dx_idx_j require implementation. The
 * GetValueAndDerivative() requires the d/dmu of those terms. Therefore,
 * we additionally define GetJacobianOfSpatialJacobian() and
 * GetJacobianOfSpatialHessian().
 *
 * \ingroup Transforms
 *
 */
template <class TScalarType, unsigned int NInputDimensions = 3, unsigned int NOutputDimensions = 3>
class ITK_TEMPLATE_EXPORT AdvancedTransform : public Transform<TScalarType, NInputDimensions, NOutputDimensions>
{
public:
  ITK_DISALLOW_COPY_AND_MOVE(AdvancedTransform);

  /** Standard class typedefs. */
  using Self = AdvancedTransform;
  using Superclass = Transform<TScalarType, NInputDimensions, NOutputDimensions>;
  using Pointer = SmartPointer<Self>;
  using ConstPointer = SmartPointer<const Self>;

  /** New method for creating an object using a factory. */
  // itkNewMacro( Self );

  /** Run-time type information (and related methods). */
  itkTypeMacro(AdvancedTransform, Transform);

  /** Dimension of the domain space. */
  itkStaticConstMacro(InputSpaceDimension, unsigned int, NInputDimensions);
  itkStaticConstMacro(OutputSpaceDimension, unsigned int, NOutputDimensions);

  /** Typedefs from the Superclass. */
  using typename Superclass::ScalarType;
  using typename Superclass::ParametersType;
  using typename Superclass::FixedParametersType;
  using typename Superclass::ParametersValueType;
  using typename Superclass::NumberOfParametersType;
  using typename Superclass::DerivativeType;
  using typename Superclass::JacobianType;
  using typename Superclass::InputVectorType;
  using typename Superclass::OutputVectorType;
  using typename Superclass::InputCovariantVectorType;
  using typename Superclass::OutputCovariantVectorType;
  using typename Superclass::InputVnlVectorType;
  using typename Superclass::OutputVnlVectorType;
  using typename Superclass::InputPointType;
  using typename Superclass::OutputPointType;

  using InverseTransformBaseType = typename Superclass::InverseTransformBaseType;
  using typename Superclass::InverseTransformBasePointer;

  /** Transform typedefs for the from Superclass. */
  using TransformType = Transform<TScalarType, NInputDimensions, NOutputDimensions>;
  using TransformTypePointer = typename TransformType::Pointer;
  using TransformTypeConstPointer = typename TransformType::ConstPointer;

  /** Types for the (Spatial)Jacobian/Hessian.
   * Using an itk::FixedArray instead of an std::vector gives a performance
   * gain for the SpatialHessianType.
   */
  using NonZeroJacobianIndicesType = std::vector<unsigned long>;
  using SpatialJacobianType = Matrix<ScalarType, OutputSpaceDimension, InputSpaceDimension>;
  using JacobianOfSpatialJacobianType = std::vector<SpatialJacobianType>;
  // \todo: think about the SpatialHessian type, should be a 3D native type
  using SpatialHessianType =
    FixedArray<Matrix<ScalarType, InputSpaceDimension, InputSpaceDimension>, OutputSpaceDimension>;
  using JacobianOfSpatialHessianType = std::vector<SpatialHessianType>;
  using InternalMatrixType = typename SpatialJacobianType::InternalMatrixType;

  /** Typedef for the moving image gradient type.
   * This type is defined by the B-spline interpolator as
   * typedef CovariantVector< RealType, ImageDimension >
   * As we cannot access this type we simply re-construct it to be identical.
   */
  using MovingImageGradientType = OutputCovariantVectorType;
  using MovingImageGradientValueType = typename MovingImageGradientType::ValueType;

  /** Get the number of nonzero Jacobian indices. By default all. */
  virtual NumberOfParametersType
  GetNumberOfNonZeroJacobianIndices() const;

  /** Whether the advanced transform has nonzero matrices. */
  itkGetConstMacro(HasNonZeroSpatialHessian, bool);
  itkGetConstMacro(HasNonZeroJacobianOfSpatialHessian, bool);

  /** This returns a sparse version of the Jacobian of the transformation.
   *
   * The Jacobian is expressed as a vector of partial derivatives of the
   * transformation components with respect to the parameters \f$\mu\f$ that
   * define the transformation \f$T\f$, evaluated at a point \f$p\f$.
   *
   * \f[
      J=\left[ \begin{array}{cccc}
      \frac{\partial T_{1}}{\partial \mu_{1}}(p) &
      \frac{\partial T_{1}}{\partial \mu_{2}}(p) &
      \cdots &
      \frac{\partial T_{1}}{\partial \mu_{m}}(p) \\
      \frac{\partial T_{2}}{\partial \mu_{1}}(p) &
      \frac{\partial T_{2}}{\partial \mu_{2}}(p) &
      \cdots &
      \frac{\partial T_{2}}{\partial \mu_{m}}(p) \\
      \vdots & \vdots & \ddots & \vdots \\
      \frac{\partial T_{d}}{\partial \mu_{1}}(p) &
      \frac{\partial T_{d}}{\partial \mu_{2}}(p) &
      \cdots &
      \frac{\partial T_{d}}{\partial \mu_{m}}(p)
      \end{array}\right],
   * \f]
   * with \f$m\f$ the number of parameters, i.e. the size of \f$\mu\f$, and \f$d\f$
   * the dimension of the image.
   */
  virtual void
  GetJacobian(const InputPointType &       inputPoint,
              JacobianType &               j,
              NonZeroJacobianIndicesType & nonZeroJacobianIndices) const = 0;

  /** Compute the inner product of the Jacobian with the moving image gradient.
   * The Jacobian is (partially) constructed inside this function, but not returned.
   */
  virtual void
  EvaluateJacobianWithImageGradientProduct(const InputPointType &          inputPoint,
                                           const MovingImageGradientType & movingImageGradient,
                                           DerivativeType &                imageJacobian,
                                           NonZeroJacobianIndicesType &    nonZeroJacobianIndices) const;

  /** Compute the spatial Jacobian of the transformation.
   *
   * The spatial Jacobian is expressed as a vector of partial derivatives of the
   * transformation components with respect to the spatial position \f$x\f$,
   * evaluated at a point \f$p\f$.
   *
   * \f[
      sJ=\left[ \begin{array}{cccc}
      \frac{\partial T_{1}}{\partial x_{1}}(p) &
      \frac{\partial T_{1}}{\partial x_{2}}(p) &
      \cdots &
      \frac{\partial T_{1}}{\partial x_{m}}(p) \\
      \frac{\partial T_{2}}{\partial x_{1}}(p) &
      \frac{\partial T_{2}}{\partial x_{2}}(p) &
      \cdots &
      \frac{\partial T_{2}}{\partial x_{m}}(p) \\
      \vdots & \vdots & \ddots & \vdots \\
      \frac{\partial T_{d}}{\partial x_{1}}(p) &
      \frac{\partial T_{d}}{\partial x_{2}}(p) &
      \cdots &
      \frac{\partial T_{d}}{\partial x_{m}}(p)
      \end{array}\right],
   * \f]
   * with \f$m\f$ the number of parameters, i.e. the size of \f$\mu\f$, and \f$d\f$
   * the dimension of the image.
   */
  virtual void
  GetSpatialJacobian(const InputPointType & inputPoint, SpatialJacobianType & sj) const = 0;

  /** Override some pure virtual ITK4 functions. */
  void
  ComputeJacobianWithRespectToParameters(const InputPointType & itkNotUsed(p),
                                         JacobianType &         itkNotUsed(j)) const override
  {
    itkExceptionMacro("This ITK4 function is currently not used in elastix.");
  }


  /** Compute the spatial Hessian of the transformation.
   *
   * The spatial Hessian is the vector of matrices of partial second order
   * derivatives of the transformation components with respect to the spatial
   * position \f$x\f$, evaluated at a point \f$p\f$.
   *
   * \f[
      sH=\left[ \begin{array}{cc}
      \frac{\partial^2 T_{i}}{\partial x_{1} \partial x_{1}}(p) &
      \frac{\partial^2 T_{i}}{\partial x_{1} \partial x_{2}}(p) \\
      \frac{\partial^2 T_{i}}{\partial x_{1} \partial x_{2}}(p) &
      \frac{\partial^2 T_{i}}{\partial x_{2} \partial x_{2}}(p) \\
      \end{array}\right],
   * \f]
   * with i the i-th component of the transformation.
   */
  virtual void
  GetSpatialHessian(const InputPointType & inputPoint, SpatialHessianType & sh) const = 0;

  /** Compute the Jacobian of the spatial Jacobian of the transformation.
   *
   * The Jacobian of the spatial Jacobian is the derivative of the spatial
   * Jacobian to the transformation parameters \f$\mu\f$, evaluated at
   * a point \f$p\f$.
   */
  virtual void
  GetJacobianOfSpatialJacobian(const InputPointType &          inputPoint,
                               JacobianOfSpatialJacobianType & jsj,
                               NonZeroJacobianIndicesType &    nonZeroJacobianIndices) const = 0;

  /** Compute both the spatial Jacobian and the Jacobian of the
   * spatial Jacobian of the transformation.
   */
  virtual void
  GetJacobianOfSpatialJacobian(const InputPointType &          inputPoint,
                               SpatialJacobianType &           sj,
                               JacobianOfSpatialJacobianType & jsj,
                               NonZeroJacobianIndicesType &    nonZeroJacobianIndices) const = 0;

  /** Compute the Jacobian of the spatial Hessian of the transformation.
   *
   * The Jacobian of the spatial Hessian is the derivative of the spatial
   * Hessian to the transformation parameters \f$\mu\f$, evaluated at
   * a point \f$p\f$.
   */
  virtual void
  GetJacobianOfSpatialHessian(const InputPointType &         inputPoint,
                              JacobianOfSpatialHessianType & jsh,
                              NonZeroJacobianIndicesType &   nonZeroJacobianIndices) const = 0;

  /** Compute both the spatial Hessian and the Jacobian of the
   * spatial Hessian of the transformation.
   */
  virtual void
  GetJacobianOfSpatialHessian(const InputPointType &         inputPoint,
                              SpatialHessianType &           sh,
                              JacobianOfSpatialHessianType & jsh,
                              NonZeroJacobianIndicesType &   nonZeroJacobianIndices) const = 0;

protected:
  AdvancedTransform() = default;

  // Inherit the other (non-default) constructor from itk::Transform.
  using Superclass::Superclass;

  ~AdvancedTransform() override = default;

  bool m_HasNonZeroSpatialHessian{ true };
  bool m_HasNonZeroJacobianOfSpatialHessian{ true };
};

namespace ImplementationDetails
{
/** Multiplies the input matrix and the input vector. */
template <class TScalarType, unsigned int VInputVectorSize>
void
EvaluateInnerProduct(const vnl_matrix<TScalarType> &                        inputMatrix,
                     const CovariantVector<TScalarType, VInputVectorSize> & inputVector,
                     vnl_vector<TScalarType> &                              outputVector)
{
  assert(inputMatrix.rows() == inputVector.size());
  assert(inputMatrix.columns() == outputVector.size());

  auto inputMatrixIterator = inputMatrix.begin();

  outputVector.fill(0.0);

  for (const double inputVectorElement : inputVector)
  {
    for (auto & outputVectorElement : outputVector)
    {
      outputVectorElement += (*inputMatrixIterator) * inputVectorElement;
      ++inputMatrixIterator;
    }
  }
}
} // namespace ImplementationDetails

} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#  include "itkAdvancedTransform.hxx"
#endif

#endif