File: itkWeightedVotingFusionImageFilter.h

package info (click to toggle)
ants 2.5.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,672 kB
  • sloc: cpp: 85,685; sh: 15,850; perl: 863; xml: 115; python: 111; makefile: 68
file content (408 lines) | stat: -rw-r--r-- 12,892 bytes parent folder | download
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
/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef __itkWeightedVotingFusionImageFilter_h
#define __itkWeightedVotingFusionImageFilter_h

#include "itkNonLocalPatchBasedImageFilter.h"

#include "itkConstNeighborhoodIterator.h"

#include <vnl/vnl_matrix.h>
#include <vnl/vnl_vector.h>

#include <vector>
#include <map>
#include <set>

namespace itk
{

/** \class WeightedVotingFusionImageFilter
 * \brief Implementation of the joint label fusion and joint intensity fusion algorithm
 *
 * \author Paul Yushkevich with modifications by Brian Avants and Nick Tustison
 *
 * \par REFERENCE
 *
 * H. Wang, J. W. Suh, S. Das, J. Pluta, C. Craige, P. Yushkevich,
 * "Multi-atlas segmentation with joint label fusion," IEEE Trans.
 * on Pattern Analysis and Machine Intelligence, 35(3), 611-623, 2013.
 *
 * H. Wang and P. A. Yushkevich, "Multi-atlas segmentation with joint
 * label fusion and corrective learning--an open source implementation,"
 * Front. Neuroinform., 2013.
 *
 * \ingroup ImageSegmentation
 */

template <typename TInputImage, typename TOutputImage>
class WeightedVotingFusionImageFilter final : public NonLocalPatchBasedImageFilter<TInputImage, TOutputImage>
{
public:
  /** Standard class typedefs. */
  typedef WeightedVotingFusionImageFilter                          Self;
  typedef NonLocalPatchBasedImageFilter<TInputImage, TOutputImage> Superclass;
  typedef SmartPointer<Self>                                       Pointer;
  typedef SmartPointer<const Self>                                 ConstPointer;

  /** Run-time type information (and related methods). */
  itkTypeMacro(WeightedVotingFusionImageFilter, NonLocalPatchBasedImageFilter);

  itkNewMacro(Self);

  /** ImageDimension constants */
  static constexpr unsigned int ImageDimension = TInputImage::ImageDimension;


  /** Some convenient typedefs. */
  typedef TInputImage                           InputImageType;
  typedef typename InputImageType::Pointer      InputImagePointer;
  typedef typename InputImageType::ConstPointer InputImageConstPointer;
  typedef typename InputImageType::PixelType    InputImagePixelType;

  typedef typename Superclass::InputImageList    InputImageList;
  typedef typename Superclass::InputImageSetList InputImageSetList;

  typedef typename Superclass::InputImagePixelVectorType InputImagePixelVectorType;

  typedef TOutputImage                        OutputImageType;
  typedef typename OutputImageType::PixelType LabelType;
  typedef std::set<LabelType>                 LabelSetType;
  typedef Image<LabelType, ImageDimension>    LabelImageType;
  typedef typename LabelImageType::Pointer    LabelImagePointer;
  typedef std::vector<LabelImagePointer>      LabelImageList;

  typedef Image<unsigned int, ImageDimension> CountImageType;

  typedef LabelImageType                  MaskImageType;
  typedef typename MaskImageType::Pointer MaskImagePointer;

  typedef typename InputImageType::RegionType RegionType;
  typedef typename InputImageType::SizeType   SizeType;
  typedef typename InputImageType::IndexType  IndexType;

  typedef Image<float, ImageDimension>           ProbabilityImageType;
  typedef typename ProbabilityImageType::Pointer ProbabilityImagePointer;

  typedef double RealType;

  typedef vnl_matrix<RealType> MatrixType;
  typedef vnl_vector<RealType> VectorType;

  typedef std::map<LabelType, ProbabilityImagePointer> LabelPosteriorProbabilityMap;
  typedef std::map<LabelType, LabelImagePointer>       LabelExclusionMap;
  typedef std::vector<ProbabilityImagePointer>         VotingWeightImageList;

  typedef typename Superclass::ConstNeighborhoodIteratorType ConstNeighborhoodIteratorType;
  typedef typename Superclass::NeighborhoodRadiusType        NeighborhoodRadiusType;
  typedef typename Superclass::NeighborhoodOffsetType        NeighborhoodOffsetType;
  typedef typename Superclass::NeighborhoodOffsetListType    NeighborhoodOffsetListType;

  typedef typename SizeType::SizeValueType       RadiusValueType;
  typedef Image<RadiusValueType, ImageDimension> RadiusImageType;
  typedef typename RadiusImageType::Pointer      RadiusImagePointer;

  /**
   * Set the multimodal target image
   */
  void
  SetTargetImage(InputImageList imageList)
  {
    this->m_TargetImage = imageList;
    this->UpdateInputs();
  }

  /**
   * Add an atlas (multi-modal image + segmentation)
   * imageList is a vector of image pointers
   * *segmentation is the pointer for the single segmentation corresponding to imageList
   */
  void
  AddAtlas(InputImageList imageList, LabelImageType * segmentation = nullptr)
  {
    this->m_AtlasImages.push_back(imageList);

    if (this->m_NumberOfAtlasModalities == 0)
    {
      itkDebugMacro("Setting the number of modalities to " << this->m_NumberOfAtlasModalities);
      this->m_NumberOfAtlasModalities = imageList.size();
    }
    else if (this->m_NumberOfAtlasModalities != imageList.size())
    {
      itkExceptionMacro("The number of atlas multimodal images is not equal to " << this->m_NumberOfAtlasModalities);
    }
    this->m_NumberOfAtlases++;

    if (segmentation != nullptr)
    {
      this->m_AtlasSegmentations.push_back(segmentation);
      this->m_NumberOfAtlasSegmentations++;
    }

    this->UpdateInputs();
  }

  /**
   * Set mask image function.  If a binary mask image is specified, only
   * those input image voxels corresponding with mask image values equal
   * to one are used.
   */
  void
  SetMaskImage(MaskImageType * mask)
  {
    this->m_MaskImage = mask;
    this->UpdateInputs();
  }

  /**
   * Add a label exclusion map
   */
  void
  AddLabelExclusionImage(LabelType label, LabelImageType * exclusionImage)
  {
    this->m_LabelExclusionImages[label] = exclusionImage;
    this->UpdateInputs();
  }

  /**
   * Get the number of modalities used in determining the optimal label fusion
   * or optimal fused image.
   */
  itkGetConstMacro(NumberOfAtlasModalities, unsigned int);

  /**
   * Get the label set.
   */
  itkGetConstMacro(LabelSet, LabelSetType);

  /**
   * Set/Get the local search neighborhood radius image.
   */
  void
  SetNeighborhoodSearchRadiusImage(RadiusImageType * image)
  {
    this->m_NeighborhoodSearchRadiusImage = image;
  }

  /**
   * Set/Get the Alpha parameter---the regularization weight added to the matrix Mx for
   * the inverse.  Default = 0.1.
   */
  itkSetMacro(Alpha, RealType);
  itkGetConstMacro(Alpha, RealType);

  /**
   * Set/Get the Beta parameter---exponent for mapping intensity difference to joint error.
   * Default = 2.0.
   */
  itkSetMacro(Beta, RealType);
  itkGetConstMacro(Beta, RealType);

  /** Set the requested region */
  void
  GenerateInputRequestedRegion() override;

  /**
   * Boolean for retaining the posterior images. This can have a negative effect
   * on memory use, so it should only be done if one wishes to save the posterior
   * maps. The posterior maps (n = number of labels) give the probability of each
   * voxel in the target image belonging to each label.  Default = false.
   */
  itkSetMacro(RetainLabelPosteriorProbabilityImages, bool);
  itkGetConstMacro(RetainLabelPosteriorProbabilityImages, bool);
  itkBooleanMacro(RetainLabelPosteriorProbabilityImages);

  /**
   * Boolean for retaining the voting weights images.  This can have a negative effect
   * on memory use, so it should only be done if one wishes to save the voting weight
   * maps.  The voting weight maps (n = number of atlases) gives the contribution of
   * a particular atlas to the final label/intensity fusion.
   */
  itkSetMacro(RetainAtlasVotingWeightImages, bool);
  itkGetConstMacro(RetainAtlasVotingWeightImages, bool);
  itkBooleanMacro(RetainAtlasVotingWeightImages);

  /**
   * Boolean for constraining the weights to be positive and sum to 1.  We use
   * an implementation of the algorithm based on the algorithm by Lawson, Charles L.;
   * Hanson, Richard J. (1995). Solving Least Squares Problems. SIAM.
   */
  itkSetMacro(ConstrainSolutionToNonnegativeWeights, bool);
  itkGetConstMacro(ConstrainSolutionToNonnegativeWeights, bool);
  itkBooleanMacro(ConstrainSolutionToNonnegativeWeights);

  /**
   * Get the current state for progress reporting.
   */
  itkGetConstMacro(IsWeightedAveragingComplete, bool);

  /**
   * Get the posterior probability image corresponding to a label.
   */
  ProbabilityImagePointer
  GetLabelPosteriorProbabilityImage(LabelType label)
  {
    if (this->m_RetainLabelPosteriorProbabilityImages)
    {
      if (std::find(this->m_LabelSet.begin(), this->m_LabelSet.end(), label) != this->m_LabelSet.end())
      {
        return this->m_LabelPosteriorProbabilityImages[label];
      }
      else
      {
        itkDebugMacro("Not returning a label posterior probability image.  Requested label not found.");
        return nullptr;
      }
    }
    else
    {
      itkDebugMacro("Not returning a label posterior probability image.  These images were not saved.");
      return nullptr;
    }
  }

  /**
   * Get the voting weight image corresponding to an atlas.
   */
  ProbabilityImagePointer
  GetAtlasVotingWeightImage(unsigned int n)
  {
    if (this->m_RetainAtlasVotingWeightImages)
    {
      if (n < this->m_NumberOfAtlases)
      {
        return this->m_AtlasVotingWeightImages[n];
      }
      else
      {
        itkDebugMacro("Not returning a voting weight image.  Requested index is greater than the number of atlases.");
        return nullptr;
      }
    }
    else
    {
      itkDebugMacro("Not returning a voting weight image.  These images were not saved.");
      return nullptr;
    }
  }

  /**
   * Get the joint intensity fusion output image
   */
  ProbabilityImagePointer
  GetJointIntensityFusionImage(unsigned int n)
  {
    if (n < this->m_NumberOfAtlasModalities)
    {
      return this->m_JointIntensityFusionImage[n];
    }
    else
    {
      itkDebugMacro(
        "Not returning a joint intensity fusion image.  Requested index is greater than the number of modalities.");
      return nullptr;
    }
  }

protected:
  WeightedVotingFusionImageFilter();
  ~WeightedVotingFusionImageFilter() override = default;

  void
  PrintSelf(std::ostream & os, Indent indent) const override;

  void
  ThreadedGenerateData(const RegionType &, ThreadIdType) override;

  void
  BeforeThreadedGenerateData() override;

  void
  AfterThreadedGenerateData() override;

  void
  GenerateData() override;

private:
  void
  ThreadedGenerateDataForWeightedAveraging(const RegionType &, ThreadIdType);

  void
  ThreadedGenerateDataForReconstruction(const RegionType &, ThreadIdType);

  VectorType
  NonNegativeLeastSquares(const MatrixType &, const VectorType &, const RealType);

  void
  UpdateInputs();

  typedef std::pair<unsigned int, RealType> DistanceIndexType;
  typedef std::vector<DistanceIndexType>    DistanceIndexVectorType;

  struct DistanceIndexComparator
  {
    bool
    operator()(const DistanceIndexType & left, const DistanceIndexType & right)
    {
      return left.second < right.second;
    }
  };

  bool m_IsWeightedAveragingComplete;

  /** Input variables   */
  InputImageList    m_TargetImage;
  InputImageSetList m_AtlasImages;
  LabelImageList    m_AtlasSegmentations;
  LabelExclusionMap m_LabelExclusionImages;
  MaskImagePointer  m_MaskImage;

  typename CountImageType::Pointer m_CountImage;

  LabelSetType  m_LabelSet;
  SizeValueType m_NumberOfAtlases;
  SizeValueType m_NumberOfAtlasSegmentations;
  SizeValueType m_NumberOfAtlasModalities;

  std::map<RadiusValueType, NeighborhoodOffsetListType> m_NeighborhoodSearchOffsetSetsMap;

  RealType m_Alpha;
  RealType m_Beta;

  bool m_RetainLabelPosteriorProbabilityImages;
  bool m_RetainAtlasVotingWeightImages;
  bool m_ConstrainSolutionToNonnegativeWeights;

  ProbabilityImagePointer m_WeightSumImage;

  RadiusImagePointer m_NeighborhoodSearchRadiusImage;

  /** Output variables     */
  LabelPosteriorProbabilityMap m_LabelPosteriorProbabilityImages;
  VotingWeightImageList        m_AtlasVotingWeightImages;

  InputImageList m_JointIntensityFusionImage;
};

} // namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#  include "itkWeightedVotingFusionImageFilter.hxx"
#endif

#endif