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