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