ANIMA  4.0
animaPyramidImageFilter.hxx
Go to the documentation of this file.
1 #pragma once
2 
4 #include <itkImageFileWriter.h>
5 
8 
9 #include <itkIdentityTransform.h>
10 
11 namespace anima
12 {
13 
14 template <class TInputImage, class TOutputImage>
17 {
18  m_NumberOfLevels = 1;
19  m_ImageResampler = 0;
20 }
21 
22 template <class TInputImage, class TOutputImage>
23 double
25 AnisotropyMeasure(SpacingType &sp, std::vector <bool> &changeableSizes)
26 {
27  double meanVals, sumVals = 0, resVal;
28 
29  unsigned int numDirs = 0;
30  for (unsigned int i = 0;i < sp.Size();++i)
31  {
32  if (changeableSizes[i])
33  {
34  ++numDirs;
35  sumVals += sp[i];
36  }
37  }
38 
39  meanVals = sumVals / numDirs;
40 
41  resVal = 0;
42  for (unsigned int i = 0;i < sp.Size();++i)
43  {
44  if (changeableSizes[i])
45  resVal += (sp[i] - meanVals) * (sp[i] - meanVals);
46  }
47 
48  resVal = std::sqrt(0.5 * resVal) / sumVals;
49 
50  return resVal;
51 }
52 
53 template <class TInputImage, class TOutputImage>
54 void
57 {
58  const unsigned int minSize = 16;
59 
60  std::vector <RegionType> tmpSizes;
61  std::vector <SpacingType> tmpSpacings;
62 
63  tmpSizes.push_back(this->GetInput()->GetLargestPossibleRegion());
64  tmpSpacings.push_back(this->GetInput()->GetSpacing());
65 
66  // Only sizes that are larger than min size are subject to the constraint
67  std::vector <bool> changeableSizes(InputImageType::ImageDimension,false);
68 
69  for (unsigned int j = 0;j < InputImageType::ImageDimension;++j)
70  {
71  if ((tmpSizes[0].GetSize()[j] > minSize))
72  changeableSizes[j] = true;
73  }
74 
75  RegionType previousRegion, newRegion;
76  SpacingType previousSpacing, newSpacing, testSpacing;
77  bool allAboveMinSize = true;
78 
79  unsigned int numPermutations = 1;
80  numPermutations <<= InputImageType::ImageDimension;
81 
82  while (allAboveMinSize && (tmpSizes.size() < m_NumberOfLevels))
83  {
84  previousRegion = tmpSizes.back();
85  previousSpacing = tmpSpacings.back();
86  newRegion = previousRegion;
87  newSpacing = previousSpacing;
88  for (unsigned int j = 0;j < InputImageType::ImageDimension;++j)
89  {
90  if (changeableSizes[j])
91  {
92  unsigned int oldSize = newRegion.GetSize()[j];
93  unsigned int tmpSize = (unsigned int)ceil(std::max(oldSize / 2.0, (double)minSize));
94  newRegion.SetSize(j,tmpSize);
95 
96  newSpacing[j] = newSpacing[j] * oldSize / newRegion.GetSize()[j];
97  }
98  }
99 
100  double bestAnisotropy = 1.0;
101  unsigned int bestIndex = 0;
102 
103  for (unsigned int counter = 1; counter < numPermutations; ++counter)
104  {
105  testSpacing = previousSpacing;
106  unsigned int upper = counter; // each bit indicates upper/lower option
107  bool usefulConfiguration = false;
108  for (unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
109  {
110  if ((upper & 1) && changeableSizes[dim])
111  {
112  usefulConfiguration = true;
113  break;
114  }
115 
116  upper >>= 1;
117  }
118 
119  if (!usefulConfiguration)
120  continue;
121 
122  upper = counter;
123  for(unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
124  {
125  if ( upper & 1 )
126  testSpacing[dim] = newSpacing[dim];
127 
128  upper >>= 1;
129  }
130 
131  double testAnisotropy = this->AnisotropyMeasure(testSpacing,changeableSizes);
132 
133  // Inferior or equal important otherwise problem for isotropic images
134  if (testAnisotropy <= bestAnisotropy)
135  {
136  bestIndex = counter;
137  bestAnisotropy = testAnisotropy;
138  }
139  }
140 
141  // Get final shrinkage
142  unsigned int upper = bestIndex;
143  for(unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
144  {
145  if (!(upper & 1))
146  {
147  newSpacing[dim] = previousSpacing[dim];
148  newRegion.SetSize(dim,previousRegion.GetSize()[dim]);
149  }
150 
151  upper >>= 1;
152  }
153 
154  allAboveMinSize = true;
155  for (unsigned int j = 0;j < InputImageType::ImageDimension;++j)
156  {
157  if ((newRegion.GetSize()[j] <= minSize)&&(changeableSizes[j]))
158  {
159  allAboveMinSize = false;
160  newRegion.SetSize(j,minSize);
161  newSpacing[j] = previousSpacing[j] * previousRegion.GetSize()[j] / minSize;
162  }
163  }
164 
165  tmpSizes.push_back(newRegion);
166  tmpSpacings.push_back(newSpacing);
167  }
168 
169  if (tmpSpacings.size() < m_NumberOfLevels)
170  m_NumberOfLevels = tmpSpacings.size();
171 
172  m_LevelSpacings.clear();
173  m_LevelRegions.clear();
174 
175  for (unsigned int i = m_NumberOfLevels;i > 0;--i)
176  {
177  m_LevelSpacings.push_back(tmpSpacings[i-1]);
178  m_LevelRegions.push_back(tmpSizes[i-1]);
179  }
180 }
181 
182 template <class TInputImage, class TOutputImage>
183 void
186 {
187  if (!m_ImageResampler)
188  itkExceptionMacro("Image resampler for pyramid filter not provided");
189 
190  this->CheckNumberOfLevels();
191 
192  this->SetNumberOfRequiredOutputs(m_NumberOfLevels);
193  for (unsigned int i = 0;i < m_NumberOfLevels;++i)
194  this->SetNthOutput(i,this->MakeOutput(i));
195 
196  bool vectorInputImages = (dynamic_cast<VectorInputImageType *> (this->GetOutput(0)) != NULL);
197 
198  for (unsigned int i = m_NumberOfLevels;i > 0;--i)
199  {
200  if (vectorInputImages)
201  this->CreateLevelVectorImage(i-1);
202  else
203  this->CreateLevelImage(i-1);
204  }
205 }
206 
207 template <class TInputImage, class TOutputImage>
208 void
210 CreateLevelVectorImage(unsigned int level)
211 {
212  const InputImageType *previousLevelImage = NULL;
213  if (level == (unsigned int)(m_NumberOfLevels - 1))
214  previousLevelImage = this->GetInput();
215  else
216  previousLevelImage = this->GetOutput(level+1);
217 
218  OutputImagePointer levelImage;
219 
220  typedef itk::MatrixOffsetTransformBase <double,InputImageType::ImageDimension> MatrixTrsfType;
221  typedef itk::Transform <double,InputImageType::ImageDimension,InputImageType::ImageDimension> BaseTrsfType;
222  typename MatrixTrsfType::Pointer idTrsf = MatrixTrsfType::New();
223  idTrsf->SetIdentity();
224 
225  typename BaseTrsfType::Pointer baseTrsf = idTrsf.GetPointer();
226 
228 
229  typename ResamplerType::Pointer resample = dynamic_cast <ResamplerType *> (m_ImageResampler->Clone().GetPointer());
230  resample->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits());
231 
232  // Compute new origin
233  itk::ContinuousIndex <double,TInputImage::ImageDimension> borderOrigin;
234  borderOrigin.Fill(-0.5);
235 
236  typename TInputImage::PointType borderPoint;
237  previousLevelImage->TransformContinuousIndexToPhysicalPoint(borderOrigin,borderPoint);
238 
239  typename TInputImage::DirectionType newDirectionMatrix = previousLevelImage->GetDirection();
240  typename TInputImage::DirectionType newScaleMatrix;
241  newScaleMatrix.SetIdentity();
242 
243  for (unsigned int i = 0;i < TInputImage::ImageDimension;++i)
244  newScaleMatrix(i,i) = m_LevelSpacings[level][i];
245 
246  newDirectionMatrix *= newScaleMatrix;
247 
248  for (unsigned int i = 0;i < TInputImage::ImageDimension;++i)
249  for (unsigned int j = 0;j < TInputImage::ImageDimension;++j)
250  borderPoint[i] += newDirectionMatrix(i,j) * 0.5;
251 
252  resample->SetOutputOrigin(borderPoint);
253 
254  resample->SetOutputLargestPossibleRegion(m_LevelRegions[level]);
255  resample->SetOutputSpacing(m_LevelSpacings[level]);
256  resample->SetOutputDirection(this->GetInput()->GetDirection());
257 
258  resample->SetInput(previousLevelImage);
259 
260  resample->SetTransform(baseTrsf);
261 
262  resample->Update();
263 
264  levelImage = resample->GetOutput();
265  levelImage->DisconnectPipeline();
266 
267  this->GraftNthOutput(level, levelImage);
268 }
269 
270 template <class TInputImage, class TOutputImage>
271 void
273 CreateLevelImage(unsigned int level)
274 {
275  const ScalarInputImageType *previousLevelImage = NULL;
276  if (level == (unsigned int)(m_NumberOfLevels - 1))
277  previousLevelImage = dynamic_cast<const ScalarInputImageType *> (this->GetInput());
278  else
279  previousLevelImage = dynamic_cast<const ScalarInputImageType *> (this->GetOutput(level+1));
280 
281  ScalarOutputImagePointer levelImage;
282 
283  typedef itk::IdentityTransform<double,InputImageType::ImageDimension> IdTrsfType;
284  typename IdTrsfType::Pointer idTrsf = IdTrsfType::New();
285  idTrsf->SetIdentity();
286 
288 
289  typename ResamplerType::Pointer resample = dynamic_cast <ResamplerType *> (m_ImageResampler->Clone().GetPointer());
290 
291  resample->SetTransform(idTrsf);
292  resample->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits());
293 
294  // Compute new origin
295  itk::ContinuousIndex <double,TInputImage::ImageDimension> borderOrigin;
296  borderOrigin.Fill(-0.5);
297 
298  typename TInputImage::PointType borderPoint;
299  previousLevelImage->TransformContinuousIndexToPhysicalPoint(borderOrigin,borderPoint);
300 
301  typename TInputImage::DirectionType newDirectionMatrix = previousLevelImage->GetDirection();
302  typename TInputImage::DirectionType newScaleMatrix;
303  newScaleMatrix.SetIdentity();
304 
305  for (unsigned int i = 0;i < TInputImage::ImageDimension;++i)
306  newScaleMatrix(i,i) = m_LevelSpacings[level][i];
307 
308  newDirectionMatrix *= newScaleMatrix;
309 
310  for (unsigned int i = 0;i < TInputImage::ImageDimension;++i)
311  for (unsigned int j = 0;j < TInputImage::ImageDimension;++j)
312  borderPoint[i] += newDirectionMatrix(i,j) * 0.5;
313 
314  resample->SetOutputOrigin(borderPoint);
315 
316  resample->SetSize(m_LevelRegions[level].GetSize());
317  resample->SetOutputSpacing(m_LevelSpacings[level]);
318  resample->SetOutputDirection(previousLevelImage->GetDirection());
319 
320  resample->SetInput(previousLevelImage);
321  resample->Update();
322 
323  levelImage = resample->GetOutput();
324  levelImage->DisconnectPipeline();
325 
326  this->SetNthOutput(level, levelImage);
327 }
328 
329 } // end of namespace anima
virtual void SetOutputOrigin(OriginPointType _arg)
InputImageType::RegionType RegionType
void CreateLevelVectorImage(unsigned int level)
itk::Image< typename TInputImage::IOPixelType, TInputImage::ImageDimension > ScalarInputImageType
itk::VectorImage< typename TInputImage::IOPixelType, TInputImage::ImageDimension > VectorInputImageType
double AnisotropyMeasure(SpacingType &sp, std::vector< bool > &changeableSizes)
ScalarOutputImageType::Pointer ScalarOutputImagePointer
void SetTransform(TransformType *transform)
void CreateLevelImage(unsigned int level)
InputImageType::SpacingType SpacingType
OutputImageType::Pointer OutputImagePointer