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