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 itkImageRegistrationMethod_hxx
19 #define itkImageRegistrationMethod_hxx
20 
21 #include "itkImageRegistrationMethod.h"
22 
23 namespace itk
24 {
25 /**
26  * Constructor
27  */
28 template< typename TFixedImage, typename TMovingImage >
29 ImageRegistrationMethod< TFixedImage, TMovingImage >
ImageRegistrationMethod()30 ::ImageRegistrationMethod()
31 {
32   this->SetNumberOfRequiredOutputs(1);    // for the Transform
33 
34   m_FixedImage   = nullptr; // has to be provided by the user.
35   m_MovingImage  = nullptr; // has to be provided by the user.
36   m_Transform    = nullptr; // has to be provided by the user.
37   m_Interpolator = nullptr; // has to be provided by the user.
38   m_Metric       = nullptr; // has to be provided by the user.
39   m_Optimizer    = nullptr; // has to be provided by the user.
40 
41   m_InitialTransformParameters = ParametersType(1);
42   m_LastTransformParameters = ParametersType(1);
43 
44   m_InitialTransformParameters.Fill(0.0f);
45   m_LastTransformParameters.Fill(0.0f);
46 
47   m_FixedImageRegionDefined = false;
48 
49   TransformOutputPointer transformDecorator =
50     itkDynamicCastInDebugMode< TransformOutputType * >(this->MakeOutput(0).GetPointer() );
51 
52   this->ProcessObject::SetNthOutput( 0, transformDecorator.GetPointer() );
53 
54   this->SetNumberOfWorkUnits( this->GetMultiThreader()->GetNumberOfWorkUnits() );
55 }
56 
57 /**
58  *
59  */
60 template< typename TFixedImage, typename TMovingImage >
61 ModifiedTimeType
62 ImageRegistrationMethod< TFixedImage, TMovingImage >
GetMTime() const63 ::GetMTime() const
64 {
65   ModifiedTimeType mtime = Superclass::GetMTime();
66   ModifiedTimeType m;
67 
68   // Some of the following should be removed once ivars are put in the
69   // input and output lists
70 
71   if ( m_Transform )
72     {
73     m = m_Transform->GetMTime();
74     mtime = ( m > mtime ? m : mtime );
75     }
76 
77   if ( m_Interpolator )
78     {
79     m = m_Interpolator->GetMTime();
80     mtime = ( m > mtime ? m : mtime );
81     }
82 
83   if ( m_Metric )
84     {
85     m = m_Metric->GetMTime();
86     mtime = ( m > mtime ? m : mtime );
87     }
88 
89   if ( m_Optimizer )
90     {
91     m = m_Optimizer->GetMTime();
92     mtime = ( m > mtime ? m : mtime );
93     }
94 
95   if ( m_FixedImage )
96     {
97     m = m_FixedImage->GetMTime();
98     mtime = ( m > mtime ? m : mtime );
99     }
100 
101   if ( m_MovingImage )
102     {
103     m = m_MovingImage->GetMTime();
104     mtime = ( m > mtime ? m : mtime );
105     }
106 
107   return mtime;
108 }
109 
110 /*
111  * Set the initial transform parameters
112  */
113 template< typename TFixedImage, typename TMovingImage >
114 void
115 ImageRegistrationMethod< TFixedImage, TMovingImage >
SetInitialTransformParameters(const ParametersType & param)116 ::SetInitialTransformParameters(const ParametersType & param)
117 {
118   m_InitialTransformParameters = param;
119   this->Modified();
120 }
121 
122 /**
123 
124  * Set the region of the fixed image to be considered for registration
125  */
126 template< typename TFixedImage, typename TMovingImage >
127 void
128 ImageRegistrationMethod< TFixedImage, TMovingImage >
SetFixedImageRegion(const FixedImageRegionType & region)129 ::SetFixedImageRegion(const FixedImageRegionType & region)
130 {
131   m_FixedImageRegion = region;
132   m_FixedImageRegionDefined = true;
133   this->Modified();
134 }
135 
136 /**
137  * Initialize by setting the interconnects between components.
138  */
139 template< typename TFixedImage, typename TMovingImage >
140 void
141 ImageRegistrationMethod< TFixedImage, TMovingImage >
Initialize()142 ::Initialize()
143 {
144   if ( !m_FixedImage )
145     {
146     itkExceptionMacro(<< "FixedImage is not present");
147     }
148 
149   if ( !m_MovingImage )
150     {
151     itkExceptionMacro(<< "MovingImage is not present");
152     }
153 
154   if ( !m_Metric )
155     {
156     itkExceptionMacro(<< "Metric is not present");
157     }
158 
159   if ( !m_Optimizer )
160     {
161     itkExceptionMacro(<< "Optimizer is not present");
162     }
163 
164   if ( !m_Transform )
165     {
166     itkExceptionMacro(<< "Transform is not present");
167     }
168 
169   //
170   // Connect the transform to the Decorator.
171   //
172   auto * transformOutput = static_cast< TransformOutputType * >( this->ProcessObject::GetOutput(0) );
173 
174   transformOutput->Set( m_Transform );
175 
176   if ( !m_Interpolator )
177     {
178     itkExceptionMacro(<< "Interpolator is not present");
179     }
180 
181   // Setup the metric
182   this->GetMultiThreader()->SetNumberOfWorkUnits( this->GetNumberOfWorkUnits() );
183   this->m_Metric->SetNumberOfWorkUnits( this->GetNumberOfWorkUnits() );
184   m_Metric->SetMovingImage(m_MovingImage);
185   m_Metric->SetFixedImage(m_FixedImage);
186   m_Metric->SetTransform(m_Transform);
187   m_Metric->SetInterpolator(m_Interpolator);
188 
189   if ( m_FixedImageRegionDefined )
190     {
191     m_Metric->SetFixedImageRegion(m_FixedImageRegion);
192     }
193   else
194     {
195     m_Metric->SetFixedImageRegion( m_FixedImage->GetBufferedRegion() );
196     }
197 
198   m_Metric->Initialize();
199 
200   // Setup the optimizer
201   m_Optimizer->SetCostFunction(m_Metric);
202 
203   // Validate initial transform parameters
204   if ( m_InitialTransformParameters.Size() !=
205        m_Transform->GetNumberOfParameters() )
206     {
207     itkExceptionMacro(<< "Size mismatch between initial parameters and transform."
208                       << "Expected " << m_Transform->GetNumberOfParameters() << " parameters and received "
209                       <<  m_InitialTransformParameters.Size() << " parameters");
210     }
211 
212   m_Optimizer->SetInitialPosition(m_InitialTransformParameters);
213 }
214 
215 /**
216  * Starts the Optimization process
217  */
218 template< typename TFixedImage, typename TMovingImage >
219 void
220 ImageRegistrationMethod< TFixedImage, TMovingImage >
StartOptimization()221 ::StartOptimization()
222 {
223   try
224     {
225     // do the optimization
226     m_Optimizer->StartOptimization();
227     }
228   catch ( ExceptionObject & err )
229     {
230     // An error has occurred in the optimization.
231     // Update the parameters
232     m_LastTransformParameters = m_Optimizer->GetCurrentPosition();
233 
234     // Pass exception to caller
235     throw err;
236     }
237 
238   // get the results
239   m_LastTransformParameters = m_Optimizer->GetCurrentPosition();
240   m_Transform->SetParameters(m_LastTransformParameters);
241 }
242 
243 /**
244  * PrintSelf
245  */
246 template< typename TFixedImage, typename TMovingImage >
247 void
248 ImageRegistrationMethod< TFixedImage, TMovingImage >
PrintSelf(std::ostream & os,Indent indent) const249 ::PrintSelf(std::ostream & os, Indent indent) const
250 {
251   Superclass::PrintSelf(os, indent);
252   os << indent << "Metric: " << m_Metric.GetPointer() << std::endl;
253   os << indent << "Optimizer: " << m_Optimizer.GetPointer() << std::endl;
254   os << indent << "Transform: " << m_Transform.GetPointer() << std::endl;
255   os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl;
256   os << indent << "Fixed Image: " << m_FixedImage.GetPointer() << std::endl;
257   os << indent << "Moving Image: " << m_MovingImage.GetPointer() << std::endl;
258   os << indent << "Fixed Image Region Defined: " << m_FixedImageRegionDefined << std::endl;
259   os << indent << "Fixed Image Region: " << m_FixedImageRegion << std::endl;
260   os << indent << "Initial Transform Parameters: " << m_InitialTransformParameters << std::endl;
261   os << indent << "Last    Transform Parameters: " << m_LastTransformParameters << std::endl;
262 }
263 
264 /*
265  * Generate Data
266  */
267 template< typename TFixedImage, typename TMovingImage >
268 void
269 ImageRegistrationMethod< TFixedImage, TMovingImage >
GenerateData()270 ::GenerateData()
271 {
272   ParametersType empty(1);
273   empty.Fill(0.0);
274   try
275     {
276     // initialize the interconnects between components
277     this->Initialize();
278     }
279   catch ( ExceptionObject & err )
280     {
281     m_LastTransformParameters = empty;
282 
283     // pass exception to caller
284     throw err;
285     }
286 
287   this->StartOptimization();
288 }
289 
290 /**
291  *  Get Output
292  */
293 template< typename TFixedImage, typename TMovingImage >
294 const typename ImageRegistrationMethod< TFixedImage, TMovingImage >::TransformOutputType *
295 ImageRegistrationMethod< TFixedImage, TMovingImage >
GetOutput() const296 ::GetOutput() const
297 {
298   return static_cast< const TransformOutputType * >( this->ProcessObject::GetOutput(0) );
299 }
300 
301 template< typename TFixedImage, typename TMovingImage >
302 DataObject::Pointer
303 ImageRegistrationMethod< TFixedImage, TMovingImage >
MakeOutput(DataObjectPointerArraySizeType output)304 ::MakeOutput(DataObjectPointerArraySizeType output)
305 {
306   if (output > 0)
307   {
308     itkExceptionMacro("MakeOutput request for an output number larger than the expected number of outputs.");
309   }
310   return TransformOutputType::New().GetPointer();
311 }
312 
313 template< typename TFixedImage, typename TMovingImage >
314 void
315 ImageRegistrationMethod< TFixedImage, TMovingImage >
SetFixedImage(const FixedImageType * fixedImage)316 ::SetFixedImage(const FixedImageType *fixedImage)
317 {
318   itkDebugMacro("setting Fixed Image to " << fixedImage);
319 
320   if ( this->m_FixedImage.GetPointer() != fixedImage )
321     {
322     this->m_FixedImage = fixedImage;
323 
324     // Process object is not const-correct so the const_cast is required here
325     this->ProcessObject::SetNthInput( 0,
326                                       const_cast< FixedImageType * >( fixedImage ) );
327 
328     this->Modified();
329     }
330 }
331 
332 template< typename TFixedImage, typename TMovingImage >
333 void
334 ImageRegistrationMethod< TFixedImage, TMovingImage >
SetMovingImage(const MovingImageType * movingImage)335 ::SetMovingImage(const MovingImageType *movingImage)
336 {
337   itkDebugMacro("setting Moving Image to " << movingImage);
338 
339   if ( this->m_MovingImage.GetPointer() != movingImage )
340     {
341     this->m_MovingImage = movingImage;
342 
343     // Process object is not const-correct so the const_cast is required here
344     this->ProcessObject::SetNthInput( 1,
345                                       const_cast< MovingImageType * >( movingImage ) );
346 
347     this->Modified();
348     }
349 }
350 
351 } // end namespace itk
352 #endif
353