21 #ifndef otbFineRegistrationImageFilter_hxx
22 #define otbFineRegistrationImageFilter_hxx
26 #include "itkProgressReporter.h"
27 #include "itkLinearInterpolateImageFunction.h"
28 #include "itkImageRegionIteratorWithIndex.h"
29 #include "itkNormalizedCorrelationImageToImageMetric.h"
37 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
40 this->SetNumberOfRequiredInputs(2);
41 this->SetNumberOfRequiredOutputs(2);
42 this->SetNthOutput(1, TOutputDisplacementField::New());
47 m_SearchRadius.Fill(4);
50 m_SubPixelAccuracy = 0.1;
51 m_ConvergenceAccuracy = 0.01;
61 m_Metric = itk::NormalizedCorrelationImageToImageMetric<TInputImage, TInputImage>::New();
64 m_Interpolator = itk::LinearInterpolateImageFunction<TInputImage, double>::New();
67 m_Translation = TranslationType::New();
73 m_InitialOffset.Fill(0);
75 m_Transform =
nullptr;
78 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
82 this->SetNthInput(0,
const_cast<TInputImage*
>(image));
85 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
89 this->SetNthInput(1,
const_cast<TInputImage*
>(image));
92 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
95 if (this->GetNumberOfInputs() < 1)
99 return static_cast<const TInputImage*
>(this->itk::ProcessObject::GetInput(0));
102 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
105 if (this->GetNumberOfInputs() < 2)
109 return static_cast<const TInputImage*
>(this->itk::ProcessObject::GetInput(1));
112 template <
class TInputImage,
class T0utputCorrelation,
class TOutputDisplacementField>
115 if (this->GetNumberOfOutputs() < 2)
119 return static_cast<TOutputDisplacementField*
>(this->itk::ProcessObject::GetOutput(1));
122 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
126 Superclass::GenerateOutputInformation();
129 TOutputCorrelation* outputPtr = this->GetOutput();
130 TOutputDisplacementField* outputFieldPtr = this->GetOutputDisplacementField();
134 SizeType outputSize = largestRegion.GetSize();
135 SpacingType outputSpacing = outputPtr->GetSignedSpacing();
137 for (
unsigned int dim = 0; dim < TOutputCorrelation::ImageDimension; ++dim)
139 outputSize[dim] /= m_GridStep[dim];
140 outputSpacing[dim] *= m_GridStep[dim];
144 outputPtr->SetSignedSpacing(outputSpacing);
145 outputFieldPtr->SetSignedSpacing(outputSpacing);
148 largestRegion.SetSize(outputSize);
149 outputPtr->SetLargestPossibleRegion(largestRegion);
150 outputFieldPtr->SetLargestPossibleRegion(largestRegion);
153 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
157 Superclass::GenerateInputRequestedRegion();
160 TInputImage* fixedPtr =
const_cast<TInputImage*
>(this->GetFixedInput());
161 TInputImage* movingPtr =
const_cast<TInputImage*
>(this->GetMovingInput());
163 TOutputCorrelation* outputPtr = this->GetOutput();
165 if (!fixedPtr || !movingPtr || !outputPtr)
173 fixedRequestedRegion = outputPtr->GetRequestedRegion();
176 SizeType fixedRequestedSize = fixedRequestedRegion.GetSize();
177 IndexType fixedRequestedIndex = fixedRequestedRegion.GetIndex();
179 for (
unsigned int dim = 0; dim < TOutputCorrelation::ImageDimension; ++dim)
181 fixedRequestedSize[dim] *= m_GridStep[dim];
182 fixedRequestedIndex[dim] *= m_GridStep[dim];
185 fixedRequestedRegion.SetSize(fixedRequestedSize);
186 fixedRequestedRegion.SetIndex(fixedRequestedIndex);
189 fixedRequestedRegion.PadByRadius(m_Radius);
195 searchFixedRequestedRegion.PadByRadius(m_SearchRadius);
199 IndexType ulIndex = searchFixedRequestedRegion.GetIndex();
202 for (
unsigned int dim = 0; dim < TInputImage::ImageDimension; ++dim)
204 lrIndex[dim] = searchFixedRequestedRegion.GetIndex()[dim] + searchFixedRequestedRegion.GetSize()[dim] - 1;
209 fixedPtr->TransformIndexToPhysicalPoint(lrIndex, lrPoint);
210 fixedPtr->TransformIndexToPhysicalPoint(ulIndex, ulPoint);
213 lrPoint += m_InitialOffset;
214 ulPoint += m_InitialOffset;
217 IndexType movingIndex1, movingIndex2, movingIndex;
218 movingPtr->TransformPhysicalPointToIndex(ulPoint, movingIndex1);
219 movingPtr->TransformPhysicalPointToIndex(lrPoint, movingIndex2);
224 for (
unsigned int dim = 0; dim < TInputImage::ImageDimension; ++dim)
226 movingIndex[dim] = std::min(movingIndex1[dim], movingIndex2[dim]);
227 movingSize[dim] = std::max(movingIndex1[dim], movingIndex2[dim]) - movingIndex[dim] + 1;
230 movingRequestedRegion.SetIndex(movingIndex);
231 movingRequestedRegion.SetSize(movingSize);
234 if (fixedRequestedRegion.Crop(fixedPtr->GetLargestPossibleRegion()))
236 fixedPtr->SetRequestedRegion(fixedRequestedRegion);
243 fixedPtr->SetRequestedRegion(fixedRequestedRegion);
246 itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
247 std::ostringstream msg;
248 msg << this->GetNameOfClass() <<
"::GenerateInputRequestedRegion()";
249 e.SetLocation(msg.str());
250 e.SetDescription(
"Requested region is (at least partially) outside the largest possible region of image 1.");
251 e.SetDataObject(fixedPtr);
256 if (movingRequestedRegion.Crop(movingPtr->GetLargestPossibleRegion()))
258 movingPtr->SetRequestedRegion(movingRequestedRegion);
266 movingRequestedRegion.SetSize(movingSize);
268 movingRequestedRegion.SetIndex(movingIndex);
271 movingPtr->SetRequestedRegion(movingRequestedRegion);
276 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
279 typename TranslationType::ParametersType paramsgn(2);
288 res = m_Metric->GetValue(paramsgn);
290 catch (itk::ExceptionObject& err)
293 itkWarningMacro(<< err.GetDescription());
299 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
301 double potBestVal,
double parx,
double pary,
double& bestVal,
typename TranslationType::ParametersType& optParams)
303 if (bestVal > potBestVal)
305 bestVal = potBestVal;
312 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
314 double& out1,
double& out2,
double& out3,
319 out3 = in1 + gn * (in2 - in1);
320 out4 = in2 - gn * (in2 - in1);
324 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
335 template <
class TInputImage,
class TOutputCorrelation,
class TOutputDisplacementField>
339 this->AllocateOutputs();
342 const TInputImage* fixedPtr = this->GetFixedInput();
343 const TInputImage* movingPtr = this->GetMovingInput();
344 TOutputCorrelation* outputPtr = this->GetOutput();
345 TOutputDisplacementField* outputDfPtr = this->GetOutputDisplacementField();
348 m_Interpolator->SetInputImage(this->GetMovingInput());
349 m_Metric->SetTransform(m_Translation);
350 m_Metric->SetInterpolator(m_Interpolator);
351 m_Metric->SetFixedImage(fixedPtr);
352 m_Metric->SetMovingImage(movingPtr);
353 m_Metric->SetComputeGradient(
false);
356 itk::ImageRegionIteratorWithIndex<TOutputCorrelation> outputIt(outputPtr, outputPtr->GetRequestedRegion());
357 itk::ImageRegionIterator<TOutputDisplacementField> outputDfIt(outputDfPtr, outputPtr->GetRequestedRegion());
358 outputIt.GoToBegin();
359 outputDfIt.GoToBegin();
363 itk::ProgressReporter progress(
this, 0, outputPtr->GetRequestedRegion().GetNumberOfPixels());
366 outputIt.GoToBegin();
367 outputDfIt.GoToBegin();
370 double currentMetric, optMetric;
373 typename TranslationType::ParametersType params(2), optParams(2);
377 displacementValue[0] = m_InitialOffset[0];
378 displacementValue[1] = m_InitialOffset[1];
384 SpacingType fixedSpacing = fixedPtr->GetSignedSpacing();
388 while (!outputIt.IsAtEnd() && !outputDfIt.IsAtEnd())
393 optMetric = itk::NumericTraits<double>::max();
397 optMetric = itk::NumericTraits<double>::NonpositiveMin();
405 IndexType currentIndex = outputIt.GetIndex();
406 for (
unsigned int dim = 0; dim < TInputImage::ImageDimension; ++dim)
408 currentIndex[dim] *= m_GridStep[dim];
410 currentMetricRegion.SetIndex(currentIndex);
413 currentMetricRegion.SetSize(size);
414 currentMetricRegion.PadByRadius(m_Radius);
415 currentMetricRegion.Crop(fixedPtr->GetLargestPossibleRegion());
416 m_Metric->SetFixedImageRegion(currentMetricRegion);
417 m_Metric->Initialize();
421 if (m_Transform.IsNotNull())
424 for (
unsigned int dim = 0; dim < TInputImage::ImageDimension; ++dim)
426 inputPoint[dim] = currentIndex[dim];
428 outputPoint = m_Transform->TransformPoint(inputPoint);
429 for (
unsigned int dim = 0; dim < TInputImage::ImageDimension; ++dim)
431 localOffset[dim] = outputPoint[dim] - inputPoint[dim];
436 for (
int i = -
static_cast<int>(m_SearchRadius[0]); i <= static_cast<int>(m_SearchRadius[0]); ++i)
438 for (
int j = -
static_cast<int>(m_SearchRadius[1]); j <= static_cast<int>(m_SearchRadius[1]); ++j)
440 params[0] = localOffset[0] +
static_cast<double>(i * fixedSpacing[0]);
441 params[1] = localOffset[1] +
static_cast<double>(j * fixedSpacing[1]);
446 currentMetric = m_Metric->GetValue(params);
449 if ((m_Minimize && (currentMetric < optMetric)) || (!m_Minimize && (currentMetric > optMetric)))
451 optMetric = currentMetric;
455 catch (itk::ExceptionObject& err)
457 itkWarningMacro(<< err.GetDescription());
464 typename TranslationType::ParametersType paramsgn(2);
465 double gn = (sqrt(5.0) - 1.0) / 2.0;
467 double ax = optParams[0] -
static_cast<double>(subPixelSpacing[0]);
468 double ay = optParams[1] -
static_cast<double>(subPixelSpacing[1]);
469 double bx = optParams[0] +
static_cast<double>(subPixelSpacing[0]);
470 double by = optParams[1] +
static_cast<double>(subPixelSpacing[1]);
473 double cx = bx - gn * (bx - ax);
474 double cy = optParams[1];
475 double dx = ax + gn * (bx - ax);
476 double dy = optParams[1];
477 double fc = 0, fd = 0;
478 bool exitWhile =
false;
480 double bestvalold = itk::NumericTraits<double>::max(), bestval = optMetric;
481 double diff = itk::NumericTraits<double>::max();
482 double diffx = itk::NumericTraits<double>::max();
483 double diffy = itk::NumericTraits<double>::max();
486 fc = callMetric(cx, cy, fc, exitWhile);
487 fd = callMetric(dx, dy, fd, exitWhile);
488 updateMinimize(fc, fd);
491 while ((diffx > m_SubPixelAccuracy || diffy > m_SubPixelAccuracy) && (diff > m_ConvergenceAccuracy) && (!exitWhile) && (nbIter <= m_MaxIter))
498 updateOptParams(fc, cx, cy, bestval, optParams);
499 updatePoints(gn, ay, by, cx, bx, dx, dy, cy);
500 fc = callMetric(cx, cy, fc, exitWhile);
501 fd = callMetric(dx, dy, fd, exitWhile);
505 updateOptParams(fd, dx, dy, bestval, optParams);
506 updatePoints(gn, by, ay, dx, ax, cx, cy, dy);
507 fc = callMetric(cx, cy, fc, exitWhile);
508 fd = callMetric(dx, dy, fd, exitWhile);
510 updateMinimize(fc, fd);
515 updateOptParams(fc, cx, cy, bestval, optParams);
516 updatePoints(gn, ax, bx, cy, by, dy, dx, cx);
517 fc = callMetric(cx, cy, fc, exitWhile);
518 fd = callMetric(dx, dy, fd, exitWhile);
522 updateOptParams(fd, dx, dy, bestval, optParams);
523 updatePoints(gn, bx, ax, dy, ay, cy, cx, dx);
524 fc = callMetric(cx, cy, fc, exitWhile);
525 fd = callMetric(dx, dy, fd, exitWhile);
527 updateMinimize(fc, fd);
530 updateOptParams(fd, dx, dy, bestval, optParams);
531 updateOptParams(fc, cx, cy, bestval, optParams);
536 diff = fabs(bestval - bestvalold);
537 bestvalold = bestval;
538 diffx = fabs(bx - ax);
539 diffy = fabs(by - ay);
543 outputIt.Set(optMetric);
546 displacementValue[0] = optParams[0];
547 displacementValue[1] = optParams[1];
551 displacementValue[0] = optParams[0] / fixedSpacing[0];
552 displacementValue[1] = optParams[1] / fixedSpacing[1];
554 outputDfIt.Set(displacementValue);
562 progress.CompletedPixel();