-
Notifications
You must be signed in to change notification settings - Fork 138
ENH: Add support for multiple metrics and regularization #1437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| #ifndef itkCombinationImageToImageMetric_h | ||
| #define itkCombinationImageToImageMetric_h | ||
|
|
||
| #include "itkTransformPenaltyTerm.h" | ||
| #include "itkAdvancedImageToImageMetric.h" | ||
| #include "itkSingleValuedPointSetToPointSetMetric.h" | ||
|
|
||
|
|
@@ -131,6 +132,10 @@ class ITK_TEMPLATE_EXPORT CombinationImageToImageMetric : public AdvancedImageTo | |
| using MovingImageRegionType = typename MovingImageType::RegionType; | ||
| using MovingImageDerivativeScalesType = FixedArray<double, Self::MovingImageDimension>; | ||
|
|
||
| /** Typedef for transform penalty metrics. */ | ||
| typedef TransformPenaltyTerm<TFixedImage> TransformMetricType; | ||
| typedef typename TransformMetricType::Pointer TransformMetricPointer; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| /** Typedef for the PointSetMetric. */ | ||
| using FixedPointSetType = PointSet<CoordinateRepresentationType, | ||
| TFixedImage::ImageDimension, | ||
|
|
@@ -163,6 +168,9 @@ class ITK_TEMPLATE_EXPORT CombinationImageToImageMetric : public AdvancedImageTo | |
|
|
||
| /** Get the number of metrics to combine. */ | ||
| itkGetConstMacro(NumberOfMetrics, unsigned int); | ||
| itkGetConstMacro(NumberOfImageMetrics, unsigned int); | ||
| itkGetConstMacro(NumberOfTransformMetrics, unsigned int); | ||
| itkGetConstMacro(NumberOfPointSetMetrics, unsigned int); | ||
|
|
||
| /** Set metric i. It may be a SingleValuedCostFunction, instead of | ||
| * a ImageToImageMetric, but the first one should be an | ||
|
|
@@ -453,6 +461,9 @@ class ITK_TEMPLATE_EXPORT CombinationImageToImageMetric : public AdvancedImageTo | |
| private: | ||
| /** Store the metrics and the corresponding weights. */ | ||
| unsigned int m_NumberOfMetrics{ 0 }; | ||
| unsigned int m_NumberOfImageMetrics{ 0 }; | ||
| unsigned int m_NumberOfTransformMetrics{ 0 }; | ||
| unsigned int m_NumberOfPointSetMetrics{ 0 }; | ||
| std::vector<SingleValuedCostFunctionPointer> m_Metrics{}; | ||
| std::vector<double> m_MetricWeights{}; | ||
| std::vector<double> m_MetricRelativeWeights{}; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -160,6 +160,9 @@ CombinationImageToImageMetric<TFixedImage, TMovingImage>::PrintSelf(std::ostream | |
|
|
||
| /** Add debugging information. */ | ||
| os << "NumberOfMetrics: " << this->m_NumberOfMetrics << std::endl; | ||
| os << "NumberOfImageMetrics: " << this->m_NumberOfImageMetrics << std::endl; | ||
| os << "NumberOfTransformMetrics: " << this->m_NumberOfTransformMetrics << std::endl; | ||
| os << "NumberOfPointSetMetrics: " << this->m_NumberOfPointSetMetrics << std::endl; | ||
| for (unsigned int i = 0; i < this->m_NumberOfMetrics; ++i) | ||
| { | ||
| os << "Metric " << i << ":\n"; | ||
|
|
@@ -275,12 +278,51 @@ CombinationImageToImageMetric<TFixedImage, TMovingImage>::SetMetric(SingleValued | |
| this->SetNumberOfMetrics(pos + 1); | ||
| } | ||
|
|
||
| if (metric != this->m_Metrics[pos]) | ||
| SingleValuedCostFunctionPointer oldMetricPtr = this->m_Metrics[pos]; | ||
| if (metric == oldMetricPtr) | ||
| { | ||
| this->m_Metrics[pos] = metric; | ||
| this->Modified(); | ||
| return; | ||
| } | ||
|
|
||
| PointSetMetricType * testPtr1 = dynamic_cast<PointSetMetricType *>(metric); | ||
| TransformMetricType * testPtr2 = dynamic_cast<TransformMetricType *>(metric); | ||
|
|
||
| // Increase newly defined numberOfMetric counters | ||
| if (testPtr1) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make it: And remove the local Similar for |
||
| { | ||
| this->m_NumberOfPointSetMetrics++; | ||
| } | ||
| else if (testPtr2) | ||
| { | ||
| this->m_NumberOfTransformMetrics++; | ||
| } | ||
| else | ||
| { | ||
| this->m_NumberOfImageMetrics++; | ||
| } | ||
|
|
||
| // if the metric has already been set, decrease the correct counter | ||
| if (oldMetricPtr != nullptr) | ||
| { | ||
| PointSetMetricType * oldTestPtr1 = dynamic_cast<PointSetMetricType *>(oldMetricPtr.GetPointer()); | ||
| TransformMetricType * oldTestPtr2 = dynamic_cast<TransformMetricType *>(oldMetricPtr.GetPointer()); | ||
| if (oldTestPtr1) | ||
| { | ||
| this->m_NumberOfPointSetMetrics--; | ||
| } | ||
| else if (oldTestPtr2) | ||
| { | ||
| this->m_NumberOfTransformMetrics--; | ||
| } | ||
| else | ||
| { | ||
| this->m_NumberOfImageMetrics--; | ||
| } | ||
| } | ||
|
|
||
| this->m_Metrics[pos] = metric; | ||
| this->Modified(); | ||
|
|
||
| } // end SetMetric() | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -565,44 +565,44 @@ MultiMetricMultiResolutionImageRegistrationMethod<TFixedImage, TMovingImage>::Ch | |
| } | ||
|
|
||
| /** nrofmetrics >= nrofinterpolators >= nrofpyramids >= nofimages */ | ||
| unsigned int nrOfMetrics = m_CombinationMetric->GetNumberOfMetrics(); | ||
| if (this->GetNumberOfInterpolators() > nrOfMetrics) | ||
| unsigned int nrOfImageMetrics = this->GetCombinationMetric()->GetNumberOfImageMetrics(); | ||
| if (this->GetNumberOfInterpolators() > nrOfImageMetrics) | ||
| { | ||
| itkExceptionMacro("NumberOfInterpolators can not exceed the NumberOfMetrics in the CombinationMetric!"); | ||
| itkExceptionMacro("NumberOfInterpolators can not exceed the nrOfImageMetrics in the CombinationMetric!"); | ||
| } | ||
| if (this->GetNumberOfFixedImagePyramids() > nrOfMetrics) | ||
| if (this->GetNumberOfFixedImagePyramids() > nrOfImageMetrics) | ||
| { | ||
| itkExceptionMacro("NumberOfFixedImagePyramids can not exceed the NumberOfMetrics in the CombinationMetric!"); | ||
| itkExceptionMacro("NumberOfFixedImagePyramids can not exceed the nrOfImageMetrics in the CombinationMetric!"); | ||
| } | ||
| if (this->GetNumberOfMovingImagePyramids() > nrOfMetrics) | ||
| if (this->GetNumberOfMovingImagePyramids() > nrOfImageMetrics) | ||
| { | ||
| itkExceptionMacro("NumberOfMovingImagePyramids can not exceed the NumberOfMetrics in the CombinationMetric!"); | ||
| itkExceptionMacro("NumberOfMovingImagePyramids can not exceed the nrOfImageMetrics in the CombinationMetric!"); | ||
| } | ||
| if (this->GetNumberOfMovingImagePyramids() > this->GetNumberOfInterpolators()) | ||
| { | ||
| itkExceptionMacro("NumberOfMovingImagePyramids can not exceed the NumberOfInterpolators!"); | ||
| } | ||
|
|
||
| /** For all components: ==nrofmetrics of ==1. */ | ||
| if ((this->GetNumberOfInterpolators() != 1) && (this->GetNumberOfInterpolators() != nrOfMetrics)) | ||
| /** For all components: ==nrOfImageMetrics of ==1. */ | ||
| if ((this->GetNumberOfInterpolators() != 1) && (this->GetNumberOfInterpolators() != nrOfImageMetrics)) | ||
| { | ||
| itkExceptionMacro("The NumberOfInterpolators should equal 1 or equal the NumberOfMetrics"); | ||
| itkExceptionMacro("The NumberOfInterpolators should equal 1 or equal the nrOfImageMetrics"); | ||
| } | ||
| if ((this->GetNumberOfFixedImagePyramids() != 1) && (this->GetNumberOfFixedImagePyramids() != nrOfMetrics)) | ||
| if ((this->GetNumberOfFixedImagePyramids() != 1) && (this->GetNumberOfFixedImagePyramids() != nrOfImageMetrics)) | ||
| { | ||
| itkExceptionMacro("The NumberOfFixedImagePyramids should equal 1 or equal the NumberOfMetrics"); | ||
| itkExceptionMacro("The NumberOfFixedImagePyramids should equal 1 or equal the nrOfImageMetrics"); | ||
| } | ||
| if ((this->GetNumberOfMovingImagePyramids() != 1) && (this->GetNumberOfMovingImagePyramids() != nrOfMetrics)) | ||
| if ((this->GetNumberOfMovingImagePyramids() != 1) && (this->GetNumberOfMovingImagePyramids() != nrOfImageMetrics)) | ||
| { | ||
| itkExceptionMacro("The NumberOfMovingImagePyramids should equal 1 or equal the NumberOfMetrics"); | ||
| itkExceptionMacro("The NumberOfMovingImagePyramids should equal 1 or equal the nrOfImageMetrics"); | ||
| } | ||
| if ((this->GetNumberOfFixedImages() != 1) && (this->GetNumberOfFixedImages() != nrOfMetrics)) | ||
| if ((this->GetNumberOfFixedImages() != 1) && (this->GetNumberOfFixedImages() != nrOfImageMetrics)) | ||
| { | ||
| itkExceptionMacro("The NumberOfFixedImages should equal 1 or equal the NumberOfMetrics"); | ||
| itkExceptionMacro("The NumberOfFixedImages should equal 1 or equal the nrOfImageMetrics"); | ||
| } | ||
| if ((this->GetNumberOfMovingImages() != 1) && (this->GetNumberOfMovingImages() != nrOfMetrics)) | ||
| if ((this->GetNumberOfMovingImages() != 1) && (this->GetNumberOfMovingImages() != nrOfImageMetrics)) | ||
| { | ||
| itkExceptionMacro("The NumberOfMovingImages should equal 1 or equal the NumberOfMetrics"); | ||
| itkExceptionMacro("The NumberOfMovingImages should equal 1 or equal the nrOfImageMetrics"); | ||
|
Comment on lines
-603
to
+605
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stefanklein @mstaring Would this change (comparing the number of input images with the number of image metrics, instead of the total number of metrics) break legacy use cases that would use "dummy" images when they use multiple metrics? If so, shall we still allow such legacy use cases, by relaxing this check? |
||
| } | ||
|
|
||
| } // end CheckOnInitialize() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nowadays, we are using
using, instead oftypedef. But a coding style issue like that is not a show-stopper. I can adjust it afterwards. Also, I think I would move the definition ofTransformMetricTypeinto the function body ofCombinationImageToImageMetric::SetMetric, as that seems to be the only place where it is needed.