Mercurial > hg > orthanc-stone
diff Framework/Toolbox/Slice.cpp @ 117:42c05a3baee3 wasm
loading multi-frame instances as 3D volumes
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 28 Sep 2017 16:55:51 +0200 |
parents | 2eca030792aa |
children | a4d0b6c82b29 |
line wrap: on
line diff
--- a/Framework/Toolbox/Slice.cpp Mon Sep 25 13:43:47 2017 +0200 +++ b/Framework/Toolbox/Slice.cpp Thu Sep 28 16:55:51 2017 +0200 @@ -21,32 +21,135 @@ #include "Slice.h" +#include "../Enumerations.h" + +#include <Core/Logging.h> #include <Core/OrthancException.h> +#include <Core/Toolbox.h> + +#include <boost/lexical_cast.hpp> namespace OrthancStone { + static bool ParseDouble(double& target, + const std::string& source) + { + try + { + target = boost::lexical_cast<double>(source); + return true; + } + catch (boost::bad_lexical_cast&) + { + return false; + } + } + + bool Slice::ComputeRTDoseGeometry(const OrthancPlugins::DicomDatasetReader& reader, + unsigned int frame) + { + // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html + static const OrthancPlugins::DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c); + static const OrthancPlugins::DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009); + + std::string increment = reader.GetStringValue(DICOM_TAG_FRAME_INCREMENT_POINTER, ""); + std::string offsetTag; + + bool ok = reader.GetDataset().GetStringValue(offsetTag, DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); + if (!ok) + { + LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1"; + return false; + } + + Orthanc::Toolbox::ToUpperCase(increment); + if (increment != "3004,000C" || + offsetTag.empty()) + { + return false; + } + + std::vector<std::string> offsets; + Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\'); + + if (frameCount_ == 0 || + offsets.size() != frameCount_ || + frame >= frameCount_) + { + LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE"; + return false; + } + + double offset0, z; + + if (!ParseDouble(offset0, offsets[0]) || + !ParseDouble(z, offsets[frame])) + { + LOG(ERROR) << "Invalid syntax"; + return false; + } + + if (!GeometryToolbox::IsCloseToZero(offset0)) + { + LOG(ERROR) << "Invalid syntax"; + return false; + } + + geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(), + geometry_.GetAxisX(), + geometry_.GetAxisY()); + + return true; + } + + bool Slice::ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset, const std::string& instanceId, unsigned int frame) { + orthancInstanceId_ = instanceId; + frame_ = frame; + type_ = Type_OrthancDecodableFrame; + OrthancPlugins::DicomDatasetReader reader(dataset); - unsigned int frameCount; - if (!reader.GetUnsignedIntegerValue(frameCount, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) + sopClassUid_ = reader.GetStringValue(OrthancPlugins::DICOM_TAG_SOP_CLASS_UID, ""); + if (sopClassUid_.empty()) { - frameCount = 1; // Assume instance with one frame + LOG(ERROR) << "Instance without a SOP class UID"; + return false; + } + + if (!reader.GetUnsignedIntegerValue(frameCount_, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frameCount_ = 1; // Assume instance with one frame } - if (frame >= frameCount) + if (frame >= frameCount_) { return false; } - if (!reader.GetDoubleValue(thickness_, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) + if (!reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) || + !reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS)) { - thickness_ = 100.0 * std::numeric_limits<double>::epsilon(); + return false; } + thickness_ = 100.0 * std::numeric_limits<double>::epsilon(); + + std::string tmp; + if (dataset.GetStringValue(tmp, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) + { + if (!tmp.empty() && + !ParseDouble(thickness_, tmp)) + { + return false; // Syntax error + } + } + + converter_.ReadParameters(dataset); + GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset); std::string position, orientation; @@ -54,33 +157,47 @@ dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT)) { geometry_ = CoordinateSystem3D(position, orientation); + + bool ok = true; + SopClassUid tmp; + + if (StringToSopClassUid(tmp, sopClassUid_)) + { + switch (tmp) + { + case SopClassUid_RTDose: + type_ = Type_OrthancRawFrame; + ok = ComputeRTDoseGeometry(reader, frame); + break; + + default: + break; + } + } + + if (!ok) + { + LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame + << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_; + return false; + } } - - if (reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) && - reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS)) - { - orthancInstanceId_ = instanceId; - frame_ = frame; - converter_.ReadParameters(dataset); - type_ = Type_OrthancInstance; - return true; - } - else - { - return false; - } + return true; } const std::string Slice::GetOrthancInstanceId() const { - if (type_ != Type_OrthancInstance) + if (type_ == Type_OrthancDecodableFrame || + type_ == Type_OrthancRawFrame) + { + return orthancInstanceId_; + } + else { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return orthancInstanceId_; + } }