Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.