Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkLevelWindow.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 ===================================================================*/
16 
17 #include "mitkLevelWindow.h"
18 #include "mitkImage.h"
19 #include "mitkImageSliceSelector.h"
21 
22 #include <algorithm>
23 
25 {
26  // Check if total range is ok
27  {
28  if (m_RangeMin > m_RangeMax)
30  if (m_RangeMin == m_RangeMax)
31  m_RangeMin = m_RangeMax - 1;
32  }
33 
34  // Check if current window is ok
35  {
38 
47 
49  {
50  m_UpperWindowBound += 0.5;
51  m_LowerWindowBound -= 0.5;
52 
55  }
56  }
57 }
58 
60  : m_LowerWindowBound(level - window / 2.0),
61  m_UpperWindowBound(level + window / 2.0),
62  m_RangeMin(-2048.0),
63  m_RangeMax(4096.0),
64  m_DefaultLowerBound(-2048.0),
65  m_DefaultUpperBound(4096.0),
66  m_IsFloatingImage(false),
67  m_Fixed(false)
68 {
69  SetDefaultLevelWindow(level, window);
70  SetLevelWindow(level, window, true);
71 }
72 
74  : m_LowerWindowBound(levWin.GetLowerWindowBound()),
75  m_UpperWindowBound(levWin.GetUpperWindowBound()),
76  m_RangeMin(levWin.GetRangeMin()),
77  m_RangeMax(levWin.GetRangeMax()),
78  m_DefaultLowerBound(levWin.GetDefaultLowerBound()),
79  m_DefaultUpperBound(levWin.GetDefaultUpperBound()),
80  m_IsFloatingImage(levWin.IsFloatingValues()),
81  m_Fixed(levWin.GetFixed())
82 {
83 }
84 
86 {
87 }
88 
90 {
91  return (m_UpperWindowBound - m_LowerWindowBound) / 2.0 + m_LowerWindowBound;
92 }
93 
95 {
96  return (m_UpperWindowBound - m_LowerWindowBound);
97 }
98 
100 {
101  return ((m_DefaultUpperBound + m_DefaultLowerBound) / 2.0);
102 }
103 
105 {
106  return ((m_DefaultUpperBound - m_DefaultLowerBound));
107 }
108 
110 {
111  SetLevelWindow(GetDefaultLevel(), GetDefaultWindow());
112 }
113 
115 {
116  return m_LowerWindowBound;
117 }
118 
120 {
121  return m_UpperWindowBound;
122 }
123 
125 {
126  SetDefaultBoundaries((level - (window / 2.0)), (level + (window / 2.0)));
127 }
128 
129 void mitk::LevelWindow::SetLevelWindow(mitk::ScalarType level, mitk::ScalarType window, bool expandRangesIfNecessary)
130 {
131  SetWindowBounds((level - (window / 2.0)), (level + (window / 2.0)), expandRangesIfNecessary);
132 }
133 
135  mitk::ScalarType upperBound,
136  bool expandRangesIfNecessary)
137 {
138  if (IsFixed())
139  return;
140 
141  m_LowerWindowBound = lowerBound;
142  m_UpperWindowBound = upperBound;
143 
144  if (expandRangesIfNecessary)
145  {
146  /* if caller is sure he wants exactly that level/window, we make sure the limits match */
147  if (m_LowerWindowBound > m_UpperWindowBound)
148  std::swap(m_LowerWindowBound, m_UpperWindowBound);
149  if (m_LowerWindowBound < m_RangeMin)
150  {
151  m_RangeMin = m_LowerWindowBound;
152  }
153 
154  if (m_UpperWindowBound > m_RangeMax)
155  {
156  m_RangeMax = m_UpperWindowBound;
157  }
158  }
159 
160  EnsureConsistency();
161 }
162 
164 {
165  if (IsFixed())
166  return;
167  m_RangeMin = min;
168  m_RangeMax = max;
169  EnsureConsistency();
170 }
171 
173 {
174  if (IsFixed())
175  return;
176  m_DefaultLowerBound = low;
177  m_DefaultUpperBound = up;
178  // Check if default window is ok
179  {
180  if (m_DefaultLowerBound > m_DefaultUpperBound)
181  std::swap(m_DefaultLowerBound, m_DefaultUpperBound);
182 
183  if (m_DefaultLowerBound == m_DefaultUpperBound)
184  m_DefaultLowerBound--;
185  }
186  EnsureConsistency();
187 }
188 
190 {
191  SetWindowBounds(m_RangeMin, m_RangeMax);
192 }
193 
195 {
196  return m_RangeMin;
197 }
198 
200 {
201  return m_RangeMax;
202 }
203 
205 {
206  return m_RangeMax - m_RangeMin;
207 }
208 
210 {
211  return m_DefaultUpperBound;
212 }
213 
215 {
216  return m_DefaultLowerBound;
217 }
218 
220 {
221  SetRangeMinMax(m_DefaultLowerBound, m_DefaultUpperBound);
222 }
223 
261  bool /*tryPicTags*/,
262  bool guessByCentralSlice,
263  unsigned selectedComponent)
264 {
265  if (IsFixed())
266  return;
267 
268  if (image == nullptr || !image->IsInitialized())
269  return;
270 
271  if ((image->GetPixelType().GetComponentType() == 9) || (image->GetPixelType().GetComponentType() == 10))
272  {
273  // Floating image
274  m_IsFloatingImage = true;
275  }
276  else
277  {
278  m_IsFloatingImage = false;
279  }
280 
281  const mitk::Image *wholeImage = image;
282  ScalarType minValue = 0.0;
283  ScalarType maxValue = 0.0;
284  ScalarType min2ndValue = 0.0;
285  ScalarType max2ndValue = 0.0;
287  if (guessByCentralSlice)
288  {
289  sliceSelector->SetInput(image);
290  sliceSelector->SetSliceNr(image->GetDimension(2) / 2);
291  sliceSelector->SetTimeNr(image->GetDimension(3) / 2);
292  sliceSelector->SetChannelNr(image->GetDimension(4) / 2);
293  sliceSelector->Update();
294  image = sliceSelector->GetOutput();
295  if (image == nullptr || !image->IsInitialized())
296  return;
297 
298  minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);
299  maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute();
300  min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute();
301  max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute();
302  if (minValue == maxValue)
303  {
304  // guessByCentralSlice seems to have failed, lets look at all data
305  image = wholeImage;
306  minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);
307  maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute();
308  min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute();
309  max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute();
310  }
311  }
312  else
313  {
314  const_cast<Image *>(image)->Update();
315  minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);
316  maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(0);
317  min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(0);
318  max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(0);
319  for (unsigned int i = 1; i < image->GetDimension(3); ++i)
320  {
321  ScalarType minValueTemp = image->GetStatistics()->GetScalarValueMin(i, selectedComponent);
322  if (minValue > minValueTemp)
323  minValue = minValueTemp;
324  ScalarType maxValueTemp = image->GetStatistics()->GetScalarValueMaxNoRecompute(i);
325  if (maxValue < maxValueTemp)
326  maxValue = maxValueTemp;
327  ScalarType min2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(i);
328  if (min2ndValue > min2ndValueTemp)
329  min2ndValue = min2ndValueTemp;
330  ScalarType max2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(i);
331  if (max2ndValue > max2ndValueTemp)
332  max2ndValue = max2ndValueTemp;
333  }
334  }
335 
336  // Fix for bug# 344 Level Window wird bei Eris Cut bildern nicht richtig gesetzt
337  if (image->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR &&
338  image->GetPixelType().GetComponentType() == itk::ImageIOBase::INT && image->GetPixelType().GetBpe() >= 8)
339  {
340  // the windows compiler complains about ambiguos 'pow' call, therefore static casting to (double, int)
341  if (minValue == -(pow((double)2.0, static_cast<int>(image->GetPixelType().GetBpe() / 2))))
342  {
343  minValue = min2ndValue;
344  }
345  }
346  // End fix
347 
349  if (minValue == maxValue)
350  {
351  minValue = maxValue - 1;
352  }
353  else
354  {
355  // Due to bug #8690 level window now is no longer of fixed range by default but the range adapts according to
356  // levelwindow interaction
357  // This is done because the range should be a little bit larger from the beginning so that the scale doesn't start
358  // to resize right from the beginning
359  double additionalRange = 0.15 * (maxValue - minValue);
360  minValue -= additionalRange;
361  maxValue += additionalRange;
362  }
363  SetRangeMinMax(minValue, maxValue);
364  SetDefaultBoundaries(minValue, maxValue);
365  /*
366  if ( tryPicTags ) // level and window will be set by informations provided directly by the mitkIpPicDescriptor
367  {
368  if ( SetAutoByPicTags(const_cast<Image*>(image)->GetPic()) )
369  {
370  return;
371  }
372  }
373  */
374 
375  unsigned int numPixelsInDataset = image->GetDimensions()[0];
376  for (unsigned int k = 0; k < image->GetDimension(); ++k)
377  numPixelsInDataset *= image->GetDimensions()[k];
378  unsigned int minCount = image->GetStatistics()->GetCountOfMinValuedVoxelsNoRecompute();
379  unsigned int maxCount = image->GetStatistics()->GetCountOfMaxValuedVoxelsNoRecompute();
380  ScalarType minCountFraction = minCount / ScalarType(numPixelsInDataset);
381  ScalarType maxCountFraction = maxCount / ScalarType(numPixelsInDataset);
382 
384  if (min2ndValue == maxValue)
385  {
386  // noop; full range is fine
387  }
388 
390  else if (min2ndValue == max2ndValue)
391  {
392  ScalarType minDelta = std::min(min2ndValue - minValue, maxValue - min2ndValue);
393  minValue = min2ndValue - minDelta;
394  maxValue = min2ndValue + minDelta;
395  }
396 
397  // now we can assume more than three distict scalar values
398  else
399  {
400  ScalarType innerRange = max2ndValue - min2ndValue;
401 
402  if (minCountFraction > 0.2)
403  {
404  ScalarType halfInnerRangeGapMinValue = min2ndValue - innerRange / 2.0;
405  minValue = std::max(minValue, halfInnerRangeGapMinValue);
406  }
407  else
408  {
409  minValue = min2ndValue;
410  }
411 
412  if (maxCountFraction > 0.2)
413  {
414  ScalarType halfInnerRangeGapMaxValue = max2ndValue + innerRange / 2.0;
415  maxValue = std::min(maxValue, halfInnerRangeGapMaxValue);
416  }
417  else
418  {
419  maxValue = max2ndValue;
420  }
421  }
422  SetWindowBounds(minValue, maxValue);
423  SetDefaultLevelWindow((maxValue - minValue) / 2 + minValue, maxValue - minValue);
424 }
425 
427 {
428  if (IsFixed())
429  return;
430 
431  if (image == NULL || !image->IsInitialized())
432  return;
433 
434  ScalarType minValue = image->GetStatistics()->GetScalarValueMin(0);
435  ScalarType maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(0);
436  SetRangeMinMax(minValue, maxValue);
437  SetDefaultBoundaries(minValue, maxValue);
438  SetWindowBounds(minValue, maxValue);
439  SetDefaultLevelWindow((maxValue - minValue) / 2 + minValue, maxValue - minValue);
440 }
441 
443 {
444  m_Fixed = fixed;
445 }
446 
448 {
449  return m_Fixed;
450 }
451 
453 {
454  return m_Fixed;
455 }
456 
458 {
459  return m_IsFloatingImage;
460 }
461 
463 {
464  m_IsFloatingImage = value;
465 }
466 
468 {
469  return mitk::Equal(this->m_RangeMin, levWin.m_RangeMin, mitk::sqrteps) &&
470  mitk::Equal(this->m_RangeMax, levWin.m_RangeMax, mitk::sqrteps) &&
471  mitk::Equal(this->m_DefaultLowerBound, levWin.m_DefaultLowerBound, mitk::sqrteps) &&
472  mitk::Equal(this->m_DefaultUpperBound, levWin.m_DefaultUpperBound, mitk::sqrteps) &&
473  mitk::Equal(this->m_LowerWindowBound, levWin.m_LowerWindowBound, mitk::sqrteps) &&
474  mitk::Equal(this->m_UpperWindowBound, levWin.m_UpperWindowBound, mitk::sqrteps) &&
475  m_Fixed == levWin.IsFixed() && m_IsFloatingImage == levWin.IsFloatingValues();
476 }
477 
479 {
480  return !((*this) == levWin);
481 }
482 
484 {
485  if (this == &levWin)
486  {
487  return *this;
488  }
489  else
490  {
491  m_RangeMin = levWin.GetRangeMin();
492  m_RangeMax = levWin.GetRangeMax();
493  m_LowerWindowBound = levWin.GetLowerWindowBound();
494  m_UpperWindowBound = levWin.GetUpperWindowBound();
495  m_DefaultLowerBound = levWin.GetDefaultLowerBound();
496  m_DefaultUpperBound = levWin.GetDefaultUpperBound();
497  m_Fixed = levWin.GetFixed();
498  m_IsFloatingImage = levWin.IsFloatingValues();
499  return *this;
500  }
501 }
void SetWindowBounds(ScalarType lowerBound, ScalarType upperBound, bool expandRangesIfNecessary=true)
ScalarType m_DefaultLowerBound
LevelWindow(ScalarType level=127.5, ScalarType window=255.0)
ScalarType GetDefaultLevel() const
method returns the default level value for the image
ScalarType GetLowerWindowBound() const
void ResetDefaultLevelWindow()
Resets the level and the window value to the default values.
void SetFixed(bool fixed)
double ScalarType
ScalarType m_DefaultUpperBound
void SetToImageRange(const Image *image)
sets level/window to the min/max greyvalues of the given Image
StatisticsHolderPointer GetStatistics() const
Returns a pointer to the ImageStatisticsHolder object that holds all statistics information for the i...
Definition: mitkImage.h:646
bool IsFloatingValues() const
Shows if floating values are accepted.
ScalarType GetDefaultWindow() const
returns the default window size for the image
virtual mitk::ScalarType GetScalarValue2ndMaxNoRecompute(unsigned int t=0)
Get the second largest value for scalar images, but do not recompute it first.
static void Update(vtkPolyData *)
Definition: mitkSurface.cpp:35
itk::ImageIOBase::IOPixelType GetPixelType() const
static Pointer New()
virtual mitk::ScalarType GetScalarValue2ndMinNoRecompute(unsigned int t=0) const
Get the second smallest value for scalar images, but do not recompute it first.
virtual unsigned int GetCountOfMinValuedVoxelsNoRecompute(unsigned int t=0) const
Get the count of voxels with the smallest scalar value in the dataset.
virtual mitk::ScalarType GetScalarValueMaxNoRecompute(unsigned int t=0)
Get the largest value for scalar images, but do not recompute it first.
ScalarType GetDefaultLowerBound() const
virtual unsigned int GetCountOfMaxValuedVoxelsNoRecompute(unsigned int t=0)
Get the count of voxels with the largest scalar value in the dataset.
void SetRangeMinMax(ScalarType min, ScalarType max)
ScalarType GetDefaultUpperBound() const
The LevelWindow class Class to store level/window values.
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
bool IsFixed() const
virtual LevelWindow & operator=(const LevelWindow &levWin)
implementation necessary because operator made private in itk::Object
void SetFloatingValues(bool value)
Sets the floating image value.
vcl_size_t GetBpe() const
Get the number of bits per element (of an element)
void SetDefaultLevelWindow(ScalarType level, ScalarType window)
unsigned int * GetDimensions() const
Get the sizes of all dimensions as an integer-array.
Definition: mitkImage.cpp:1308
void ResetDefaultRangeMinMax()
the default min and max range for image will be reset
Image class for storing images.
Definition: mitkImage.h:76
void SetAuto(const Image *image, bool tryPicTags=true, bool guessByCentralSlice=true, unsigned selectedComponent=0)
sets level/window to optimize the contrast of the given Image
bool GetFixed() const
ScalarType m_UpperWindowBound
virtual bool operator!=(const LevelWindow &levWin) const
non equality operator implementation that allows to compare two level windows
int GetComponentType() const
Get the component type (the scalar (!) type). Each element may contain m_NumberOfComponents (more tha...
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:105
static T max(T x, T y)
Definition: svm.cpp:70
static T min(T x, T y)
Definition: svm.cpp:67
MITKCORE_EXPORT const ScalarType sqrteps
void SetDefaultBoundaries(ScalarType low, ScalarType up)
ScalarType GetRangeMax() const
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
ScalarType m_LowerWindowBound
static void swap(T &x, T &y)
Definition: svm.cpp:72
virtual bool IsInitialized() const
Check whether the data has been initialized, i.e., at least the Geometry and other header data has be...
ScalarType GetRangeMin() const
virtual bool operator==(const LevelWindow &levWin) const
equality operator implementation that allows to compare two level windows
ScalarType GetUpperWindowBound() const
void SetLevelWindow(ScalarType level, ScalarType window, bool expandRangesIfNecessary=true)
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:110
ScalarType GetWindow() const
returns the current window size, i.e the range size of the current grey value interval ...
ScalarType GetRange() const
returns the size of the grey value range
ScalarType GetLevel() const
method that returns the level value, i.e. the center of the current grey value interval ...