Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkDicomSR_GantryTiltInformation.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 <mitkDicomSeriesReader.h>
18 
19 namespace mitk
20 {
22  : m_ShiftUp(0.0), m_ShiftRight(0.0), m_ShiftNormal(0.0), m_ITKAssumedSliceSpacing(0.0), m_NumberOfSlicesApart(1)
23  {
24  }
25 
26 #define doublepoint(x) \
27  Point3Dd x; \
28  x[0] = x##f[0]; \
29  x[1] = x##f[1]; \
30  x[2] = x##f[2];
31 
32 #define doublevector(x) \
33  Vector3Dd x; \
34  x[0] = x##f[0]; \
35  x[1] = x##f[1]; \
36  x[2] = x##f[2];
37 
39  const Point3D &origin2f,
40  const Vector3D &rightf,
41  const Vector3D &upf,
42  unsigned int numberOfSlicesApart)
43  : m_ShiftUp(0.0), m_ShiftRight(0.0), m_ShiftNormal(0.0), m_NumberOfSlicesApart(numberOfSlicesApart)
44  {
45  assert(numberOfSlicesApart);
46 
47  doublepoint(origin1);
48  doublepoint(origin2);
49  doublevector(right);
50  doublevector(up);
51 
52  // determine if slice 1 (imagePosition1 and imageOrientation1) and slice 2 can be in one orthogonal slice stack:
53  // calculate a line from origin 1, directed along the normal of slice (calculated as the cross product of
54  // orientation
55  // 1)
56  // check if this line passes through origin 2
57 
58  /*
59  Determine if line (imagePosition2 + l * normal) contains imagePosition1.
60  Done by calculating the distance of imagePosition1 from line (imagePosition2 + l *normal)
61 
62  E.g. http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
63 
64  squared distance = | (pointAlongNormal - origin2) x (origin2 - origin1) | ^ 2
65  /
66  |pointAlongNormal - origin2| ^ 2
67 
68  ( x meaning the cross product )
69  */
70 
71  Vector3Dd normal = itk::CrossProduct(right, up);
72  Point3Dd pointAlongNormal = origin2 + normal;
73 
74  double numerator = itk::CrossProduct(pointAlongNormal - origin2, origin2 - origin1).GetSquaredNorm();
75  double denominator = (pointAlongNormal - origin2).GetSquaredNorm();
76 
77  double distance = sqrt(numerator / denominator);
78 
79  if (distance > 0.001) // mitk::eps is too small; 1/1000 of a mm should be enough to detect tilt
80  {
81  MITK_DEBUG << " Series seems to contain a tilted (or sheared) geometry";
82  MITK_DEBUG << " Distance of expected slice origin from actual slice origin: " << distance;
83  MITK_DEBUG << " ==> storing this shift for later analysis:";
84  MITK_DEBUG << " v right: " << right;
85  MITK_DEBUG << " v up: " << up;
86  MITK_DEBUG << " v normal: " << normal;
87 
88  Point3Dd projectionRight = projectPointOnLine(origin1, origin2, right);
89  Point3Dd projectionNormal = projectPointOnLine(origin1, origin2, normal);
90 
91  m_ShiftRight = (projectionRight - origin2).GetNorm();
92  m_ShiftNormal = (projectionNormal - origin2).GetNorm();
93 
94  /*
95  now also check to which side the image is shifted.
96 
97  Calculation e.g. from
98  http://mathworld.wolfram.com/Point-PlaneDistance.html
99  */
100 
101  Point3Dd testPoint = origin1;
102  Vector3Dd planeNormal = up;
103 
104  double signedDistance =
105  (planeNormal[0] * testPoint[0] + planeNormal[1] * testPoint[1] + planeNormal[2] * testPoint[2] -
106  (planeNormal[0] * origin2[0] + planeNormal[1] * origin2[1] + planeNormal[2] * origin2[2])) /
107  sqrt(planeNormal[0] * planeNormal[0] + planeNormal[1] * planeNormal[1] + planeNormal[2] * planeNormal[2]);
108 
109  m_ShiftUp = signedDistance;
110 
111  m_ITKAssumedSliceSpacing = (origin2 - origin1).GetNorm();
112  // How do we now this is assumed? See header documentation for ITK code references
113  // double itkAssumedSliceSpacing = sqrt( m_ShiftUp * m_ShiftUp + m_ShiftNormal * m_ShiftNormal );
114 
115  MITK_DEBUG << " shift normal: " << m_ShiftNormal;
116  MITK_DEBUG << " shift normal assumed by ITK: " << m_ITKAssumedSliceSpacing;
117  MITK_DEBUG << " shift up: " << m_ShiftUp;
118  MITK_DEBUG << " shift right: " << m_ShiftRight;
119 
120  MITK_DEBUG << " tilt angle (deg): " << atan(m_ShiftUp / m_ShiftNormal) * 180.0 / 3.1415926535;
121  }
122  }
123 
125  Point3Dd lineOrigin,
126  Vector3Dd lineDirection)
127  {
134  Vector3Dd lineOriginToP = p - lineOrigin;
135  double innerProduct = lineOriginToP * lineDirection;
136 
137  double factor = innerProduct / lineDirection.GetSquaredNorm();
138  Point3Dd projection = lineOrigin + factor * lineDirection;
139 
140  return projection;
141  }
142 
145  {
146  return atan(fabs(m_ShiftUp) / m_ShiftNormal) * 180.0 / 3.1415926535;
147  }
148 
150  {
151  // so many mm need to be shifted per slice!
152  return m_ShiftUp / static_cast<double>(m_NumberOfSlicesApart);
153  }
154 
156  {
157  return m_ShiftNormal / static_cast<double>(m_NumberOfSlicesApart);
158  }
159 
161  {
162  return (fabs(m_ShiftRight) > 0.001 || fabs(m_ShiftUp) > 0.001);
163  }
164 
166  {
167  return (fabs(m_ShiftRight) < 0.001 && fabs(m_ShiftUp) > 0.001);
168  }
169 
170 } // end namespace mitk
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
#define doublepoint(x)
double GetMatrixCoefficientForCorrectionInWorldCoordinates() const
The offset distance in Y direction for each slice in mm (describes the tilt result).
bool IsSheared() const
Whether the slices were sheared.
Point3D projectPointOnLine(Point3Dd p, Point3Dd lineOrigin, Vector3Dd lineDirection)
Projection of point p onto line through lineOrigin in direction of lineDirection. ...
#define doublevector(x)
double GetTiltCorrectedAdditionalSize() const
The shift between first and last slice in mm.
double GetTiltAngleInDegrees() const
Calculated tilt angle in degrees.
double GetRealZSpacing() const
The z / inter-slice spacing. Needed to correct ImageSeriesReader's result.
GantryTiltInformation()
Just so we can create empty instances for assigning results later.
bool IsRegularGantryTilt() const
Whether the shearing is a gantry tilt or more complicated.