ANIMA  4.0
animaMCMLinearInterpolateImageFunction.hxx
Go to the documentation of this file.
1 #pragma once
3 
4 #include <itkMultiThreaderBase.h>
5 
6 namespace anima
7 {
11 template<class TInputImage, class TCoordRep>
12 const unsigned long
13 MCMLinearInterpolateImageFunction< TInputImage, TCoordRep >
14 ::m_Neighbors = 1 << TInputImage::ImageDimension;
15 
16 
20 template<class TInputImage, class TCoordRep>
23 {
24 }
25 
26 template<class TInputImage, class TCoordRep>
27 void
30 {
31  this->Superclass::SetInputImage(ptr);
32 
33  InputImageType *input = const_cast <InputImageType *> (ptr);
34  MCModelPointer model = input->GetDescriptionModel();
35 
36  if (m_MCMAveragers.size() != 0)
37  {
38  if (m_MCMAveragers[0].IsNotNull())
39  this->TestModelsAdequation(model,m_MCMAveragers[0]->GetUntouchedOutputModel());
40  }
41 
42  unsigned int numThreads = itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads();
43  m_ReferenceInputModels.resize(numThreads);
44  m_ReferenceInputWeights.resize(numThreads);
45  for (unsigned int i = 0;i < numThreads;++i)
46  {
47  m_ReferenceInputModels[i].resize(m_Neighbors);
48  m_ReferenceInputWeights[i].resize(m_Neighbors);
49  std::fill(m_ReferenceInputWeights[i].begin(),m_ReferenceInputWeights[i].end(),0.0);
50  for (unsigned int j = 0;j < m_Neighbors;++j)
51  m_ReferenceInputModels[i][j] = model->Clone();
52  }
53 }
54 
55 template<class TInputImage, class TCoordRep>
56 void
59 {
60  if (this->GetInputImage() != 0)
61  this->TestModelsAdequation(m_ReferenceInputModels[0][0],model);
62 
63  this->ResetAveragePointers(model);
64 }
65 
66 template<class TInputImage, class TCoordRep>
67 void
70 {
71  unsigned int numThreads = itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads();
72  m_MCMAveragers.resize(numThreads);
73 
74  for (unsigned int i = 0;i < numThreads;++i)
75  {
76  m_MCMAveragers[i] = AveragerType::New();
77  m_MCMAveragers[i]->SetOutputModel(model);
78  }
79 }
80 
81 template<class TInputImage, class TCoordRep>
82 bool
85 {
86  unsigned int numIsoCompartments = model->GetNumberOfIsotropicCompartments();
87  if (!model->GetCompartment(numIsoCompartments)->GetTensorCompatible())
88  return false;
89 
90  return true;
91 }
92 
93 template<class TInputImage, class TCoordRep>
94 void
97 {
98  unsigned int numIsoCompartmentsInput = inputModel->GetNumberOfIsotropicCompartments();
99  unsigned int numIsoCompartmentsOutput = outputModel->GetNumberOfIsotropicCompartments();
100 
101  if (numIsoCompartmentsInput != numIsoCompartmentsOutput)
102  itkExceptionMacro("Cannot handle interpolation to model with different number of isotropic compartments.");
103 
104  for (unsigned int i = 0;i < numIsoCompartmentsInput;++i)
105  {
106  if (outputModel->GetCompartment(i)->GetCompartmentType() != inputModel->GetCompartment(i)->GetCompartmentType())
107  itkExceptionMacro("Interpolation only of models with the same isotropic compartment types.");
108  }
109 
110  if (outputModel->GetNumberOfCompartments() - numIsoCompartmentsOutput > 0)
111  {
112  if (outputModel->GetCompartment(numIsoCompartmentsOutput)->GetCompartmentType()
113  != inputModel->GetCompartment(numIsoCompartmentsOutput)->GetCompartmentType())
114  itkExceptionMacro("Interpolation of non tensor compatible models only to the same compartment type.");
115 
116  if (!this->CheckModelCompatibility(outputModel))
117  itkExceptionMacro("Model not yet supported by MCM linear interpolation");
118  }
119 }
120 
121 
122 template<class TInputImage, class TCoordRep>
123 unsigned int
126 {
127  m_LockUsedModels.lock();
128 
129  unsigned int workIndex = 0;
130  bool workIndexOk = false;
131 
132  while ((!workIndexOk)&&(workIndex < m_ReferenceInputModels.size()))
133  {
134  workIndexOk = true;
135  for (unsigned int i = 0;i < m_UsedModels.size();++i)
136  {
137  if (m_UsedModels[i] == workIndex)
138  {
139  workIndexOk = false;
140  break;
141  }
142  }
143 
144  if (!workIndexOk)
145  ++workIndex;
146  }
147 
148  m_UsedModels.push_back(workIndex);
149  m_LockUsedModels.unlock();
150 
151  return workIndex;
152 }
153 
154 template<class TInputImage, class TCoordRep>
155 void
157 ::UnlockWorkIndex(unsigned int index) const
158 {
159  m_LockUsedModels.lock();
160 
161  for (unsigned int i = 0;i < m_UsedModels.size();++i)
162  {
163  if (m_UsedModels[i] == index)
164  {
165  m_UsedModels.erase(m_UsedModels.begin() + i);
166  break;
167  }
168  }
169 
170  m_LockUsedModels.unlock();
171 }
172 
176 template<class TInputImage, class TCoordRep>
181 {
182  IndexType baseIndex;
183  double distance[ImageDimension], oppDistance[ImageDimension];
184 
185  for (unsigned int dim = 0; dim < ImageDimension; ++dim)
186  {
187  baseIndex[dim] = itk::Math::Floor< IndexValueType >( index[dim] );
188  distance[dim] = index[dim] - static_cast< double >( baseIndex[dim] );
189  oppDistance[dim] = 1.0 - distance[dim];
190  }
191 
192  unsigned int threadIndex = this->GetFreeWorkIndex();
193 
194  OutputType voxelOutputValue(m_MCMAveragers[threadIndex]->GetOutputModelSize());
195  voxelOutputValue.Fill(0);
196  std::fill(m_ReferenceInputWeights[threadIndex].begin(),m_ReferenceInputWeights[threadIndex].end(),0.0);
197 
198  this->SetSpecificAveragerParameters(threadIndex);
199  m_MCMAveragers[threadIndex]->ResetNumberOfOutputDirectionalCompartments();
200 
201  double totalOverlap = 0;
202 
203  unsigned int posMCM = 0;
204  unsigned int maxNumCompartments = 0;
205 
206  unsigned int numIsoCompartments = m_ReferenceInputModels[threadIndex][0]->GetNumberOfIsotropicCompartments();
207  unsigned int numberOfTotalInputCompartments = m_ReferenceInputModels[threadIndex][0]->GetNumberOfCompartments();
208 
209  for (unsigned int counterInput = 0;counterInput < m_Neighbors;++counterInput)
210  {
211  double overlap = 1.0; // fraction overlap
212  unsigned int upper = counterInput; // each bit indicates upper/lower neighbour
213  IndexType neighIndex;
214 
215  // get neighbor index and overlap fraction
216  bool okValue = true;
217  for (unsigned int dim = 0; dim < ImageDimension; ++dim)
218  {
219  if (upper & 1)
220  {
221  neighIndex[dim] = baseIndex[dim] + 1;
222 
223  if (neighIndex[dim] > this->m_EndIndex[dim])
224  {
225  okValue = false;
226  break;
227  }
228 
229  overlap *= distance[dim];
230  }
231  else
232  {
233  neighIndex[dim] = baseIndex[dim];
234 
235  if (neighIndex[dim] < this->m_StartIndex[dim])
236  {
237  okValue = false;
238  break;
239  }
240 
241  overlap *= oppDistance[dim];
242  }
243 
244  upper >>= 1;
245  }
246 
247  // get neighbor value only if overlap is not zero
248  if ((overlap > 0) && okValue)
249  {
250  const PixelType input = this->GetInputImage()->GetPixel( neighIndex );
251  if (isZero(input))
252  continue;
253 
254  m_ReferenceInputModels[threadIndex][posMCM]->SetModelVector(input);
255  m_ReferenceInputWeights[threadIndex][posMCM] = overlap;
256 
257  unsigned int numEffectiveAnisotropicCompartments = 0;
258  for (unsigned int i = numIsoCompartments;i < numberOfTotalInputCompartments;++i)
259  {
260  double fascWeight = m_ReferenceInputModels[threadIndex][posMCM]->GetCompartmentWeight(i);
261  if (fascWeight <= 0)
262  continue;
263 
264  ++numEffectiveAnisotropicCompartments;
265  }
266 
267  if (numEffectiveAnisotropicCompartments > maxNumCompartments)
268  maxNumCompartments = numEffectiveAnisotropicCompartments;
269 
270  totalOverlap += overlap;
271  ++posMCM;
272  }
273  }
274 
275  if (totalOverlap < 0.5)
276  {
277  this->UnlockWorkIndex(threadIndex);
278  voxelOutputValue.Fill(0.0);
279  return voxelOutputValue;
280  }
281 
282  m_MCMAveragers[threadIndex]->SetNumberOfOutputDirectionalCompartments(maxNumCompartments);
283  m_MCMAveragers[threadIndex]->SetInputModels(m_ReferenceInputModels[threadIndex]);
284  m_MCMAveragers[threadIndex]->SetInputWeights(m_ReferenceInputWeights[threadIndex]);
285 
286  m_MCMAveragers[threadIndex]->Update();
287 
288  voxelOutputValue = m_MCMAveragers[threadIndex]->GetOutputModel()->GetModelVector();
289 
290  this->UnlockWorkIndex(threadIndex);
291 
292  // Be sure there is no nan value in a voxel
293  for (int i = 0; i < voxelOutputValue.GetSize(); ++i)
294  {
295  if (std::isnan(voxelOutputValue[i]))
296  itkExceptionMacro("Problem, OutputVoxel has a nan value.");
297  }
298 
299  return voxelOutputValue;
300 }
301 
302 } // end namespace anima
void TestModelsAdequation(MCModelPointer &inputModel, MCModelPointer &outputModel)
Tests if input and output models of the interpolator are compatible.
virtual void SetInputImage(const InputImageType *ptr) ITK_OVERRIDE
virtual OutputType EvaluateAtContinuousIndex(const ContinuousIndexType &index) const ITK_OVERRIDE
virtual void ResetAveragePointers(MCModelPointer &model)
Resets averager pointers, can be overloaded to handle more models.
virtual bool CheckModelCompatibility(MCModelPointer &model)
Check if model can actually be interpolated.