Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkCalculateGrayValueStatisticsTool.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 
18 
19 #include "mitkCalculateGrayValueStatisticsTool.xpm"
20 
21 #include "mitkImageAccessByItk.h"
22 #include "mitkImageCast.h"
23 #include "mitkImageTimeSelector.h"
24 #include "mitkProgressBar.h"
25 #include "mitkStatusBar.h"
26 #include "mitkToolManager.h"
27 
28 #include <itkCommand.h>
29 
30 #include <itkHistogram.h>
31 
32 namespace mitk
33 {
35 }
36 
38 {
39 }
40 
42 {
43 }
44 
46 {
47  return mitkCalculateGrayValueStatisticsTool_xpm;
48 }
49 
51 {
52  return "Statistics";
53 }
54 
56 {
57  return "No statistics generated for these segmentations:";
58 }
59 
61 {
62  // clear/prepare report
63  m_CompleteReport.str("");
64 }
65 
67 {
68  if (node)
69  {
70  Image::Pointer image = dynamic_cast<Image *>(node->GetData());
71  if (image.IsNull())
72  return false;
73 
74  DataNode *referencenode = m_ToolManager->GetReferenceData(0);
75  if (!referencenode)
76  return false;
77 
78  try
79  {
81 
82  // add to report
83  std::string nodename("structure");
84  node->GetName(nodename);
85 
86  std::string message = "Calculating statistics for ";
87  message += nodename;
88 
89  StatusBar::GetInstance()->DisplayText(message.c_str());
90 
91  Image::Pointer refImage = dynamic_cast<Image *>(referencenode->GetData());
92  Image::Pointer image = dynamic_cast<Image *>(node->GetData());
93 
94  m_CompleteReport << "======== Gray value analysis of " << nodename << " ========\n";
95 
96  if (image.IsNotNull() && refImage.IsNotNull())
97  {
98  for (unsigned int timeStep = 0; timeStep < image->GetTimeSteps(); ++timeStep)
99  {
101  timeSelector->SetInput(refImage);
102  timeSelector->SetTimeNr(timeStep);
103  timeSelector->UpdateLargestPossibleRegion();
104  Image::Pointer refImage3D = timeSelector->GetOutput();
105 
107  timeSelector2->SetInput(image);
108  timeSelector2->SetTimeNr(timeStep);
109  timeSelector2->UpdateLargestPossibleRegion();
110  Image::Pointer image3D = timeSelector2->GetOutput();
111 
112  if (image3D.IsNotNull() && refImage3D.IsNotNull())
113  {
114  m_CompleteReport << "=== " << nodename << ", time step " << timeStep << " ===\n";
115  AccessFixedDimensionByItk_2(refImage3D, ITKHistogramming, 3, image3D, m_CompleteReport);
116  }
117  }
118  }
119 
120  m_CompleteReport << "======== End of analysis for " << nodename << " ===========\n\n\n";
121 
123  }
124  catch (...)
125  {
126  return false;
127  }
128  }
129 
130  return true;
131 }
132 
134 {
136 
137  // show/send results
138  StatisticsCompleted.Send();
139  // MITK_INFO << m_CompleteReport.str() << std::endl;
140 }
141 
142 #define ROUND_P(x) ((int)((x) + 0.5))
143 
144 template <typename TPixel, unsigned int VImageDimension>
145 void mitk::CalculateGrayValueStatisticsTool::CalculateMinMax(itk::Image<TPixel, VImageDimension> *referenceImage,
146  Image *segmentation,
147  TPixel &minimum,
148  TPixel &maximum)
149 {
150  typedef itk::Image<TPixel, VImageDimension> ImageType;
151  typedef itk::Image<Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
152 
153  typename SegmentationType::Pointer segmentationItk;
154  CastToItkImage(segmentation, segmentationItk);
155 
156  typename SegmentationType::RegionType segmentationRegion = segmentationItk->GetLargestPossibleRegion();
157 
158  segmentationRegion.Crop(referenceImage->GetLargestPossibleRegion());
159 
160  itk::ImageRegionConstIteratorWithIndex<SegmentationType> segmentationIterator(segmentationItk, segmentationRegion);
161  itk::ImageRegionConstIteratorWithIndex<ImageType> referenceIterator(referenceImage, segmentationRegion);
162 
163  segmentationIterator.GoToBegin();
164  referenceIterator.GoToBegin();
165 
168 
169  while (!segmentationIterator.IsAtEnd())
170  {
171  itk::Point<float, 3> pt;
172  segmentationItk->TransformIndexToPhysicalPoint(segmentationIterator.GetIndex(), pt);
173 
174  typename ImageType::IndexType ind;
175  itk::ContinuousIndex<float, 3> contInd;
176  if (referenceImage->TransformPhysicalPointToContinuousIndex(pt, contInd))
177  {
178  for (unsigned int i = 0; i < 3; ++i)
179  ind[i] = ROUND_P(contInd[i]);
180 
181  referenceIterator.SetIndex(ind);
182 
183  if (segmentationIterator.Get() > 0)
184  {
185  if (referenceIterator.Get() < minimum)
186  minimum = referenceIterator.Get();
187  if (referenceIterator.Get() > maximum)
188  maximum = referenceIterator.Get();
189  }
190  }
191 
192  ++segmentationIterator;
193  }
194 }
195 
196 template <typename TPixel, unsigned int VImageDimension>
197 void mitk::CalculateGrayValueStatisticsTool::ITKHistogramming(itk::Image<TPixel, VImageDimension> *referenceImage,
198  Image *segmentation,
199  std::stringstream &report)
200 {
201  typedef itk::Image<TPixel, VImageDimension> ImageType;
202  typedef itk::Image<Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
203 
204  typename SegmentationType::Pointer segmentationItk;
205  CastToItkImage(segmentation, segmentationItk);
206 
207  // generate histogram
208  typename SegmentationType::RegionType segmentationRegion = segmentationItk->GetLargestPossibleRegion();
209 
210  segmentationRegion.Crop(referenceImage->GetLargestPossibleRegion());
211 
212  itk::ImageRegionConstIteratorWithIndex<SegmentationType> segmentationIterator(segmentationItk, segmentationRegion);
213  itk::ImageRegionConstIteratorWithIndex<ImageType> referenceIterator(referenceImage, segmentationRegion);
214 
215  segmentationIterator.GoToBegin();
216  referenceIterator.GoToBegin();
217 
218  m_ITKHistogram = HistogramType::New();
219 
220  TPixel minimum = std::numeric_limits<TPixel>::max();
221  TPixel maximum = std::numeric_limits<TPixel>::min();
222 
223  CalculateMinMax(referenceImage, segmentation, minimum, maximum);
224 
225  // initialize the histogram to the range of the cropped region
226  HistogramType::SizeType size;
227 #if defined(ITK_USE_REVIEW_STATISTICS)
228  typedef typename HistogramType::SizeType::ValueType HSizeValueType;
229 #else
230  typedef typename HistogramType::SizeType::SizeValueType HSizeValueType;
231 #endif
232  size.Fill(static_cast<HSizeValueType>(maximum - minimum + 1));
233  HistogramType::MeasurementVectorType lowerBound;
234  HistogramType::MeasurementVectorType upperBound;
235  lowerBound[0] = minimum;
236  upperBound[0] = maximum;
237  m_ITKHistogram->Initialize(size, lowerBound, upperBound);
238 
239  double mean(0.0);
240  double sd(0.0);
241  double voxelCount(0.0);
242 
243  // iterate through the cropped region add the values to the histogram
244  while (!segmentationIterator.IsAtEnd())
245  {
246  itk::Point<float, 3> pt;
247  segmentationItk->TransformIndexToPhysicalPoint(segmentationIterator.GetIndex(), pt);
248 
249  typename ImageType::IndexType ind;
250  itk::ContinuousIndex<float, 3> contInd;
251  if (referenceImage->TransformPhysicalPointToContinuousIndex(pt, contInd))
252  {
253  for (unsigned int i = 0; i < 3; ++i)
254  ind[i] = ROUND_P(contInd[i]);
255 
256  referenceIterator.SetIndex(ind);
257 
258  if (segmentationIterator.Get() > 0)
259  {
260  HistogramType::MeasurementVectorType currentMeasurementVector;
261 
262  currentMeasurementVector[0] = static_cast<HistogramType::MeasurementType>(referenceIterator.Get());
263  m_ITKHistogram->IncreaseFrequencyOfMeasurement(currentMeasurementVector, 1);
264 
265  mean = (mean * (static_cast<double>(voxelCount) /
266  static_cast<double>(voxelCount + 1))) // 3 points: old center * 2/3 + currentPoint * 1/3;
267  + static_cast<double>(referenceIterator.Get()) / static_cast<double>(voxelCount + 1);
268 
269  voxelCount += 1.0;
270  }
271  }
272 
273  ++segmentationIterator;
274  }
275 
276  // second pass for SD
277  segmentationIterator.GoToBegin();
278  referenceIterator.GoToBegin();
279  while (!segmentationIterator.IsAtEnd())
280  {
281  itk::Point<float, 3> pt;
282  segmentationItk->TransformIndexToPhysicalPoint(segmentationIterator.GetIndex(), pt);
283 
284  typename ImageType::IndexType ind;
285  itk::ContinuousIndex<float, 3> contInd;
286  if (referenceImage->TransformPhysicalPointToContinuousIndex(pt, contInd))
287  {
288  for (unsigned int i = 0; i < 3; ++i)
289  ind[i] = ROUND_P(contInd[i]);
290 
291  referenceIterator.SetIndex(ind);
292 
293  if (segmentationIterator.Get() > 0)
294  {
295  sd += ((static_cast<double>(referenceIterator.Get()) - mean) *
296  (static_cast<double>(referenceIterator.Get()) - mean));
297  }
298  }
299 
300  ++segmentationIterator;
301  }
302 
303  sd /= static_cast<double>(voxelCount - 1);
304  sd = sqrt(sd);
305 
306  // generate quantiles
307  TPixel histogramQuantileValues[5];
308  histogramQuantileValues[0] = m_ITKHistogram->Quantile(0, 0.05);
309  histogramQuantileValues[1] = m_ITKHistogram->Quantile(0, 0.25);
310  histogramQuantileValues[2] = m_ITKHistogram->Quantile(0, 0.50);
311  histogramQuantileValues[3] = m_ITKHistogram->Quantile(0, 0.75);
312  histogramQuantileValues[4] = m_ITKHistogram->Quantile(0, 0.95);
313 
314  // report histogram values
315  std::locale C("C");
316  std::locale originalLocale = report.getloc();
317  report.imbue(C);
318 
319  report << " Minimum:" << minimum << "\n 5% quantile: " << histogramQuantileValues[0]
320  << "\n 25% quantile: " << histogramQuantileValues[1] << "\n 50% quantile: " << histogramQuantileValues[2]
321  << "\n 75% quantile: " << histogramQuantileValues[3] << "\n 95% quantile: " << histogramQuantileValues[4]
322  << "\n Maximum: " << maximum << "\n Mean: " << mean << "\n SD: " << sd << "\n";
323 
324  report.imbue(originalLocale);
325 }
326 
328 {
329  return m_CompleteReport.str();
330 }
331 
334 {
335  return m_ITKHistogram.GetPointer();
336 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
itk::SmartPointer< Self > Pointer
virtual const char ** GetXPM() const override
Returns an icon in the XPM format.
bool GetName(std::string &nodeName, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="name") const
Convenience access method for accessing the name of an object (instance of StringProperty with proper...
Definition: mitkDataNode.h:366
#define MITKSEGMENTATION_EXPORT
DataCollection - Class to facilitate loading/accessing structured data.
#define MITK_TOOL_MACRO(EXPORT_SPEC, CLASS_NAME, DESCRIPTION)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
virtual void StartProcessingAllData() override
Subclasses should override this method.
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
itk::SmartPointer< const Self > ConstPointer
map::core::discrete::Elements< 3 >::InternalImageType ImageType
void CalculateMinMax(itk::Image< TPixel, VImageDimension > *referenceImage, Image *segmentation, TPixel &minimum, TPixel &maximum)
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
virtual void FinishProcessingAllData() override
Subclasses should override this method.
virtual const char * GetName() const override
Returns the name of this tool. Make it short!
void DisplayText(const char *t)
Send a string to the applications StatusBar.
ValueType
Type of the value held by a Value object.
Definition: jsoncpp.h:345
virtual std::string GetErrorMessage() override
Describes the error (if one occurred during processing).
Image class for storing images.
Definition: mitkImage.h:76
Calculates some gray value statistics for segmentations.
static T max(T x, T y)
Definition: svm.cpp:70
void ITKHistogramming(itk::Image< TPixel, VImageDimension > *referenceImage, Image *segmentation, std::stringstream &report)
static StatusBar * GetInstance()
static method to get the GUI dependent StatusBar-instance so the methods DisplayText, etc. can be called No reference counting, cause of decentral static use!
static T min(T x, T y)
Definition: svm.cpp:67
void AddStepsToDo(unsigned int steps)
Adds steps to totalSteps.
virtual bool ProcessOneWorkingData(DataNode *node) override
Subclasses should override this method.
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
virtual void FinishProcessingAllData()
Subclasses should override this method.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static Pointer New()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.