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 
19 #ifndef itkObjectToObjectMultiMetricv4_h
20 #define itkObjectToObjectMultiMetricv4_h
21 
22 #include "itkObjectToObjectMetric.h"
23 #include "itkArray.h"
24 #include <deque>
25 
26 namespace itk
27 {
28 /** \class ObjectToObjectMultiMetricv4
29   * \brief This class takes one ore more ObjectToObject metrics and assigns weights to their derivatives
30   * to compute a single result.
31   *
32   * This class takes N ObjectToObject-derived component metrics and assigns a weight to each of the metrics'
33   * derivatives. It then computes a weighted measure of the metric. The GetValue() and
34   * GetValueAndDerivative() methods compute the measure and derivative using the following calculation:
35   *
36   * metric value = Sum_j ( w_j * M_j ) (see important note below)
37   *
38   * and the GetDerivative() method computes the derivative by computing:
39   *
40   * derivative = Sum_j ( w_j * dM_j / ||dM_j|| ) * ( Sum_j( ||dM_j|| ) / J )
41   *
42   * \note The metric value is unit-less, and thus it is difficult to compute a combined metric.
43   * This metric returns the metric value in three ways:
44   *  1) GetValue() returns the computed value of only the *first* component metric. This result
45   *     is stored in m_Value and also returned by GetCurrentValue().
46   *  2) GetValueArray() returns an itkArray of metric values, one for each component metric. It
47   *     only has meaning after a call to GetValue(), GetDerivative() or GetValueAndDerivative().
48   *  3) GetWeightedValue() returns a combined metric value of all component metrics, using the
49   *     assigned weights. It only has meaning after a call to GetValue(), GetDerivative()
50   *     or GetValueAndDerivative().
51   *
52   * The assigned weights are normalized internally to sum to one before use, and the weights
53   * default to 1/N, where N is the number of component metrics.
54   *
55   * \note Each component metric must use the same transform parameters object. That is, each metric
56   * must be evaluating the same parameters by evaluating the same transform. Except, if a component
57   * transform is a CompositeTransform, in which case it must be set to optimize a single transform,
58   * and that transform must be the same as the transform in other component metrics.
59   *
60   * \note Each component metric must be setup independently, except for the metric transforms
61   * which can optionally be set from this class. That is, each component's images or point sets,
62   * fixed transforms and options must be set independently. The only methods in this metric for setting
63   * up the component metrics is SetMovingTransform(). The corresponding
64   * Set accesor is also available. When Set{Fixed/Moving}Transform() is not used
65   * this metric's m_{Fixed/Moving}Transform member is assigned to the
66   * fixed/moving transform assigned to the first component metric.
67   *
68   * Each component will be initialized by this metric in the call to Initialize().
69   *
70   * \note When used with an itkRegistrationParameterScalesEstimator estimator, and the multi-metric
71   * holds one or more point-set metrics, the user must assign a virtual domain point set for sampling
72   * to ensure proper sampling within the point set metrics. In order to generate valid shift estimations,
73   * such a virtual domain point set must include mapped points from the fixed point set.
74   * See RegistrationParameterScalesEstimator::SetVirtualDomainPointSet() and
75   * PointSetToPointSetMetricv4::GetVirtualTransformedPointSet(). If there are two different point sets,
76   * then the virtual domain point set should be a union of the two for completeness.
77   *
78   * \note If the user does not explicitly assign a virtual domain, then the first valid virtual
79   * domain found in the component metrics will be used a virtual domain for this multi-metric,
80   * which will be queried by classes such as registration parameter estimators.
81   * Each componenet metric will still use its own virtual domain for internal calculations when
82   * evaluated, so it is possible to use different virtual domains for each metric if desired.
83   * If no component metric has a virtual domain defined, then by default the virtual domain is
84   * unbounded.
85   * When the transform is high dimensional (e.g. DisplacementFieldTransform) then there must
86   * be a virtual domain that matches the space of the transform field. Note that when used
87   * with a DisplacementFieldTransform, both Image and PointSet metrics will automatically
88   * create a matching virtual domain during initialization if one has not been assigned by the user.
89   *
90   * \ingroup ITKMetricsv4
91   */
92 template<unsigned int TFixedDimension, unsigned int TMovingDimension, typename TVirtualImage = Image<double, TFixedDimension>, class TInternalComputationValueType = double >
93 class ITK_TEMPLATE_EXPORT ObjectToObjectMultiMetricv4:
94   public ObjectToObjectMetric<TFixedDimension, TMovingDimension, TVirtualImage, TInternalComputationValueType>
95 {
96 public:
97   ITK_DISALLOW_COPY_AND_ASSIGN(ObjectToObjectMultiMetricv4);
98 
99   /** Standard class type aliases */
100   using Self = ObjectToObjectMultiMetricv4;
101   using Superclass = ObjectToObjectMetric<TFixedDimension, TMovingDimension, TVirtualImage, TInternalComputationValueType>;
102   using Pointer = SmartPointer<Self>;
103   using ConstPointer = SmartPointer<const Self>;
104 
105   /** Run-time type information (and related methods). */
106   itkTypeMacro(ObjectToObjectMultiMetricv4, ObjectToObjectMetric);
107 
108   /** New macro for creation of through a Smart Pointer */
109   itkNewMacro( Self );
110 
111   /** Types inherited from Superclass. */
112   using MeasureType = typename Superclass::MeasureType;
113   using DerivativeType = typename Superclass::DerivativeType;
114   using DerivativeValueType = typename Superclass::DerivativeValueType;
115   using ParametersType = typename Superclass::ParametersType;
116   using ParametersValueType = typename Superclass::ParametersValueType;
117   using NumberOfParametersType = typename Superclass::NumberOfParametersType;
118   using CoordinateRepresentationType = typename Superclass::CoordinateRepresentationType;
119   using MovingTransformType = typename Superclass::MovingTransformType;
120   using FixedTransformType = typename Superclass::FixedTransformType;
121 
122   /** type alias related to the metric queue */
123   using MetricType = Superclass;
124   using MetricBasePointer = typename MetricType::Pointer;
125   using MetricBaseConstPointer = typename MetricType::ConstPointer;
126   using MetricQueueType = std::deque<MetricBasePointer>;
127 
128   using ObjectType = typename Superclass::ObjectType;
129 
130   using WeightValueType = typename DerivativeType::ValueType;
131   using WeightsArrayType = Array<WeightValueType>;
132   using MetricValueArrayType = Array<MeasureType>;
133 
134   itkSetMacro(MetricWeights,WeightsArrayType);
135   itkGetMacro(MetricWeights,WeightsArrayType);
136 
137   /** Add a metric to the queue */
138   void AddMetric( MetricType* metric );
139 
140   /** Clear the metric queue */
141   void ClearMetricQueue();
142 
143   /** Get the number of metrics */
144   SizeValueType GetNumberOfMetrics() const;
145 
146   void Initialize() override;
147 
148   /** Set fixed object (image, point set, etc.)*/
SetFixedObject(const ObjectType * itkNotUsed (object))149   void SetFixedObject( const ObjectType *itkNotUsed( object ) ) override
150     {
151     itkExceptionMacro( "A single object should not be specified for the multi metric.");
152     }
153 
154   /** Set moving object (image, point set, etc.)*/
SetMovingObject(const ObjectType * itkNotUsed (object))155   void SetMovingObject( const ObjectType *itkNotUsed( object ) ) override
156     {
157     itkExceptionMacro( "A single object should not be specified for the multi metric.");
158     }
159 
160   /** Set each of the component metrics to use this moving transform. */
161   void SetMovingTransform( MovingTransformType * ) override;
162 
163   /** Set each of the component metrics to use this fixed transform. */
164   void SetFixedTransform( FixedTransformType * ) override;
165 
166   /** Evaluate the metrics and return the value of only the *first* metric.
167    * \sa GetValueArray
168    * \sa GetWeightedValue
169    */
170   MeasureType GetValue() const override;
171 
172   void GetDerivative( DerivativeType & ) const override;
173 
174   /** Evaluate the metric value and derivative.
175    * \note \param value will contain the value of only the *first* metric on return.
176    * \param derivative holds the combined derivative on return.
177    *
178    * \sa GetValueArray
179    * \sa GetWeightedValue */
180   void GetValueAndDerivative(MeasureType & value, DerivativeType & derivative) const override;
181 
182   /** Returns an itkArray of metric values, one for each component metric. It
183    *  only has meaning after a call to GetValue(), GetDerivative() or GetValueAndDerivative(). */
184   MetricValueArrayType GetValueArray() const;
185 
186   /**  Returns a combined metric value of all component metrics, using the
187    *   assigned weights. It only has meaning after a call to GetValue(), GetDerivative() or GetValueAndDerivative(). */
188   MeasureType GetWeightedValue() const;
189 
190   /** Get the metrics queue */
191   const MetricQueueType & GetMetricQueue() const;
192 
193   bool SupportsArbitraryVirtualDomainSamples() const override;
194 
195   using MetricCategoryType = typename Superclass::MetricCategoryType;
196 
197   /** Get metric category */
GetMetricCategory()198   MetricCategoryType GetMetricCategory() const override
199     {
200     return Superclass::MULTI_METRIC;
201     }
202 
203 protected:
204 
205   ObjectToObjectMultiMetricv4();
206   ~ObjectToObjectMultiMetricv4() override = default;
207   void PrintSelf(std::ostream & os, Indent indent) const override;
208 
209 private:
210   MetricQueueType               m_MetricQueue;
211   WeightsArrayType              m_MetricWeights;
212   mutable MetricValueArrayType  m_MetricValueArray;
213 };
214 
215 } //end namespace itk
216 
217 #ifndef ITK_MANUAL_INSTANTIATION
218 #include "itkObjectToObjectMultiMetricv4.hxx"
219 #endif
220 
221 #endif
222