# HG changeset patch # User Sebastien Jodogne # Date 1604944148 -3600 # Node ID 960bb5fcc4406f7779e13e23c251c29d30869b7a # Parent 78509230f0d7fe7e97e0bbea692dd577c655b72c SortedFrames::GetFrameGeometry() diff -r 78509230f0d7 -r 960bb5fcc440 OrthancStone/Sources/Toolbox/SortedFrames.cpp --- a/OrthancStone/Sources/Toolbox/SortedFrames.cpp Mon Nov 09 18:01:32 2020 +0100 +++ b/OrthancStone/Sources/Toolbox/SortedFrames.cpp Mon Nov 09 18:49:08 2020 +0100 @@ -24,6 +24,7 @@ #include "GeometryToolbox.h" +#include #include #include @@ -40,7 +41,8 @@ } uint32_t tmp; - if (tags.ParseUnsignedInteger32(tmp, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) + if (tags.ParseUnsignedInteger32(tmp, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES) && + tmp > 0) { numberOfFrames_ = tmp; } @@ -59,9 +61,68 @@ { monochrome1_ = false; } + + bool ok = false; + + if (numberOfFrames_ > 1) + { + std::string offsets, increment; + if (tags.LookupStringValue(offsets, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, false) && + tags.LookupStringValue(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false)) + { + Orthanc::Toolbox::ToUpperCase(increment); + if (increment != "3004,000C") + { + LOG(WARNING) << "Bad value for the FrameIncrementPointer tags in a multiframe image"; + } + else if (LinearAlgebra::ParseVector(frameOffsets_, offsets)) + { + if (frameOffsets_.size() == numberOfFrames_) + { + ok = true; + } + else + { + LOG(WARNING) << "The size of the GridFrameOffsetVector does not correspond to the number of frames"; + } + } + else + { + LOG(WARNING) << "Cannot parse the GridFrameOffsetVector tag"; + } + } + else + { + LOG(INFO) << "Missing the frame offset information in a multiframe image"; + } + } + + if (!ok) + { + frameOffsets_.resize(numberOfFrames_); + for (size_t i = 0; i < numberOfFrames_; i++) + { + frameOffsets_[i] = 0; + } + } } + double SortedFrames::Instance::GetFrameOffset(unsigned int frame) const + { + assert(GetNumberOfFrames() == frameOffsets_.size()); + + if (frame >= GetNumberOfFrames()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else + { + return frameOffsets_[frame]; + } + } + + SortedFrames::Frame::Frame(const Instance& instance, unsigned int frameNumber) : instance_(&instance), @@ -364,6 +425,24 @@ } + CoordinateSystem3D SortedFrames::GetFrameGeometry(size_t frameIndex) const + { + const Frame& frame = GetFrame(frameIndex); + CoordinateSystem3D geometry = frame.GetInstance().GetGeometry(); + + if (geometry.IsValid()) + { + geometry.SetOrigin(geometry.GetOrigin() + geometry.GetNormal() * + frame.GetInstance().GetFrameOffset(frame.GetFrameNumberInInstance())); + return geometry; + } + else + { + return geometry; + } + } + + bool SortedFrames::LookupFrame(size_t& frameIndex, const std::string& sopInstanceUid, unsigned int frameNumber) const diff -r 78509230f0d7 -r 960bb5fcc440 OrthancStone/Sources/Toolbox/SortedFrames.h --- a/OrthancStone/Sources/Toolbox/SortedFrames.h Mon Nov 09 18:01:32 2020 +0100 +++ b/OrthancStone/Sources/Toolbox/SortedFrames.h Mon Nov 09 18:49:08 2020 +0100 @@ -38,6 +38,7 @@ unsigned int numberOfFrames_; CoordinateSystem3D geometry_; bool monochrome1_; + Vector frameOffsets_; public: explicit Instance(const Orthanc::DicomMap& tags); @@ -66,6 +67,8 @@ { return monochrome1_; } + + double GetFrameOffset(unsigned int frame) const; }; struct Frame @@ -199,6 +202,8 @@ return GetFrame(frameIndex).GetInstance().IsMonochrome1(); } + CoordinateSystem3D GetFrameGeometry(size_t frameIndex) const; + bool LookupFrame(size_t& frameIndex, const std::string& sopInstanceUid, unsigned int frameNumber) const; diff -r 78509230f0d7 -r 960bb5fcc440 UnitTestsSources/SortedFramesTests.cpp --- a/UnitTestsSources/SortedFramesTests.cpp Mon Nov 09 18:01:32 2020 +0100 +++ b/UnitTestsSources/SortedFramesTests.cpp Mon Nov 09 18:49:08 2020 +0100 @@ -245,6 +245,47 @@ } +TEST(SortedFrames, FrameOffset) +{ + Orthanc::DicomMap tags; + tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false); + tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false); + tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "1.2.276.0.7230010.3.1.4.296485376.1.1568899779.944133", false); + tags.SetValue(Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, "-350\\-145\\-985", false); + tags.SetValue(Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "1\\0\\0\\0\\1\\0", false); + tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "2", false); + + for (unsigned int i = 0; i < 3; i++) + { + tags.SetValue(Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, i != 1 ? "3004,000c" : "nope", false); + tags.SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, i != 2 ? "8\\11" : "1\\2\\3", false); + + OrthancStone::SortedFrames f; + f.AddInstance(tags); + f.Sort(); + + ASSERT_EQ(2u, f.GetFramesCount()); + ASSERT_TRUE(f.GetFrameGeometry(0).IsValid()); + ASSERT_TRUE(f.GetFrameGeometry(1).IsValid()); + ASSERT_FLOAT_EQ(-350.0f, f.GetFrameGeometry(0).GetOrigin() [0]); + ASSERT_FLOAT_EQ(-145.0f, f.GetFrameGeometry(0).GetOrigin() [1]); + ASSERT_FLOAT_EQ(-350.0f, f.GetFrameGeometry(1).GetOrigin() [0]); + ASSERT_FLOAT_EQ(-145.0f, f.GetFrameGeometry(1).GetOrigin() [1]); + + if (i == 0) + { + ASSERT_FLOAT_EQ(-985.0f + 8.0f, f.GetFrameGeometry(0).GetOrigin() [2]); + ASSERT_FLOAT_EQ(-985.0f + 11.0f, f.GetFrameGeometry(1).GetOrigin() [2]); + } + else + { + ASSERT_FLOAT_EQ(-985.0f, f.GetFrameGeometry(0).GetOrigin() [2]); + ASSERT_FLOAT_EQ(-985.0f, f.GetFrameGeometry(1).GetOrigin() [2]); + } + } +} + + TEST(SortedFrames, Knix) // Created using "SortedFramesCreateTest.py" { Orthanc::DicomMap tags;