1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkMINCTransformAdapter_h
19 #define itkMINCTransformAdapter_h
20 
21 #include "itkObject.h"
22 #include "itkPoint.h"
23 #include "itkVector.h"
24 #include "itkCovariantVector.h"
25 #include "vnl/vnl_matrix_fixed.h"
26 #include "vnl/vnl_vector_fixed.h"
27 #include "vnl/vnl_det.h"
28 #include "vnl/vnl_vector_fixed_ref.h"
29 #include "vnl/vnl_vector.h"
30 #include "itkTransform.h"
31 #include "itkObjectFactory.h"
32 
33 //minc header
34 #include "itk_minc2.h"
35 
36 namespace itk
37 {
38 
39 /** \class MINCTransformAdapter
40   * \ingroup  ITKIOTransformMINC
41   * \brief ITK wrapper around MINC general transform functions, supports all the transformations that MINC XFM supports
42   *
43   * \author Vladimir S. FONOV
44   *         Brain Imaging Center, Montreal Neurological Institute, McGill University, Montreal Canada 2012
45   * \ingroup ITKIOTransformMINC
46   */
47 template<typename TParametersValueType=double, unsigned int NInputDimensions=3,unsigned int NOutputDimensions=3>
48   class MINCTransformAdapter : public Transform<TParametersValueType, NInputDimensions, NOutputDimensions>
49 {
50 public:
51   ITK_DISALLOW_COPY_AND_ASSIGN(MINCTransformAdapter);
52 
53   /** Standard class type aliases. */
54   using Self = MINCTransformAdapter;
55 
56   using Superclass = Transform<TParametersValueType, NInputDimensions, NOutputDimensions>;
57 
58   using Pointer = SmartPointer<Self>;
59   using ConstPointer = SmartPointer<const Self>;
60 
61   using NumberOfParametersType = typename Superclass::NumberOfParametersType;
62 
63   /** New method for creating an object using a factory. */
64   itkNewMacro(Self);
65 
66   /** Run-time type information (and related methods). */
67   itkTypeMacro( MINCTransformAdapter, Transform );
68 
69   /** Dimension of the domain space. */
70   static constexpr unsigned int InputSpaceDimension = NInputDimensions;
71   static constexpr unsigned int OutputSpaceDimension = NOutputDimensions;
72 
73   /** Type of the input parameters. */
74   using ScalarType = double;
75 
76   /** Type of the input parameters. */
77   using ParametersType = typename Superclass::ParametersType;
78   using FixedParametersType = typename Superclass::FixedParametersType;
79 
80   /** Type of the Jacobian matrix. */
81   using JacobianType = typename Superclass::JacobianType;
82 
83   /** Standard vector type for this class. */
84   using InputVectorType = Vector<TParametersValueType, Self::InputSpaceDimension>;
85   using OutputVectorType = Vector<TParametersValueType, Self::OutputSpaceDimension>;
86 
87   /** Standard variable length vector type for this class
88   *  this provides an interface for the VectorImage class */
89   using InputVectorPixelType = VariableLengthVector<TParametersValueType>;
90   using OutputVectorPixelType = VariableLengthVector<TParametersValueType>;
91 
92   /** Standard covariant vector type for this class */
93   using InputCovariantVectorType = CovariantVector<TParametersValueType, Self::InputSpaceDimension>;
94 
95   using OutputCovariantVectorType = CovariantVector<TParametersValueType, Self::OutputSpaceDimension>;
96 
97   /** Standard coordinate point type for this class */
98   using InputPointType = Point<TParametersValueType,NInputDimensions >;
99   using OutputPointType = Point<TParametersValueType,NInputDimensions >;
100 
101   /** Standard vnl_vector type for this class. */
102   using InputVnlVectorType = vnl_vector_fixed<TParametersValueType, NInputDimensions>;
103   using OutputVnlVectorType = vnl_vector_fixed<TParametersValueType, NOutputDimensions>;
104 
105   /**  Method to transform a point. */
TransformPoint(const InputPointType & point)106   OutputPointType TransformPoint(const InputPointType  &point ) const override
107   {
108     if(!m_Initialized)
109       {
110       return point;
111       }
112 
113     if(m_Invert && !m_Initialized_invert)
114       {
115       return point;
116       }
117 
118     OutputPointType pnt;
119     //works only for 3D->3D transforms
120     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm), point[0], point[1], point[2], &pnt[0], &pnt[1], &pnt[2]);
121 
122     return pnt;
123   }
124 
125   //! use finate element difference to estimate local jacobian
estimate_local_jacobian(const InputPointType & orig,vnl_matrix_fixed<double,3,3> & m)126   void estimate_local_jacobian(const InputPointType  &orig, vnl_matrix_fixed< double, 3, 3 > &m)
127   {
128     double u1,v1,w1;
129     double u2,v2,w2;
130     const double delta=1e-4;
131 
132     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm) , orig[0]-delta, orig[1], orig[2],&u1, &v1, &w1);
133     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm) , orig[0]+delta, orig[1], orig[2],&u2, &v2, &w2);
134     m(0,0)=(u2-u1)/(2*delta);
135     m(0,1)=(v2-v1)/(2*delta);
136     m(0,2)=(w2-w1)/(2*delta);
137 
138     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm) , orig[0], orig[1]-delta, orig[2],&u1, &v1, &w1);
139     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm) , orig[0], orig[1]+delta, orig[2],&u2, &v2, &w2);
140     m(1,0)=(u2-u1)/(2*delta);
141     m(1,1)=(v2-v1)/(2*delta);
142     m(1,2)=(w2-w1)/(2*delta);
143 
144     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm), orig[0], orig[1], orig[2]-delta,&u1, &v1, &w1);
145     general_transform_point((m_Invert ? &m_Xfm_inv : &m_Xfm), orig[0], orig[1], orig[2]+delta,&u2, &v2, &w2);
146     m(2,0)=(u2-u1)/(2*delta);
147     m(2,1)=(v2-v1)/(2*delta);
148     m(2,2)=(w2-w1)/(2*delta);
149   }
150 
151   /**  Method to transform a vector. */
TransformVector(const InputVectorType & vector,const InputPointType &)152   OutputVectorType TransformVector( const InputVectorType& vector, const InputPointType &  ) const override
153   {
154     itkExceptionMacro( << "Not Implemented" );
155     return vector;
156   }
157 
158   /**  Method to transform a vector. */
TransformVector(const InputVnlVectorType & vector,const InputPointType &)159   OutputVnlVectorType TransformVector( const InputVnlVectorType& vector, const InputPointType & ) const override
160   {
161     itkExceptionMacro( << "Not Implemented" );
162     return vector;
163   }
164 
165   /**  Method to transform a vector. */
TransformVector(const InputVectorType & vector)166   OutputVectorType TransformVector( const InputVectorType& vector) const override
167   {
168     return Superclass::TransformVector(vector);
169   }
170 
171   /**  Method to transform a vector. */
TransformVector(const InputVnlVectorType & vector)172   OutputVnlVectorType TransformVector( const InputVnlVectorType& vector) const override
173   {
174     return Superclass::TransformVector(vector);
175   }
176 
177   /**  Method to transform a vector. */
TransformVector(const InputVectorPixelType & vector)178   OutputVectorPixelType TransformVector( const InputVectorPixelType& vector) const override
179   {
180     return Superclass::TransformVector(vector);
181   }
182 
183   /**  Method to transform a vector. */
TransformVector(const InputVectorPixelType & vector,const InputPointType &)184   OutputVectorPixelType TransformVector(
185     const InputVectorPixelType& vector,
186     const InputPointType & ) const override
187   {
188     itkExceptionMacro( << "Not Implemented" );
189     return vector;
190   }
191 
192   /**  Method to transform a CovariantVector. */
TransformCovariantVector(const InputCovariantVectorType & vector,const InputPointType &)193   OutputCovariantVectorType TransformCovariantVector(
194     const InputCovariantVectorType &vector
195   , const InputPointType & ) const override
196   {
197     itkExceptionMacro( << "Not Implemented" );
198     return vector;
199   }
200 
201 /**  Method to transform a CovariantVector. */
TransformCovariantVector(const InputCovariantVectorType & vector)202   OutputCovariantVectorType TransformCovariantVector(
203     const InputCovariantVectorType &vector) const override
204   {
205     return Superclass::TransformCovariantVector(vector);
206   }
207 
208 /**  Method to transform a CovariantVector. */
TransformCovariantVector(const InputVectorPixelType & vector)209   OutputVectorPixelType TransformCovariantVector(
210     const InputVectorPixelType &vector) const override
211   {
212     return Superclass::TransformCovariantVector(vector);
213   }
214 
215   /**  Method to transform a CovariantVector. */
TransformCovariantVector(const InputVectorPixelType & vector,const InputPointType &)216   OutputVectorPixelType TransformCovariantVector(
217     const InputVectorPixelType &vector, const InputPointType & ) const override
218   {
219     itkExceptionMacro( << "Not Implemented" );
220     return vector;
221   }
222 
223   /** Set the transformation to an Identity
224     */
SetIdentity()225   virtual void SetIdentity()
226   {
227     cleanup();
228   }
229 
SetFixedParameters(const FixedParametersType &)230   void SetFixedParameters(const FixedParametersType &) override
231   {
232     itkExceptionMacro( << "Not Implemented" );
233   }
234 
ComputeJacobianWithRespectToParameters(const InputPointType &,JacobianType &)235   void ComputeJacobianWithRespectToParameters(
236               const InputPointType &,
237               JacobianType &) const override
238   {
239     itkExceptionMacro( << "Not Implemented" );
240   }
241 
GetNumberOfParameters()242   NumberOfParametersType GetNumberOfParameters() const override
243   {
244     //this transform is defined by XFM file
245     itkExceptionMacro( << "Not Defined" );
246     return 0;
247   }
248 
249   /** Set the Transformation Parameters
250     * and update the internal transformation. */
SetParameters(const ParametersType &)251   void  SetParameters(const ParametersType &) override
252   {
253     itkExceptionMacro( << "Not Implemented" );
254   }
255 
GetParameters()256   const ParametersType & GetParameters() const override
257   {
258     itkExceptionMacro( << "Not Implemented" );
259     return m_Parameters;
260   }
261 
OpenXfm(const char * xfm)262   void OpenXfm(const char *xfm)
263   {
264     cleanup();
265     if(input_transform_file(xfm, &m_Xfm) != VIO_OK)
266       itkExceptionMacro( << "Error reading XFM:" << xfm );
267     m_Initialized=true;
268   }
269 
Invert()270   void Invert()
271   {
272     if(!m_Initialized)
273       itkExceptionMacro( << "XFM not initialized" );
274     if(!m_Initialized_invert)
275       {
276       create_inverse_general_transform(&m_Xfm,&m_Xfm_inv);
277       m_Initialized_invert=true;
278       }
279     m_Invert= !m_Invert;
280   }
281 
282 protected:
MINCTransformAdapter()283   MINCTransformAdapter():
284     Transform<TParametersValueType, NInputDimensions, NOutputDimensions>(0),
285     m_Invert(false),
286     m_Initialized(false),
287     m_Initialized_invert(false)
288   {
289     if(NInputDimensions!=3 || NOutputDimensions!=3)
290       itkExceptionMacro(<< "Sorry, only 3D to 3d minc xfm transform is currently implemented");
291   }
292 
~MINCTransformAdapter()293   ~MINCTransformAdapter() override
294   {
295     cleanup();
296   }
297 
cleanup()298   void cleanup()
299   {
300     if(m_Initialized)
301       {
302       delete_general_transform(&m_Xfm);
303       }
304     if(m_Initialized_invert)
305       {
306       delete_general_transform(&m_Xfm_inv);
307       }
308     m_Initialized=false;
309     m_Initialized_invert=false;
310   }
311 
312   ParametersType m_Parameters;
313 
314   mutable VIO_General_transform m_Xfm;
315   mutable VIO_General_transform m_Xfm_inv;
316 
317   bool m_Invert;
318   bool m_Initialized;
319   bool m_Initialized_invert;
320 };
321 
322 }
323 #endif //itkMINCTransformAdapter_h
324