Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkIntensityProfile.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 <itkLinearInterpolateImageFunction.h>
18 #include <itkNearestNeighborInterpolateImageFunction.h>
19 #include <itkPolyLineParametricPath.h>
20 #include <itkWindowedSincInterpolateImageFunction.h>
21 #include <mitkImageAccessByItk.h>
23 #include <mitkPixelTypeMultiplex.h>
24 #include "mitkIntensityProfile.h"
25 
26 using namespace mitk;
27 
28 template <class T>
29 static void ReadPixel(const PixelType&, Image::Pointer image, const itk::Index<3>& index, ScalarType* returnValue)
30 {
31  switch (image->GetDimension())
32  {
33  case 2:
34  {
35  ImagePixelReadAccessor<T, 2> readAccess(image, image->GetSliceData(0));
36  *returnValue = readAccess.GetPixelByIndex(reinterpret_cast<const itk::Index<2>&>(index));
37  break;
38  }
39 
40  case 3:
41  {
42  ImagePixelReadAccessor<T, 3> readAccess(image, image->GetVolumeData(0));
43  *returnValue = readAccess.GetPixelByIndex(index);
44  break;
45  }
46 
47  default:
48  *returnValue = 0;
49  break;
50  }
51 }
52 
54 {
56  itk::PolyLineParametricPath<3>::InputType input = path->StartOfInput();
57  BaseGeometry* imageGeometry = image->GetGeometry();
58  const PixelType pixelType = image->GetPixelType();
59 
60  IntensityProfile::MeasurementVectorType measurementVector;
61  itk::PolyLineParametricPath<3>::OffsetType offset;
62  Point3D worldPoint;
63  itk::Index<3> index;
64 
65  do
66  {
67  imageGeometry->IndexToWorld(path->Evaluate(input), worldPoint);
68  imageGeometry->WorldToIndex(worldPoint, index);
69 
70  mitkPixelTypeMultiplex3(ReadPixel, pixelType, image, index, measurementVector.GetDataPointer());
71  intensityProfile->PushBack(measurementVector);
72 
73  offset = path->IncrementInput(input);
74  } while ((offset[0] | offset[1] | offset[2]) != 0);
75 
76  return intensityProfile;
77 }
78 
79 template <class TInputImage>
81 {
82  switch (interpolator)
83  {
86 
89 
91  return itk::WindowedSincInterpolateImageFunction<TInputImage, 3, itk::Function::BlackmanWindowFunction<3> >::New().GetPointer();
92 
94  return itk::WindowedSincInterpolateImageFunction<TInputImage, 4, itk::Function::BlackmanWindowFunction<4> >::New().GetPointer();
95 
97  return itk::WindowedSincInterpolateImageFunction<TInputImage, 5, itk::Function::BlackmanWindowFunction<5> >::New().GetPointer();
98 
100  return itk::WindowedSincInterpolateImageFunction<TInputImage, 3, itk::Function::CosineWindowFunction<3> >::New().GetPointer();
101 
103  return itk::WindowedSincInterpolateImageFunction<TInputImage, 4, itk::Function::CosineWindowFunction<4> >::New().GetPointer();
104 
106  return itk::WindowedSincInterpolateImageFunction<TInputImage, 5, itk::Function::CosineWindowFunction<5> >::New().GetPointer();
107 
109  return itk::WindowedSincInterpolateImageFunction<TInputImage, 3, itk::Function::HammingWindowFunction<3> >::New().GetPointer();
110 
112  return itk::WindowedSincInterpolateImageFunction<TInputImage, 4, itk::Function::HammingWindowFunction<4> >::New().GetPointer();
113 
115  return itk::WindowedSincInterpolateImageFunction<TInputImage, 5, itk::Function::HammingWindowFunction<5> >::New().GetPointer();
116 
118  return itk::WindowedSincInterpolateImageFunction<TInputImage, 3, itk::Function::LanczosWindowFunction<3> >::New().GetPointer();
119 
121  return itk::WindowedSincInterpolateImageFunction<TInputImage, 4, itk::Function::LanczosWindowFunction<4> >::New().GetPointer();
122 
124  return itk::WindowedSincInterpolateImageFunction<TInputImage, 5, itk::Function::LanczosWindowFunction<5> >::New().GetPointer();
125 
127  return itk::WindowedSincInterpolateImageFunction<TInputImage, 3, itk::Function::WelchWindowFunction<3> >::New().GetPointer();
128 
130  return itk::WindowedSincInterpolateImageFunction<TInputImage, 4, itk::Function::WelchWindowFunction<4> >::New().GetPointer();
131 
133  return itk::WindowedSincInterpolateImageFunction<TInputImage, 5, itk::Function::WelchWindowFunction<5> >::New().GetPointer();
134 
135  default:
137  }
138 }
139 
140 template <class TPixel, unsigned int VImageDimension>
141 static void ComputeIntensityProfile(itk::Image<TPixel, VImageDimension>* image, itk::PolyLineParametricPath<3>::Pointer path, unsigned int numSamples, InterpolateImageFunction::Enum interpolator, IntensityProfile::Pointer intensityProfile)
142 {
143  typename itk::InterpolateImageFunction<itk::Image<TPixel, VImageDimension> >::Pointer interpolateImageFunction = CreateInterpolateImageFunction<itk::Image<TPixel, VImageDimension> >(interpolator);
144  interpolateImageFunction->SetInputImage(image);
145 
146  const itk::PolyLineParametricPath<3>::InputType startOfInput = path->StartOfInput();
147  const itk::PolyLineParametricPath<3>::InputType delta = 1.0 / (numSamples - 1);
148 
149  IntensityProfile::MeasurementVectorType measurementVector;
150 
151  for (unsigned int i = 0; i < numSamples; ++i)
152  {
153  measurementVector[0] = interpolateImageFunction->EvaluateAtContinuousIndex(path->Evaluate(startOfInput + i * delta));
154  intensityProfile->PushBack(measurementVector);
155  }
156 }
157 
159 {
161  AccessFixedDimensionByItk_n(image, ComputeIntensityProfile, 3, (path, numSamples, interpolator, intensityProfile));
162  return intensityProfile;
163 }
164 
165 class AddPolyLineElementToPath
166 {
167 public:
168  AddPolyLineElementToPath(const PlaneGeometry* planarFigureGeometry, const BaseGeometry* imageGeometry, itk::PolyLineParametricPath<3>::Pointer path)
169  : m_PlanarFigureGeometry(planarFigureGeometry),
170  m_ImageGeometry(imageGeometry),
171  m_Path(path)
172  {
173  }
174 
175  void operator()(const PlanarFigure::PolyLineElement& polyLineElement)
176  {
177  m_PlanarFigureGeometry->Map(polyLineElement, m_WorldPoint);
178  m_ImageGeometry->WorldToIndex(m_WorldPoint, m_ContinuousIndexPoint);
179  m_Vertex.CastFrom(m_ContinuousIndexPoint);
180  m_Path->AddVertex(m_Vertex);
181  }
182 
183 private:
184  const PlaneGeometry* m_PlanarFigureGeometry;
185  const BaseGeometry* m_ImageGeometry;
187 
188  Point3D m_WorldPoint;
189  Point3D m_ContinuousIndexPoint;
190  itk::PolyLineParametricPath<3>::ContinuousIndexType m_Vertex;
191 };
192 
194 {
196  const PlanarFigure::PolyLineType polyLine = planarFigure->GetPolyLine(0);
197 
198  std::for_each(polyLine.begin(), polyLine.end(),
199  AddPolyLineElementToPath(planarFigure->GetPlaneGeometry(), imageGeometry, path));
200 
201  return path;
202 }
203 
204 static void AddPointToPath(const BaseGeometry* imageGeometry, const Point3D& point, itk::PolyLineParametricPath<3>::Pointer path)
205 {
206  Point3D continuousIndexPoint;
207  imageGeometry->WorldToIndex(point, continuousIndexPoint);
208 
209  itk::PolyLineParametricPath<3>::ContinuousIndexType vertex;
210  vertex.CastFrom(continuousIndexPoint);
211 
212  path->AddVertex(vertex);
213 }
214 
215 static itk::PolyLineParametricPath<3>::Pointer CreatePathFromPoints(BaseGeometry* imageGeometry, const Point3D& startPoint, const Point3D& endPoint)
216 {
218 
219  AddPointToPath(imageGeometry, startPoint, path);
220  AddPointToPath(imageGeometry, endPoint, path);
221 
222  return path;
223 }
224 
226 {
227  return ::ComputeIntensityProfile(image, CreatePathFromPlanarFigure(image->GetGeometry(), planarFigure));
228 }
229 
231 {
232  return ::ComputeIntensityProfile(image, CreatePathFromPlanarFigure(image->GetGeometry(), planarLine.GetPointer()), numSamples, interpolator);
233 }
234 
235 IntensityProfile::Pointer mitk::ComputeIntensityProfile(Image::Pointer image, const Point3D& startPoint, const Point3D& endPoint, unsigned int numSamples, InterpolateImageFunction::Enum interpolator)
236 {
237  return ::ComputeIntensityProfile(image, CreatePathFromPoints(image->GetGeometry(), startPoint, endPoint), numSamples, interpolator);
238 }
239 
240 IntensityProfile::InstanceIdentifier mitk::ComputeGlobalMaximum(IntensityProfile::Pointer intensityProfile, IntensityProfile::MeasurementType &max)
241 {
243  IntensityProfile::InstanceIdentifier maxIndex = 0;
244 
245  IntensityProfile::ConstIterator end = intensityProfile->End();
246  IntensityProfile::MeasurementType measurement;
247 
248  for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it)
249  {
250  measurement = it.GetMeasurementVector()[0];
251 
252  if (measurement > max)
253  {
254  max = measurement;
255  maxIndex = it.GetInstanceIdentifier();
256  }
257  }
258 
259  return maxIndex;
260 }
261 
262 IntensityProfile::InstanceIdentifier mitk::ComputeGlobalMinimum(IntensityProfile::Pointer intensityProfile, IntensityProfile::MeasurementType &min)
263 {
265  IntensityProfile::InstanceIdentifier minIndex = 0;
266 
267  IntensityProfile::ConstIterator end = intensityProfile->End();
268  IntensityProfile::MeasurementType measurement;
269 
270  for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it)
271  {
272  measurement = it.GetMeasurementVector()[0];
273 
274  if (measurement < min)
275  {
276  min = measurement;
277  minIndex = it.GetInstanceIdentifier();
278  }
279  }
280 
281  return minIndex;
282 }
283 
284 IntensityProfile::InstanceIdentifier mitk::ComputeCenterOfMaximumArea(IntensityProfile::Pointer intensityProfile, IntensityProfile::InstanceIdentifier radius)
285 {
286  //const IntensityProfile::MeasurementType min = intensityProfile->GetMeasurementVector(ComputeGlobalMinimum(intensityProfile))[0];
287  IntensityProfile::MeasurementType min;
288  ComputeGlobalMinimum(intensityProfile, min);
289  const IntensityProfile::InstanceIdentifier areaWidth = 1 + 2 * radius;
290 
291  IntensityProfile::MeasurementType maxArea = 0;
292 
293  for (IntensityProfile::InstanceIdentifier i = 0; i < areaWidth; ++i)
294  maxArea += intensityProfile->GetMeasurementVector(i)[0] - min;
295 
296  const IntensityProfile::InstanceIdentifier lastIndex = intensityProfile->Size() - areaWidth;
297  IntensityProfile::InstanceIdentifier centerOfMaxArea = radius;
298  IntensityProfile::MeasurementType area = maxArea;
299 
300  for (IntensityProfile::InstanceIdentifier i = 1; i <= lastIndex; ++i)
301  {
302  area += intensityProfile->GetMeasurementVector(i + areaWidth - 1)[0] - min;
303  area -= intensityProfile->GetMeasurementVector(i - 1)[0] - min;
304 
305  if (area > maxArea)
306  {
307  maxArea = area;
308  centerOfMaxArea = i + radius; // TODO: If multiple areas in the neighborhood have the same intensity chose the middle one instead of the first one.
309  }
310  }
311 
312  return centerOfMaxArea;
313 }
314 
315 std::vector<IntensityProfile::MeasurementType> mitk::CreateVectorFromIntensityProfile(IntensityProfile::Pointer intensityProfile)
316 {
317  std::vector<IntensityProfile::MeasurementType> result;
318  result.reserve(intensityProfile->Size());
319 
320  IntensityProfile::ConstIterator end = intensityProfile->End();
321 
322  for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it)
323  result.push_back(it.GetMeasurementVector()[0]);
324 
325  return result;
326 }
327 
328 IntensityProfile::Pointer mitk::CreateIntensityProfileFromVector(const std::vector<IntensityProfile::MeasurementType>& vector)
329 {
330  const IntensityProfile::InstanceIdentifier size = vector.size();
331 
333  result->Resize(size);
334 
335  for (IntensityProfile::InstanceIdentifier i = 0; i < size; ++i)
336  result->SetMeasurement(i, 0, vector[i]);
337 
338  return result;
339 }
340 
342 {
343  typedef std::vector<IntensityProfile::MeasurementType> StatsVecType;
344 
345  StatsVecType statsVec = mitk::CreateVectorFromIntensityProfile( intensityProfile );
346 
347  IntensityProfile::MeasurementType min;
348  IntensityProfile::MeasurementType max;
349  mitk::ComputeGlobalMinimum( intensityProfile, min );
350  mitk::ComputeGlobalMaximum( intensityProfile, max );
351  StatsVecType::size_type numSamples = statsVec.size();
352 
353  double mean = 0.0;
354  double rms = 0.0;
355  for ( StatsVecType::const_iterator it = statsVec.begin(); it != statsVec.end(); ++it )
356  {
357  double val = *it;
358  mean += val;
359  rms += val*val;
360  }
361  mean /= numSamples;
362  rms /= numSamples;
363 
364  double var = 0.0;
365  for ( StatsVecType::const_iterator it = statsVec.begin(); it != statsVec.end(); ++it )
366  {
367  double diff = *it - mean;
368  var += diff*diff;
369  }
370  var /= ( numSamples - 1 );
371 
372  rms = sqrt( rms );
373 
374  stats->SetMin( static_cast<double>( min ) );
375  stats->SetMax( static_cast<double>( max ) );
376  stats->SetN( numSamples );
377  stats->SetMean( mean );
378  stats->SetVariance( var );
379  stats->SetRMS( rms );
380 }
MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeCenterOfMaximumArea(IntensityProfile::Pointer intensityProfile, IntensityProfile::InstanceIdentifier radius)
Compute center of maximum area under the curve of an intensity profile.
MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeGlobalMaximum(IntensityProfile::Pointer intensityProfile, IntensityProfile::MeasurementType &max)
Compute global maximum of an intensity profile.
itk::SmartPointer< Self > Pointer
Gives locked and index-based read access for a particular image part. The class provides several set-...
const TPixel & GetPixelByIndex(const itk::Index< VDimension > &idx) const
double ScalarType
MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, PlanarFigure::Pointer planarFigure)
Compute intensity profile of an image for each pixel along the first PolyLine of a given planar figur...
#define AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, va_tuple)
Access a mitk-image with known dimension by an itk-image with one or more parameters.
static IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, itk::PolyLineParametricPath< 3 >::Pointer path)
static itk::PolyLineParametricPath< 3 >::Pointer CreatePathFromPlanarFigure(BaseGeometry *imageGeometry, PlanarFigure *planarFigure)
DataCollection - Class to facilitate loading/accessing structured data.
virtual const PlaneGeometry * GetPlaneGeometry() const
Returns (previously set) 2D geometry of this figure.
MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeGlobalMinimum(IntensityProfile::Pointer intensityProfile, IntensityProfile::MeasurementType &min)
Compute global minimum of an intensity profile.
const PolyLineType GetPolyLine(unsigned int index)
Returns the polyline representing the planar figure (for rendering, measurements, etc...
static void AddPointToPath(const BaseGeometry *imageGeometry, const Point3D &point, itk::PolyLineParametricPath< 3 >::Pointer path)
static Vector3D offset
static itk::PolyLineParametricPath< 3 >::Pointer CreatePathFromPoints(BaseGeometry *imageGeometry, const Point3D &startPoint, const Point3D &endPoint)
#define mitkPixelTypeMultiplex3(function, ptype, param1, param2, param3)
MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer CreateIntensityProfileFromVector(const std::vector< IntensityProfile::MeasurementType > &vector)
Convert a standard library vector to an intensity profile.
static T max(T x, T y)
Definition: svm.cpp:70
static T min(T x, T y)
Definition: svm.cpp:67
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const
Convert (continuous or discrete) index coordinates of a vector vec_units to world coordinates (in mm)...
std::vector< PolyLineElement > PolyLineType
MITKIMAGESTATISTICS_EXPORT void ComputeIntensityProfileStatistics(IntensityProfile::Pointer intensityProfile, ImageStatisticsCalculator::StatisticsContainer::Pointer stats)
Compute statistics of an intensity profile.
Describes a two-dimensional, rectangular plane.
static void ReadPixel(const PixelType &, Image::Pointer image, const itk::Index< 3 > &index, ScalarType *returnValue)
static itk::InterpolateImageFunction< TInputImage >::Pointer CreateInterpolateImageFunction(InterpolateImageFunction::Enum interpolator)
MITKIMAGESTATISTICS_EXPORT std::vector< IntensityProfile::MeasurementType > CreateVectorFromIntensityProfile(IntensityProfile::Pointer intensityProfile)
Convert an intensity profile to a standard library vector.
BaseGeometry Describes the geometry of a data object.
Class for defining the data type of pixels.
Definition: mitkPixelType.h:55
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.