File: cmtkGroupwiseRegistrationFunctionalBase.h

package info (click to toggle)
cmtk 3.3.1p2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 10,492 kB
  • sloc: cpp: 87,098; ansic: 23,347; sh: 3,896; xml: 1,551; perl: 707; makefile: 332
file content (515 lines) | stat: -rw-r--r-- 17,066 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
/*
//
//  Copyright 1997-2009 Torsten Rohlfing
//
//  Copyright 2004-2012 SRI International
//
//  This file is part of the Computational Morphometry Toolkit.
//
//  http://www.nitrc.org/projects/cmtk/
//
//  The Computational Morphometry Toolkit is free software: you can
//  redistribute it and/or modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  The Computational Morphometry Toolkit is distributed in the hope that it
//  will be useful, but WITHOUT ANY WARRANTY; without even the implied
//  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with the Computational Morphometry Toolkit.  If not, see
//  <http://www.gnu.org/licenses/>.
//
//  $Revision: 5436 $
//
//  $LastChangedDate: 2018-12-10 19:01:20 -0800 (Mon, 10 Dec 2018) $
//
//  $LastChangedBy: torstenrohlfing $
//
*/

#ifndef __cmtkGroupwiseRegistrationFunctionalBase_h_included_
#define __cmtkGroupwiseRegistrationFunctionalBase_h_included_

#include <cmtkconfig.h>

#include <Base/cmtkFunctional.h>
#include <Base/cmtkUniformVolume.h>
#include <Base/cmtkXform.h>

#include <System/cmtkSmartPtr.h>
#include <System/cmtkThreads.h>

#include <vector>

namespace
cmtk
{

/** \addtogroup Registration */
//@{

/** Base class for groupwise registration functionals.
 * This class provides the lowest-level components of groupwise image registration, such as
 * image IO, preprocessing, generic access to transformation and image vectors, and parameters
 * common to all algorithms such as zero-sum optimization.
 */
class GroupwiseRegistrationFunctionalBase : 
  /** Inherit from abstract functional base class. */
  public Functional
{
public:
  /// Type of parent class.
  typedef Functional Superclass;

  /// Type of this class.
  typedef GroupwiseRegistrationFunctionalBase Self;

  /// Smart pointer.
  typedef SmartPointer<Self> SmartPtr;

  /// Exception for "bad transformation".
  class BadXform {};

  /// Constructor.
  GroupwiseRegistrationFunctionalBase();

  /// Destructor.
  virtual ~GroupwiseRegistrationFunctionalBase();

  /** Set flag for freeing and rereading images.
   * If registration uses smoothed images, the original data can be freed after smoothing
   * and reread from the file system if needed again. This saves roughly 1/2 of memory
   * allocation.
   */
  virtual void SetFreeAndRereadImages( const bool flag = true )
  {
    this->m_FreeAndRereadImages = flag;
  }

  /// Set flag for repeated histogram-based intensity matching.
  virtual void SetRepeatIntensityHistogramMatching( const bool flag = true )
  {
    this->m_RepeatIntensityHistogramMatching = flag;
    if ( flag )
      {
      this->SetFreeAndRereadImages( false );
      }
  }

  /** Create template grid based on target images.
   * The template image is constructed so that is has the maximum number of
   * pixels of all targets in each dimension, and the minimum isotropic
   * pixel size.
   *
   *\param targets The vector of target images for this groupwise registration.
   *\param downsample Downsampling factor. The voxel size in the template
   * image is increased by this factor.
   */
  virtual void CreateTemplateGridFromTargets( const std::vector<UniformVolume::SmartPtr>& targets, const int downsample = 0 );

  /** Create template grid based on geometry.
   */
  virtual void CreateTemplateGrid( const DataGrid::IndexType& dims /*!< Template grid dimensions */, const UniformVolume::CoordinateVectorType& deltas /*!< Template grid deltas (i.e., pixel size). */ );

  /** Set template grid.
   */
  virtual void SetTemplateGrid( UniformVolume::SmartPtr& templateGrid /*!< The template grid that defines size and resolution for the implicit registration template. */, 
				const int downsample = 1 /*!< Downsampling factor */, const bool useTemplateData = false /*!< Flag to use template data, not just grid */ );

  /** Retrieve the template grid.
   */
  virtual UniformVolume::SmartPtr& GetTemplateGrid() 
  { 
    return this->m_TemplateGrid; 
  }

  /** Retrieve the template grid.
   */
  virtual const UniformVolume* GetTemplateGrid() const
  {
    return this->m_TemplateGrid; 
  }

  /** Set target images.
   *\param tImages Vector of all images to be registered.
   */
  virtual void SetTargetImages( std::vector<UniformVolume::SmartPtr>& tImages );

  /** Get the original target images.
   */
  virtual void GetOriginalTargetImages( std::vector<UniformVolume::SmartPtr>& tImages )
  {
    tImages = this->m_OriginalImageVector;
  }  

  /** Get the original target images.
   */
  virtual std::vector<UniformVolume::SmartPtr>& GetOriginalTargetImages()
  {
    return this->m_OriginalImageVector;
  }  

  /** Get number of target images.
   */
  virtual size_t GetNumberOfTargetImages() const
  {
    return this->m_OriginalImageVector.size();
  }  

  /** Get a smart pointer to one original target image.
   */
  virtual UniformVolume::SmartPtr GetOriginalTargetImage( const size_t imageIdx )
  {
    return this->m_OriginalImageVector[imageIdx];
  }  

  /** Get a constant pointer to one original target image.
   */
  virtual const UniformVolume* GetOriginalTargetImage( const size_t imageIdx ) const
  {
    return this->m_OriginalImageVector[imageIdx];
  }  

  /** Set Gaussian smoothing kernel width for target images.
   * Non-positive values turn off smoothing.
   */
  virtual void SetGaussianSmoothImagesSigma( const Types::Coordinate gaussianSmoothImagesSigma )
  {
    this->m_GaussianSmoothImagesSigma = gaussianSmoothImagesSigma;
  }

  /** Set user-defined image background value to be substituted outside the field of view. */
  virtual void SetUserBackgroundValue( const byte value = 0 )
  {
    this->m_UserBackgroundValue = value;
    this->m_UserBackgroundFlag = true;
  }

  /** Unset user-defined image background value. */
  virtual void UnsetUserBackgroundValue()
  {
    this->m_UserBackgroundFlag = false;
  }

  /// Set flag for zero-sum updates.
  virtual void SetForceZeroSum( const bool forceZeroSum = true )
  {
    this->m_ForceZeroSum = forceZeroSum;
  }

  /// Set count for restricted zero-sum updates.
  virtual void SetForceZeroSumFirstN( const size_t forceZeroSumFirstN )
  {
    this->m_ForceZeroSumFirstN = forceZeroSumFirstN;
    this->m_ForceZeroSum = this->m_ForceZeroSum || (this->m_ForceZeroSumFirstN>0);
  }

  /** Set range of currently active images.
   * The "to" parameter is the index of the last active image plus one, so
   * it can be used directly as the upper bound in a "for" loop.
   */
  virtual void SetActiveImagesFromTo( const size_t from, const size_t to )
  {
    this->m_ActiveImagesFrom = from;
    this->m_ActiveImagesTo = to;
  }

  /** Set range of currently active transformations.
   * The "to" parameter is the index of the last active transformation plus one, so
   * it can be used directly as the upper bound in a "for" loop.
   */
  virtual void SetActiveXformsFromTo( const size_t from, const size_t to )
  {
    this->m_ActiveXformsFrom = from;
    this->m_ActiveXformsTo = to;
  }

  /** Set probabilistic sampling density.
   */
  virtual void SetProbabilisticSampleDensity( const float density )
  {
    this->m_ProbabilisticSampleDensity = density;
  }

  /** Set number of iterations after which probabilistic samples are updated.
   */
  virtual void SetProbabilisticSampleUpdatesAfter( const int iterations )
  {
    this->m_ProbabilisticSampleUpdatesAfter = iterations;
    this->m_ProbabilisticSampleUpdatesSince = 0;
  }

  /** Set transformations.
   */
  void SetXforms( const std::vector<Xform::SmartPtr>& xformVector )
  {
    this->m_XformVector.resize( xformVector.size() );
    for ( size_t i = 0; i < this->m_XformVector.size(); ++i )
      {
      this->m_XformVector[i] = xformVector[i];
      }
  }

  /** Get coordinate transformation for one image in the group.
   *\param idx Index of the volume/transformation.
   *\return Transformation for the selected volume.
   */
  virtual const Xform* GetGenericXformByIndex( const size_t idx ) const
  {
    return this->m_XformVector[idx];
  }

  /** Get coordinate transformation for one image in the group.
   *\param idx Index of the volume/transformation.
   *\return Transformation for the selected volume.
   */
  virtual Xform::SmartPtr GetGenericXformByIndex( const size_t idx )
  {
    return this->m_XformVector[idx];
  }

  /** Get coordinate transformation for one active image in the group.
   *\param idx Index of the volume/transformation.
   *\return Transformation for the selected volume.
   */
  virtual const Xform* GetGenericActiveXformByIndex( const size_t idx ) const
  {
    return this->m_XformVector[idx + this->m_ActiveXformsFrom];
  }

  /** Get coordinate transformation for one active image in the group.
   *\param idx Index of the volume/transformation.
   *\return Transformation for the selected volume.
   */
  virtual Xform::SmartPtr GetGenericActiveXformByIndex( const size_t idx )
  {
    return this->m_XformVector[idx + this->m_ActiveXformsFrom];
  }

  /** Get parameter stepping in milimeters.
   *\param idx Parameter index.
   *\param mmStep Desired step length. This is typically used as a scalar factor for the default (1mm) step size.
   *\return Step of given parameter that corresponds to 1 mm effective motion.
   */
  virtual Types::Coordinate GetParamStep( const size_t idx, const Types::Coordinate mmStep = 1 ) const 
  {
    const size_t xformIdx = idx / this->m_ParametersPerXform;
    if ( (xformIdx >= this->m_ActiveXformsFrom) && (xformIdx < this->m_ActiveXformsTo) )
      {
      return this->m_XformVector[xformIdx]->GetParamStep( idx % this->m_ParametersPerXform, this->m_ImageVector[xformIdx]->m_Size, mmStep );
      }
    else
      {
      return 0.0;
      }
  }
  
  /** Return the functional's parameter vector dimension.
   * We assume that all transformations have the same number of parameters.
   * This is true for affine transformations.
   */
  virtual size_t ParamVectorDim() const 
  { 
    return this->m_ParametersPerXform * this->m_XformVector.size(); 
  }
  
  /** Return the number of variable parameters of the transformation.
   *\return This function returns the same value as ParamVectorDim(). 
   *  Non-varying parameters (e.g., rotation centers) are handled via
   *  parameter step values.
   */
  virtual size_t VariableParamVectorDim() const
  { 
    return this->ParamVectorDim();
  }
  
  /** Get parameter vector.
   */
  virtual void GetParamVector( CoordinateVector& v );

  /** Set parameter vector.
   */
  virtual void SetParamVector( CoordinateVector& v );

  /** Set parameter vector for a given transformation.
   */
  virtual void SetParamVector( CoordinateVector& v, const size_t xformIdx );

  /** Set single parameter value.
   */
  virtual void SetParameter( const size_t param, const Types::Coordinate value );

  /** Set single parameter value with separate xform and parameter index.
   */
  virtual void SetParameter( const size_t xform, const size_t param, const Types::Coordinate value );

  /** Evaluate functional with given parameter vector.
   * This function sets the current parameter vector, reformats all image data
   * into template space according to the current transformations, and calls
   * Evaluate() to compute the entropy-based functional value.
   *\param v Parameter vector.
   *\return Const function value for given parameters.
   */
  virtual Self::ReturnType EvaluateAt ( CoordinateVector& v );

  /** Compute functional value and gradient.
   *\param v Parameter vector.
   *\param g The extimated gradient of the functional is stored in this vector.
   *\param step Step size for finite difference gradient approximation. Default
   *  is 1 mm.
   *\return Const function value for given parameters.
   */
  virtual Self::ReturnType EvaluateWithGradient( CoordinateVector& v, CoordinateVector& g, const Types::Coordinate step = 1 );

  /** Allocate storage for reformatted images etc.
   * This function must be called AFTER setting template grid and target images, but BEFORE
   * any calls to Evaluate, EvaluateAt, or EvaluateWithGradient.
   */
  virtual void AllocateStorage();

  /// Write all images for debug purposes.
  void DebugWriteImages();

protected:
  /// Number of threads in thread pool (for allocation of temporary thread memory).
  size_t m_NumberOfThreads;

  /// Number of tasks for thread pool (for allocation of task arguments and results).
  size_t m_NumberOfTasks;

  /// Flag for freeing and re-reading original images if using smoothed data.
  bool m_FreeAndRereadImages;

  /// Flag for enforcing zero-sum parameter changes.
  bool m_ForceZeroSum;
  
  /// Restrict zero-sum computation to first N images.
  size_t m_ForceZeroSumFirstN;

  /// Currently active images from index.
  size_t m_ActiveImagesFrom;

  /// Currently active images to index (plus 1).
  size_t m_ActiveImagesTo;

  /// Currently active transformations from index.
  size_t m_ActiveXformsFrom;

  /// Currently active transformations to index (plus 1).
  size_t m_ActiveXformsTo;

  /// Enforce gradient to be zero-sum over all images.
  virtual void ForceZeroSumGradient( CoordinateVector& g ) const;

  /// Number of pixels in template.
  size_t m_TemplateNumberOfPixels;

  /// Number of samples drawn from the pixels in template.
  size_t m_TemplateNumberOfSamples;

  /// Template grid (not pixel data).
  UniformVolume::SmartPtr m_TemplateGrid;

  /// Flag for use of template pixel data in registration.
  bool m_UseTemplateData;

  /// Prepared (smoothed, scaled etc.) data of the template image if used in registration.
  std::vector<byte> m_TemplateData;

  /// Vector of image volumes with pre-scaled pixel values.
  std::vector<UniformVolume::SmartPtr> m_ImageVector;

  /// Vector of original image volumes.
  std::vector<UniformVolume::SmartPtr> m_OriginalImageVector;

  /// Vector of transformations
  std::vector<Xform::SmartPtr> m_XformVector;

  /// Probabilistic sample count.
  float m_ProbabilisticSampleDensity;

  /// Pixel indices of probabilistic samples.
  std::vector<size_t> m_ProbabilisticSamples;

  /** Number of iterations (calls to Evaluate()) after which probabilistic 
   * samples are updated.
   */
  int m_ProbabilisticSampleUpdatesAfter;

  /** Current number of iterations since last update of probabilistic samples.
   */
  int m_ProbabilisticSampleUpdatesSince;

  /** Update probablistic samples.
   * This function generates a new list of random pixel indices for sampling
   * the images. It is called every m_ProbabilisticSampleUpdatesAfter calls to
   * Evaluate().
   */
  virtual void UpdateProbabilisticSamples();

  /** Interpolate all moving images.
   * By default, this only calls InterpolateImage() for each image. 
   */
  virtual void InterpolateAllImages();

  /** Interpolate given moving image to template.
   *\param idx Index of of to reformat to template. This also determines which
   *  transformation is used.
   *\param destination The reformatted pixel data is stored in this array.
   *  Sufficient memory (for as many pixels as there are in the template grid)
   *  must be allocated there.
   */
  virtual void InterpolateImage( const size_t idx, byte* const destination ) { UNUSED(idx); UNUSED(destination); } // cannot make this pure virtual because we need to instantiate for affine initialization

  /// Vector of reformatted and rescaled image data.
  std::vector<byte*> m_Data;

  /// Temporary data allocated at correct size of template grid.
  std::vector<byte> m_TempData;

  /// Kernel width in [mm] for Gaussian smoothing of target images.
  Types::Coordinate m_GaussianSmoothImagesSigma;

  /// Value used to mark regions outside the FOV.
  static const byte m_PaddingValue = 255;

  /// User-defined value to fill regions outside FOV.
  byte m_UserBackgroundValue;
  
  /// Flag for user-defined background value.
  bool m_UserBackgroundFlag;

  /// Number of parameters per transformation..
  size_t m_ParametersPerXform;

  /// Repeat histogram-based intensity matching after each stage.
  bool m_RepeatIntensityHistogramMatching;

  /// Update probabilistic sample table..
  virtual bool Wiggle();

  /// Prepare data for one image.
  virtual UniformVolume::SmartPtr PrepareSingleImage( UniformVolume::SmartPtr& image );

  /// Smooth and pre-scale target images.
  virtual void PrepareTargetImages();

  /// Reformat one image to a given target grid.
  virtual const UniformVolume::SmartPtr GetReformattedImage( const UniformVolume::SmartPtr& targetGrid, const size_t idx ) const;

private:
  /// Copy template data from TypedArray to byte vector.
  void CopyTemplateData();

  /// Initializer class shall be our friend.
  friend class GroupwiseRegistrationFunctionalAffineInitializer;
};

//@}

} // namespace cmtk

#endif // #ifndef __cmtkGroupwiseRegistrationFunctionalBase_h_included_