double mitk::SortByImagePositionPatient ::InternalNumericDistance(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right, bool& possible) const { // sort by distance to world origin, assuming (almost) equal orientation static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient) static const DICOMTag tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation Vector3D leftRight; leftRight.Fill(0.0); Vector3D leftUp; leftUp.Fill(0.0); bool leftHasOrientation(false); DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ).value, leftRight, leftUp, leftHasOrientation ); Vector3D rightRight; rightRight.Fill(0.0); Vector3D rightUp; rightUp.Fill(0.0); bool rightHasOrientation(false); DICOMStringToOrientationVectors(right->GetTagValueAsString(tagImageOrientation).value, rightRight, rightUp, rightHasOrientation ); Point3D leftOrigin; leftOrigin.Fill(0.0f); bool leftHasOrigin(false); leftOrigin = DICOMStringToPoint3D(left->GetTagValueAsString(tagImagePositionPatient).value, leftHasOrigin); Point3D rightOrigin; rightOrigin.Fill(0.0f); bool rightHasOrigin(false); rightOrigin = DICOMStringToPoint3D(right->GetTagValueAsString(tagImagePositionPatient).value, rightHasOrigin); // we tolerate very small differences in image orientation, since we got to know about // acquisitions where these values change across a single series (7th decimal digit) // (http://bugs.mitk.org/show_bug.cgi?id=12263) // still, we want to check if our assumption of 'almost equal' orientations is valid for (unsigned int dim = 0; dim < 3; ++dim) { if ( fabs(leftRight[dim] - rightRight[dim]) > 0.0001 || fabs(leftUp[dim] - rightUp[dim]) > 0.0001) { MITK_ERROR << "Dicom images have different orientations."; throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images."); } } Vector3D normal; normal[0] = leftRight[1] * leftUp[2] - leftRight[2] * leftUp[1]; normal[1] = leftRight[2] * leftUp[0] - leftRight[0] * leftUp[2]; normal[2] = leftRight[0] * leftUp[1] - leftRight[1] * leftUp[0]; double leftDistance = 0.0; double rightDistance = 0.0; // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes for (unsigned int dim = 0; dim < 3; ++dim) { leftDistance += normal[dim] * leftOrigin[dim]; rightDistance += normal[dim] * rightOrigin[dim]; } // if we can sort by just comparing the distance, we do exactly that if ( fabs(leftDistance - rightDistance) >= mitk::eps) { possible = true; // default: compare position return rightDistance - leftDistance; // if (left < right> ==> diff > 0 } else { possible = false; return 0.0; } }
void mitk::NormalDirectionConsistencySorter ::Sort() { DICOMDatasetList datasets = GetInput(); if (datasets.size() > 1) { // at some point in the code, there is the expectation that // the direction of the slice normals is the same as the direction between // first and last slice origin. We need to make this sure here, because // we want to feed the files into itk::ImageSeriesReader with the consistent // setting of ReverseOrderOff. static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient) static const DICOMTag tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation DICOMDatasetAccess* firstDS = datasets.front(); DICOMDatasetAccess* lastDS = datasets.back(); // make sure here that the direction from slice to slice is the direction of // image normals... std::string imageOrientationString = firstDS->GetTagValueAsString( tagImageOrientation ); std::string imagePositionPatientFirst = firstDS->GetTagValueAsString( tagImagePositionPatient ); std::string imagePositionPatientLast = lastDS->GetTagValueAsString( tagImagePositionPatient ); Vector3D right; right.Fill(0.0); Vector3D up; up.Fill(0.0); bool hasOrientation(false); DICOMStringToOrientationVectors( imageOrientationString, right, up, hasOrientation ); Point3D firstOrigin; firstOrigin.Fill(0.0f); bool firstHasOrigin(false); firstOrigin = DICOMStringToPoint3D( imagePositionPatientFirst, firstHasOrigin ); Point3D lastOrigin; lastOrigin.Fill(0.0f); bool lastHasOrigin(false); lastOrigin = DICOMStringToPoint3D( imagePositionPatientLast, lastHasOrigin ); Vector3D normal; normal[0] = right[1] * up[2] - right[2] * up[1]; normal[1] = right[2] * up[0] - right[0] * up[2]; normal[2] = right[0] * up[1] - right[1] * up[0]; normal.Normalize(); Vector3D directionOfSlices; directionOfSlices = lastOrigin - firstOrigin; directionOfSlices.Normalize(); double projection = normal * directionOfSlices; MITK_DEBUG << "Making sense of \norientation '" << imageOrientationString << "'\nfirst position '" << imagePositionPatientFirst << "'\nlast position '" << imagePositionPatientLast << "'"; MITK_DEBUG << "Normal: " << normal; MITK_DEBUG << "Direction of slices: " << directionOfSlices; MITK_DEBUG << "Projection of direction onto slice normal: " << projection; if ( projection < 0.0 ) { MITK_DEBUG << "Need to reverse filenames"; std::reverse( datasets.begin(), datasets.end() ); m_TiltInfo = GantryTiltInformation::MakeFromTagValues( imagePositionPatientLast, imagePositionPatientFirst, imageOrientationString, datasets.size() - 1 ); } else { m_TiltInfo = GantryTiltInformation::MakeFromTagValues( imagePositionPatientFirst, imagePositionPatientLast, imageOrientationString, datasets.size() - 1 ); } } else // just ONE dataset, do not forget to reset tilt information { m_TiltInfo = GantryTiltInformation(); // empty info } this->SetNumberOfOutputs(1); this->SetOutput(0, datasets); }