Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkImageStatisticsHolder.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
17 
18 #include "mitkHistogramGenerator.h"
19 //#include "mitkImageTimeSelector.h"
20 #include <mitkProperties.h>
21 
23  : m_Image(image) /*, m_TimeSelectorForExtremaObject(NULL)*/
24 {
25  m_CountOfMinValuedVoxels.resize(1, 0);
26  m_CountOfMaxValuedVoxels.resize(1, 0);
28  m_ScalarMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
30  m_Scalar2ndMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
31 
33  m_HistogramGeneratorObject = generator;
34 
35  // m_Image = image;
36 
37  // create time selector
38  // this->GetTimeSelector();
39 }
40 
42 {
43  m_HistogramGeneratorObject = nullptr;
44  // m_TimeSelectorForExtremaObject = NULL;
45  // m_Image = NULL;
46 }
47 
49  int t, unsigned int /*component*/)
50 {
51  mitk::ImageTimeSelector *timeSelector = this->GetTimeSelector();
52  if (timeSelector != nullptr)
53  {
54  timeSelector->SetTimeNr(t);
55  timeSelector->UpdateLargestPossibleRegion();
56 
57  mitk::HistogramGenerator *generator =
58  static_cast<mitk::HistogramGenerator *>(m_HistogramGeneratorObject.GetPointer());
59  generator->SetImage(timeSelector->GetOutput());
60  generator->ComputeHistogram();
61  return static_cast<const mitk::ImageStatisticsHolder::HistogramType *>(generator->GetHistogram());
62  }
63  return nullptr;
64 }
65 
67 {
68  return m_Image->IsValidTimeStep(t);
69 }
70 
72 {
73  // if(m_TimeSelectorForExtremaObject.IsNull())
74  //{
75  // m_TimeSelectorForExtremaObject = ImageTimeSelector::New();
76 
77  ImageTimeSelector::Pointer timeSelector =
78  ImageTimeSelector::New(); // static_cast<mitk::ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
79  timeSelector->SetInput(m_Image);
80  //}
81 
82  return timeSelector; // static_cast<ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
83 }
84 
85 void mitk::ImageStatisticsHolder::Expand(unsigned int timeSteps)
86 {
87  if (!m_Image->IsValidTimeStep(timeSteps - 1))
88  return;
89 
90  // The BaseData needs to be expanded, call the mitk::Image::Expand() method
91  m_Image->Expand(timeSteps);
92 
93  if (timeSteps > m_ScalarMin.size())
94  {
95  m_ScalarMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
96  m_ScalarMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
97  m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
98  m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
99  m_CountOfMinValuedVoxels.resize(timeSteps, 0);
100  m_CountOfMaxValuedVoxels.resize(timeSteps, 0);
101  }
102 }
103 
105 {
106  m_ScalarMin.assign(1, itk::NumericTraits<ScalarType>::max());
107  m_ScalarMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
108  m_Scalar2ndMin.assign(1, itk::NumericTraits<ScalarType>::max());
109  m_Scalar2ndMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
110  m_CountOfMinValuedVoxels.assign(1, 0);
111  m_CountOfMaxValuedVoxels.assign(1, 0);
112 }
113 
114 #include "mitkImageAccessByItk.h"
115 
116 //#define BOUNDINGOBJECT_IGNORE
117 
118 template <typename ItkImageType>
119 void mitk::_ComputeExtremaInItkImage(const ItkImageType *itkImage, mitk::ImageStatisticsHolder *statisticsHolder, int t)
120 {
121  typename ItkImageType::RegionType region;
122  region = itkImage->GetBufferedRegion();
123  if (region.Crop(itkImage->GetRequestedRegion()) == false)
124  return;
125  if (region != itkImage->GetRequestedRegion())
126  return;
127 
128  itk::ImageRegionConstIterator<ItkImageType> it(itkImage, region);
129  typedef typename ItkImageType::PixelType TPixel;
130  TPixel value = 0;
131 
132  if (statisticsHolder == nullptr || !statisticsHolder->IsValidTimeStep(t))
133  return;
134  statisticsHolder->Expand(t + 1); // make sure we have initialized all arrays
135  statisticsHolder->m_CountOfMinValuedVoxels[t] = 0;
136  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 0;
137 
138  statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMin[t] = itk::NumericTraits<ScalarType>::max();
139  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_ScalarMax[t] =
140  itk::NumericTraits<ScalarType>::NonpositiveMin();
141 
142  while (!it.IsAtEnd())
143  {
144  value = it.Get();
145 // if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) ) mitkImage->m_Scalar2ndMin =
146 // value;
147 // else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) ) mitkImage->m_Scalar2ndMax =
148 // value;
149 // else if (value > mitkImage->m_ScalarMax) mitkImage->m_ScalarMax =
150 // value;
151 // else if (value < mitkImage->m_ScalarMin) mitkImage->m_ScalarMin =
152 // value;
153 
154 // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed
155 #ifdef BOUNDINGOBJECT_IGNORE
156  if (value > -32765)
157  {
158 #endif
159  // update min
160  if (value < statisticsHolder->m_ScalarMin[t])
161  {
162  statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMin[t];
163  statisticsHolder->m_ScalarMin[t] = value;
164  statisticsHolder->m_CountOfMinValuedVoxels[t] = 1;
165  }
166  else if (value == statisticsHolder->m_ScalarMin[t])
167  {
168  ++statisticsHolder->m_CountOfMinValuedVoxels[t];
169  }
170  else if (value < statisticsHolder->m_Scalar2ndMin[t])
171  {
172  statisticsHolder->m_Scalar2ndMin[t] = value;
173  }
174 
175  // update max
176  if (value > statisticsHolder->m_ScalarMax[t])
177  {
178  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_ScalarMax[t];
179  statisticsHolder->m_ScalarMax[t] = value;
180  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 1;
181  }
182  else if (value == statisticsHolder->m_ScalarMax[t])
183  {
184  ++statisticsHolder->m_CountOfMaxValuedVoxels[t];
185  }
186  else if (value > statisticsHolder->m_Scalar2ndMax[t])
187  {
188  statisticsHolder->m_Scalar2ndMax[t] = value;
189  }
190 #ifdef BOUNDINGOBJECT_IGNORE
191  }
192 #endif
193 
194  ++it;
195  }
196 
198  if (statisticsHolder->m_ScalarMax[t] == statisticsHolder->m_ScalarMin[t])
199  {
200  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMax[t];
201  }
202  statisticsHolder->m_LastRecomputeTimeStamp.Modified();
203  // MITK_DEBUG <<"extrema "<<itk::NumericTraits<TPixel>::NonpositiveMin()<<" "<<mitkImage->m_ScalarMin<<"
204  // "<<mitkImage->m_Scalar2ndMin<<" "<<mitkImage->m_Scalar2ndMax<<" "<<mitkImage->m_ScalarMax<<"
205  // "<<itk::NumericTraits<TPixel>::max();
206 }
207 
208 template <typename ItkImageType>
209 void mitk::_ComputeExtremaInItkVectorImage(const ItkImageType *itkImage,
210  mitk::ImageStatisticsHolder *statisticsHolder,
211  int t,
212  unsigned int component)
213 {
214  typename ItkImageType::RegionType region;
215  region = itkImage->GetBufferedRegion();
216  if (region.Crop(itkImage->GetRequestedRegion()) == false)
217  return;
218  if (region != itkImage->GetRequestedRegion())
219  return;
220 
221  itk::ImageRegionConstIterator<ItkImageType> it(itkImage, region);
222 
223  if (statisticsHolder == nullptr || !statisticsHolder->IsValidTimeStep(t))
224  return;
225  statisticsHolder->Expand(t + 1); // make sure we have initialized all arrays
226  statisticsHolder->m_CountOfMinValuedVoxels[t] = 0;
227  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 0;
228 
229  statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMin[t] = itk::NumericTraits<ScalarType>::max();
230  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_ScalarMax[t] =
231  itk::NumericTraits<ScalarType>::NonpositiveMin();
232 
233  while (!it.IsAtEnd())
234  {
235  double value = it.Get()[component];
236 // if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) ) mitkImage->m_Scalar2ndMin =
237 // value;
238 // else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) ) mitkImage->m_Scalar2ndMax =
239 // value;
240 // else if (value > mitkImage->m_ScalarMax) mitkImage->m_ScalarMax =
241 // value;
242 // else if (value < mitkImage->m_ScalarMin) mitkImage->m_ScalarMin =
243 // value;
244 
245 // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed
246 #ifdef BOUNDINGOBJECT_IGNORE
247  if (value > -32765)
248  {
249 #endif
250  // update min
251  if (value < statisticsHolder->m_ScalarMin[t])
252  {
253  statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMin[t];
254  statisticsHolder->m_ScalarMin[t] = value;
255  statisticsHolder->m_CountOfMinValuedVoxels[t] = 1;
256  }
257  else if (value == statisticsHolder->m_ScalarMin[t])
258  {
259  ++statisticsHolder->m_CountOfMinValuedVoxels[t];
260  }
261  else if (value < statisticsHolder->m_Scalar2ndMin[t])
262  {
263  statisticsHolder->m_Scalar2ndMin[t] = value;
264  }
265 
266  // update max
267  if (value > statisticsHolder->m_ScalarMax[t])
268  {
269  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_ScalarMax[t];
270  statisticsHolder->m_ScalarMax[t] = value;
271  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 1;
272  }
273  else if (value == statisticsHolder->m_ScalarMax[t])
274  {
275  ++statisticsHolder->m_CountOfMaxValuedVoxels[t];
276  }
277  else if (value > statisticsHolder->m_Scalar2ndMax[t])
278  {
279  statisticsHolder->m_Scalar2ndMax[t] = value;
280  }
281 #ifdef BOUNDINGOBJECT_IGNORE
282  }
283 #endif
284 
285  ++it;
286  }
287 
289  if (statisticsHolder->m_ScalarMax[t] == statisticsHolder->m_ScalarMin[t])
290  {
291  statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMax[t];
292  }
293  statisticsHolder->m_LastRecomputeTimeStamp.Modified();
294  // MITK_DEBUG <<"extrema "<<itk::NumericTraits<TPixel>::NonpositiveMin()<<" "<<mitkImage->m_ScalarMin<<"
295  // "<<mitkImage->m_Scalar2ndMin<<" "<<mitkImage->m_Scalar2ndMax<<" "<<mitkImage->m_ScalarMax<<"
296  // "<<itk::NumericTraits<TPixel>::max();
297 }
298 
299 void mitk::ImageStatisticsHolder::ComputeImageStatistics(int t, unsigned int component)
300 {
301  // timestep valid?
302  if (!m_Image->IsValidTimeStep(t))
303  return;
304 
305  // image modified?
306  if (this->m_Image->GetMTime() > m_LastRecomputeTimeStamp.GetMTime())
307  this->ResetImageStatistics();
308 
309  Expand(t + 1);
310 
311  // do we have valid information already?
312  if (m_ScalarMin[t] != itk::NumericTraits<ScalarType>::max() ||
313  m_Scalar2ndMin[t] != itk::NumericTraits<ScalarType>::max())
314  return; // Values already calculated before...
315 
316  // used to avoid statistics calculation on qball images. property will be replaced as soons as bug 17928 is merged and
317  // the diffusion image refactoring is complete.
318  mitk::BoolProperty *isqball = dynamic_cast<mitk::BoolProperty *>(m_Image->GetProperty("IsQballImage").GetPointer());
319  const mitk::PixelType pType = m_Image->GetPixelType(0);
320  if (pType.GetNumberOfComponents() == 1 && (pType.GetPixelType() != itk::ImageIOBase::UNKNOWNPIXELTYPE) &&
321  (pType.GetPixelType() != itk::ImageIOBase::VECTOR))
322  {
323  // recompute
324  mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
325  if (timeSelector.IsNotNull())
326  {
327  timeSelector->SetTimeNr(t);
328  timeSelector->UpdateLargestPossibleRegion();
329  const mitk::Image *image = timeSelector->GetOutput();
330  AccessByItk_2(image, _ComputeExtremaInItkImage, this, t);
331  }
332  }
333  else if (pType.GetPixelType() == itk::ImageIOBase::VECTOR &&
334  (!isqball || !isqball->GetValue())) // we have a vector image
335  {
336  // recompute
337  mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
338  if (timeSelector.IsNotNull())
339  {
340  timeSelector->SetTimeNr(t);
341  timeSelector->UpdateLargestPossibleRegion();
342  const mitk::Image *image = timeSelector->GetOutput();
343  AccessVectorPixelTypeByItk_n(image, _ComputeExtremaInItkVectorImage, (this, t, component));
344  }
345  }
346  else
347  {
348  m_ScalarMin[t] = 0;
349  m_ScalarMax[t] = 255;
350  m_Scalar2ndMin[t] = 0;
351  m_Scalar2ndMax[t] = 255;
352  }
353 }
354 
356 {
357  ComputeImageStatistics(t, component);
358  return m_ScalarMin[t];
359 }
360 
362 {
363  ComputeImageStatistics(t, component);
364  return m_ScalarMax[t];
365 }
366 
368 {
369  ComputeImageStatistics(t, component);
370  return m_Scalar2ndMin[t];
371 }
372 
374 {
375  ComputeImageStatistics(t, component);
376  return m_Scalar2ndMax[t];
377 }
378 
380 {
381  ComputeImageStatistics(t, component);
382  return m_CountOfMinValuedVoxels[t];
383 }
384 
386 {
387  ComputeImageStatistics(t, component);
388  return m_CountOfMaxValuedVoxels[t];
389 }
virtual ScalarType GetScalarValue2ndMin(int t=0, unsigned int component=0)
Get the second smallest value for scalar images. Recomputation performed only when necessary...
double ScalarType
virtual ScalarType GetScalarValue2ndMax(int t=0, unsigned int component=0)
Get the second largest value for scalar images.
itk::Object::Pointer m_HistogramGeneratorObject
std::vector< unsigned int > m_CountOfMaxValuedVoxels
std::vector< unsigned int > m_CountOfMinValuedVoxels
virtual void ComputeImageStatistics(int t=0, unsigned int component=0)
itk::ImageIOBase::IOPixelType GetPixelType() const
virtual void Expand(unsigned int timeSteps)
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
virtual void SetTimeNr(int _arg)
#define AccessVectorPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple)
Access a vector mitk::Image by an ITK vector image with one or more parameters.
virtual ScalarType GetScalarValueMax(int t=0, unsigned int component=0)
Get the maximum for scalar images. Recomputation performed only when necessary.
static Pointer New()
Image class for storing images.
Definition: mitkImage.h:76
Provides access to a volume at a specific time of the input image.
static T max(T x, T y)
Definition: svm.cpp:70
virtual void SetImage(mitk::Image::ConstPointer _arg)
Class holding the statistics informations about a single mitk::Image.
ImageTimeSelector::Pointer GetTimeSelector()
vcl_size_t GetNumberOfComponents() const
Get the number of components of which each element consists.
std::vector< ScalarType > m_ScalarMax
unsigned short PixelType
OutputType * GetOutput()
Get the output data of this image source object.
#define AccessByItk_2(mitkImage, itkImageTypeFunction, arg1, arg2)
itk::Statistics::Histogram< double > HistogramType
Provides an easy way to calculate an itk::Histogram for a mitk::Image.
std::vector< ScalarType > m_Scalar2ndMin
mitk::ScalarType GetCountOfMinValuedVoxels(int t=0, unsigned int component=0)
Get the count of voxels with the smallest scalar value in the dataset.
virtual const HistogramType * GetHistogram()
mitk::ScalarType GetCountOfMaxValuedVoxels(int t=0, unsigned int component=0)
Get the count of voxels with the largest scalar value in the dataset.
std::vector< ScalarType > m_Scalar2ndMax
static Pointer New()
Class for defining the data type of pixels.
Definition: mitkPixelType.h:55
std::vector< ScalarType > m_ScalarMin
virtual T GetValue() const
virtual const HistogramType * GetScalarHistogram(int t=0, unsigned int=0)