Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkSortByImagePositionPatient.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 #include "mitkDICOMTag.h"
15 
17 ::SortByImagePositionPatient(DICOMSortCriterion::Pointer secondaryCriterion)
18 :DICOMSortCriterion(secondaryCriterion)
19 {
20 }
21 
24 {
25 }
26 
29 :DICOMSortCriterion(other)
30 {
31 }
32 
36 {
37  if (this != &other)
38  {
40  }
41  return *this;
42 }
43 
44 bool
46 ::operator==(const DICOMSortCriterion& other) const
47 {
48  return dynamic_cast<const SortByImagePositionPatient*>(&other) != nullptr; // same class
49 }
50 
51 void
53 ::Print(std::ostream& os) const
54 {
55  os << "(0020,0032) Image Position (Patient) along normal of (0020,0037) Image Orientation (Patient)";
56 }
57 
61 {
62  DICOMTagList tags;
63  tags.push_back( DICOMTag(0x0020, 0x0032) ); // ImagePositionPatient
64  tags.push_back( DICOMTag(0x0020, 0x0037) ); // ImageOrientationPatient
65 
66  return tags;
67 }
68 
69 bool
72 {
73  bool possible(false);
74  double distance = InternalNumericDistance(left, right, possible); // returns 0.0 if not possible
75  if (possible)
76  {
77  return distance > 0.0;
78  }
79  else
80  {
81  return this->NextLevelIsLeftBeforeRight(left, right);
82  }
83 }
84 
85 double
88 {
89  // sort by distance to world origin, assuming (almost) equal orientation
90  static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
91  static const DICOMTag tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation
92 
93  Vector3D leftRight; leftRight.Fill(0.0);
94  Vector3D leftUp; leftUp.Fill(0.0);
95  bool leftHasOrientation(false);
96  DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ).value,
97  leftRight, leftUp, leftHasOrientation );
98 
99  Vector3D rightRight; rightRight.Fill(0.0);
100  Vector3D rightUp; rightUp.Fill(0.0);
101  bool rightHasOrientation(false);
102  DICOMStringToOrientationVectors(right->GetTagValueAsString(tagImageOrientation).value,
103  rightRight, rightUp, rightHasOrientation );
104 
105  Point3D leftOrigin; leftOrigin.Fill(0.0f);
106  bool leftHasOrigin(false);
107  leftOrigin = DICOMStringToPoint3D(left->GetTagValueAsString(tagImagePositionPatient).value, leftHasOrigin);
108 
109  Point3D rightOrigin; rightOrigin.Fill(0.0f);
110  bool rightHasOrigin(false);
111  rightOrigin = DICOMStringToPoint3D(right->GetTagValueAsString(tagImagePositionPatient).value, rightHasOrigin);
112 
113  // we tolerate very small differences in image orientation, since we got to know about
114  // acquisitions where these values change across a single series (7th decimal digit)
115  // (http://bugs.mitk.org/show_bug.cgi?id=12263)
116  // still, we want to check if our assumption of 'almost equal' orientations is valid
117  for (unsigned int dim = 0; dim < 3; ++dim)
118  {
119  if ( fabs(leftRight[dim] - rightRight[dim]) > 0.0001
120  || fabs(leftUp[dim] - rightUp[dim]) > 0.0001)
121  {
122  MITK_ERROR << "Dicom images have different orientations.";
123  throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images.");
124  }
125  }
126 
127  Vector3D normal;
128  normal[0] = leftRight[1] * leftUp[2] - leftRight[2] * leftUp[1];
129  normal[1] = leftRight[2] * leftUp[0] - leftRight[0] * leftUp[2];
130  normal[2] = leftRight[0] * leftUp[1] - leftRight[1] * leftUp[0];
131 
132  double leftDistance = 0.0;
133  double rightDistance = 0.0;
134 
135  // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes
136  for (unsigned int dim = 0; dim < 3; ++dim)
137  {
138  leftDistance += normal[dim] * leftOrigin[dim];
139  rightDistance += normal[dim] * rightOrigin[dim];
140  }
141 
142  // if we can sort by just comparing the distance, we do exactly that
143  if ( fabs(leftDistance - rightDistance) >= mitk::eps)
144  {
145  possible = true;
146  // default: compare position
147  return rightDistance - leftDistance; // if (left < right> ==> diff > 0
148  }
149  else
150  {
151  possible = false;
152  return 0.0;
153  }
154 }
155 
156 
157 double
160 {
161  bool possible(false);
162  double retVal = InternalNumericDistance(from, to, possible); // returns 0.0 if not possible
163  return possible ? retVal : 0.0;
164 }
bool operator==(const DICOMSortCriterion &other) const override
#define MITK_ERROR
Definition: mitkLogMacros.h:20
std::vector< DICOMTag > DICOMTagList
Definition: mitkDICOMTag.h:59
void DICOMStringToOrientationVectors(const std::string &s, Vector3D &right, Vector3D &up, bool &successful)
Convert DICOM string describing a point two Vector3D.
Representation of a DICOM tag.
Definition: mitkDICOMTag.h:32
use the deprecated old MITK testing style If possible
Sort by distance of image origin along image normal (for use in DICOMTagBasedSorter).
DICOMSortCriterion & operator=(const DICOMSortCriterion &other)
SortByImagePositionPatient(DICOMSortCriterion::Pointer secondaryCriterion=nullptr)
Interface to datasets that is presented to sorting classes such as DICOMDatasetSorter.
void Print(std::ostream &os) const override
brief describe this class in given stream.
bool NextLevelIsLeftBeforeRight(const mitk::DICOMDatasetAccess *left, const mitk::DICOMDatasetAccess *right) const
virtual DICOMDatasetFinding GetTagValueAsString(const DICOMTag &tag) const =0
Return a DICOMDatasetFinding instance of the tag. The return containes (if valid) the raw value of th...
DICOMTagList GetTagsOfInterest() const override
Tags used for comparison.
double NumericDistance(const mitk::DICOMDatasetAccess *from, const mitk::DICOMDatasetAccess *to) const override
Calculate a distance between two datasets. This ansers the question of consecutive datasets...
A tag based sorting criterion for use in DICOMTagBasedSorter.
MITKCORE_EXPORT const ScalarType eps
double InternalNumericDistance(const mitk::DICOMDatasetAccess *from, const mitk::DICOMDatasetAccess *to, bool &possible) const
Point3D DICOMStringToPoint3D(const std::string &s, bool &successful)
Convert DICOM string describing a point to Point3D.
SortByImagePositionPatient & operator=(const SortByImagePositionPatient &other)
bool IsLeftBeforeRight(const mitk::DICOMDatasetAccess *left, const mitk::DICOMDatasetAccess *right) const override
Answer the sorting question.