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