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 itkMultiTransform_h 19 #define itkMultiTransform_h 20 21 #include "itkTransform.h" 22 23 #include <deque> 24 25 namespace itk 26 { 27 28 /** \class MultiTransform 29 * \brief This abstract class contains a list of transforms and provides basic methods. 30 * 31 * This abstract base class is used by classes that operate on a list of 32 * sub-transforms. The sub-transforms can have a different dimensionality 33 * than the container transform. 34 * 35 * Transforms are stored in a container (queue), in the following order: 36 * \f$ T_0, T_1, ... , T_N-1 \f$ 37 * 38 * Transforms are added via a single method, AddTransform(). This adds the 39 * transforms to the back of the queue. A single method for adding transforms 40 * is meant to simplify the interface and prevent errors. 41 * 42 * Inverse 43 * todo 44 * 45 * TODO 46 * 47 * Interface Issues/Comments 48 * x The PushFrontTransform and PushBackTransform methods are protected to 49 * force the user to use the AddTransform method, forcing the order of 50 * transforms. Are there use cases where the user would *need* to insert 51 * transforms at the front of the queue? Or at arbitrary positions? 52 * 53 * GetParameters efficiency optimization 54 * Can we optimize this to only query the sub-transforms when the params 55 * in the sub transforms have changed since the previous call? Can't use 56 * Modified time b/c that will get updated in sub-transforms with every 57 * call to SetParameters. Is this worth worrying about? i.e. how much time 58 * will it take in the overall registration process? Probably very little. 59 * 60 * \ingroup ITKTransform 61 */ 62 template 63 <typename TParametersValueType=double, unsigned int NDimensions=3, unsigned int NSubDimensions=NDimensions> 64 class ITK_TEMPLATE_EXPORT MultiTransform : 65 public Transform<TParametersValueType, NDimensions, NSubDimensions> 66 { 67 public: 68 ITK_DISALLOW_COPY_AND_ASSIGN(MultiTransform); 69 70 /** Standard class type aliases. */ 71 using Self = MultiTransform; 72 using Superclass = Transform<TParametersValueType, NDimensions, NSubDimensions>; 73 using Pointer = SmartPointer<Self>; 74 using ConstPointer = SmartPointer<const Self>; 75 76 /** Run-time type information (and related methods). */ 77 itkTypeMacro( MultiTransform, Transform ); 78 79 /** Sub transform type **/ 80 using TransformType = Transform<TParametersValueType, NSubDimensions, NSubDimensions >; 81 using TransformTypePointer = typename TransformType::Pointer; 82 83 /* Types common to both container and sub transforms */ 84 85 /** Parameters type. */ 86 using ParametersType = typename Superclass::ParametersType; 87 using ParametersValueType = typename Superclass::ParametersValueType; 88 using FixedParametersType = typename Superclass::FixedParametersType; 89 using FixedParametersValueType = typename Superclass::FixedParametersValueType; 90 using ScalarType = ParametersValueType; 91 /** Derivative type */ 92 using DerivativeType = typename Superclass::DerivativeType; 93 /** Jacobian type. */ 94 using JacobianType = typename Superclass::JacobianType; 95 using JacobianPositionType = typename Superclass::JacobianPositionType; 96 using InverseJacobianPositionType = typename Superclass::InverseJacobianPositionType; 97 /** Transform category type. */ 98 using TransformCategoryType = typename Superclass::TransformCategoryType; 99 100 /* Types relative to the container transform. */ 101 102 /** InverseTransform type. */ 103 using InverseTransformBasePointer = typename Superclass::InverseTransformBasePointer; 104 105 /** Standard coordinate point type for this class. */ 106 using InputPointType = typename Superclass::InputPointType; 107 using OutputPointType = typename Superclass::OutputPointType; 108 /** Standard vector type for this class. */ 109 using InputVectorType = typename Superclass::InputVectorType; 110 using OutputVectorType = typename Superclass::OutputVectorType; 111 /** Standard covariant vector type for this class */ 112 using InputCovariantVectorType = typename Superclass::InputCovariantVectorType; 113 using OutputCovariantVectorType = typename Superclass::OutputCovariantVectorType; 114 /** Standard vnl_vector type for this class. */ 115 using InputVnlVectorType = typename Superclass::InputVnlVectorType; 116 using OutputVnlVectorType = typename Superclass::OutputVnlVectorType; 117 /** Standard Vectorpixel type for this class */ 118 using InputVectorPixelType = typename Superclass::InputVectorPixelType; 119 using OutputVectorPixelType = typename Superclass::OutputVectorPixelType; 120 /** Standard DiffusionTensor3D type alias for this class */ 121 using InputDiffusionTensor3DType = typename Superclass::InputDiffusionTensor3DType; 122 using OutputDiffusionTensor3DType = typename Superclass::OutputDiffusionTensor3DType; 123 /** Standard SymmetricSecondRankTensor type alias for this class */ 124 using InputSymmetricSecondRankTensorType = typename Superclass::InputSymmetricSecondRankTensorType; 125 using OutputSymmetricSecondRankTensorType = typename Superclass::OutputSymmetricSecondRankTensorType; 126 127 /* Types relative to the sub transform type. */ 128 129 /** InverseTransform type. */ 130 using SubTransformInverseTransformBasePointer = typename TransformType::InverseTransformBasePointer; 131 132 /** Transform queue type */ 133 using TransformQueueType = std::deque<TransformTypePointer>; 134 135 /** The number of parameters defininig this transform. */ 136 using NumberOfParametersType = typename Superclass::NumberOfParametersType; 137 138 /** Dimension of the domain spaces. */ 139 static constexpr unsigned int InputDimension = NDimensions; 140 static constexpr unsigned int OutputDimension = NDimensions; 141 142 static constexpr unsigned int SubInputDimension = NSubDimensions; 143 static constexpr unsigned int SubOutputDimension = NSubDimensions; 144 145 /** Functionality for sub transforms */ 146 147 /** Add transforms to the queue, as stack. 148 * Most-recently added transform is always at back of queue, index N-1. 149 */ AddTransform(TransformType * t)150 virtual void AddTransform( TransformType *t ) 151 { 152 this->PushBackTransform( t ); 153 } 154 155 /** Same as AddTransform */ AppendTransform(TransformType * t)156 virtual void AppendTransform( TransformType *t ) 157 { 158 this->AddTransform( t ); 159 } 160 161 /** Add transform to the front of the stack */ PrependTransform(TransformType * t)162 virtual void PrependTransform( TransformType *t ) 163 { 164 this->PushFrontTransform( t ); 165 } 166 167 /** Remove transform from the back of the queue, index N-1 */ RemoveTransform()168 virtual void RemoveTransform() 169 { 170 this->PopBackTransform(); 171 } 172 173 /** Get transforms at the front and the back of the queue */ 174 virtual const GetFrontTransform()175 TransformType * GetFrontTransform() const 176 { 177 return this->m_TransformQueue.front().GetPointer(); 178 } 179 180 virtual const GetBackTransform()181 TransformType * GetBackTransform() const 182 { 183 return this->m_TransformQueue.back().GetPointer(); 184 } 185 186 virtual const GetNthTransform(SizeValueType n)187 TransformTypePointer GetNthTransform( SizeValueType n ) const 188 { 189 //NOTE: By returning a smart pointer type, the use of this function can 190 // be a significant bottleneck in multithreaded applications. 191 return this->m_TransformQueue[n]; 192 } 193 194 /** Get the Nth transform. 195 * \warning No bounds checking is performed. */ 196 virtual GetNthTransformModifiablePointer(const SizeValueType n)197 TransformType * GetNthTransformModifiablePointer( const SizeValueType n ) const 198 { 199 return this->m_TransformQueue[n].GetPointer(); 200 } 201 202 virtual const GetNthTransformConstPointer(const SizeValueType n)203 TransformType * GetNthTransformConstPointer( const SizeValueType n ) const 204 { 205 return this->m_TransformQueue[n].GetPointer(); 206 } 207 208 /** Access transform queue */ GetTransformQueue()209 virtual const TransformQueueType & GetTransformQueue() const 210 { 211 return this->m_TransformQueue; 212 } 213 214 /** Misc. functionality */ IsTransformQueueEmpty()215 virtual bool IsTransformQueueEmpty() const 216 { 217 return this->m_TransformQueue.empty(); 218 } 219 220 /** Return the number of sub-transforms. */ GetNumberOfTransforms()221 virtual SizeValueType GetNumberOfTransforms() const 222 { 223 return static_cast<SizeValueType>(this->m_TransformQueue.size()); 224 } 225 226 /** Clear the transform queue. */ ClearTransformQueue()227 virtual void ClearTransformQueue() 228 { 229 this->m_TransformQueue.clear(); 230 this->Modified(); 231 } 232 233 /** If all sub-transforms are linear, then the multi-transform is linear. */ 234 bool IsLinear() const override; 235 236 /** If all sub-transforms are of the same category, return that category. 237 * Otherwise return UnknownTransformCategory. */ 238 TransformCategoryType GetTransformCategory() const override; 239 240 /** Get/Set Parameter functions work on all sub-transforms. 241 The parameter data from each sub-transform is 242 concatenated into a single ParametersType object. 243 \note The sub-transforms are read in forward queue order, 244 so the returned array is ordered in the same way. That is, 245 first sub-transform to be added is returned first in the 246 parameter array.*/ 247 const ParametersType & GetParameters() const override; 248 249 /* SetParameters for all sub-transforms. 250 * See GetParameters() for parameter ordering. */ 251 void SetParameters(const ParametersType & p) override; 252 253 /* GetFixedParameters for all sub-transforms. 254 * See GetParameters() for parameter ordering. */ 255 const FixedParametersType & GetFixedParameters() const override; 256 257 /* SetFixedParameters for all sub-transforms. 258 * See GetParameters() for parameter ordering. */ 259 void SetFixedParameters(const FixedParametersType & fixedParameters) override; 260 261 /* Get total number of parameters. Sum of all sub-transforms. */ 262 NumberOfParametersType GetNumberOfParameters() const override; 263 264 /* Get total number of local parameters, the sum of all sub-transforms. */ 265 NumberOfParametersType GetNumberOfLocalParameters() const override; 266 267 /* Get total number of fixed parameters, the sum of all sub-transforms. */ 268 NumberOfParametersType GetNumberOfFixedParameters() const override; 269 270 /** Update the transform's parameters by the values in \c update. 271 * See GetParameters() for parameter ordering. */ 272 void UpdateTransformParameters( const DerivativeType & update, ScalarType factor = 1.0 ) override; 273 274 /** Returns a boolean indicating whether it is possible or not to compute the 275 * inverse of this current Transform. If it is possible, then the inverse of 276 * the transform is returned in the inverseTransform variable passed by the user. 277 * The inverse consists of the inverse of each sub-transform, in the same order 278 * as the forward transforms. */ 279 bool GetInverse( Self *inverse ) const; 280 281 /** Flatten the transform queue such that there are no nested composite transforms. */ 282 //TODO - what do we need here? 283 // virtual void FlattenTransformQueue(); 284 285 protected: 286 MultiTransform(); 287 ~MultiTransform() override = default; 288 void PrintSelf( std::ostream& os, Indent indent ) const override; 289 PushFrontTransform(TransformTypePointer t)290 virtual void PushFrontTransform( TransformTypePointer t ) 291 { 292 this->m_TransformQueue.push_front( t ); 293 this->Modified(); 294 } 295 PushBackTransform(TransformTypePointer t)296 virtual void PushBackTransform( TransformTypePointer t ) 297 { 298 this->m_TransformQueue.push_back( t ); 299 this->Modified(); 300 } 301 PopFrontTransform()302 virtual void PopFrontTransform() 303 { 304 this->m_TransformQueue.pop_front(); 305 this->Modified(); 306 } 307 PopBackTransform()308 virtual void PopBackTransform() 309 { 310 this->m_TransformQueue.pop_back(); 311 this->Modified(); 312 } 313 314 /** Transform container object. */ 315 mutable TransformQueueType m_TransformQueue; 316 317 /** Cache to save time returning the number of local parameters */ 318 mutable NumberOfParametersType m_NumberOfLocalParameters; 319 mutable ModifiedTimeType m_LocalParametersUpdateTime; 320 }; 321 322 } // end namespace itk 323 324 #ifndef ITK_MANUAL_INSTANTIATION 325 #include "itkMultiTransform.hxx" 326 #endif 327 328 #endif // itkMultiTransform_h 329