Mercurial > hg > orthanc-stone
diff Framework/Toolbox/OrthancSlicesLoader.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/OrthancSlicesLoader.cpp Mon Sep 25 13:43:47 2017 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.cpp Thu Sep 28 16:55:51 2017 +0200 @@ -27,6 +27,7 @@ #include <Core/Images/ImageProcessing.h> #include <Core/Images/JpegReader.h> #include <Core/Images/PngReader.h> +#include <Core/Compression/GzipCompressor.h> #include <Core/Logging.h> #include <Core/OrthancException.h> #include <Core/Toolbox.h> @@ -96,25 +97,29 @@ unsigned int GetSliceIndex() const { - assert(mode_ == Mode_LoadImage); + assert(mode_ == Mode_LoadImage || + mode_ == Mode_LoadRawImage); return sliceIndex_; } const Slice& GetSlice() const { - assert(mode_ == Mode_LoadImage && slice_ != NULL); + assert(mode_ == Mode_LoadImage || + mode_ == Mode_LoadRawImage); + assert(slice_ != NULL); return *slice_; } unsigned int GetFrame() const { - assert(mode_ == Mode_InstanceGeometry); + assert(mode_ == Mode_FrameGeometry); return frame_; } const std::string& GetInstanceId() const { - assert(mode_ == Mode_InstanceGeometry); + assert(mode_ == Mode_FrameGeometry || + mode_ == Mode_InstanceGeometry); return instanceId_; } @@ -123,11 +128,18 @@ return new Operation(Mode_SeriesGeometry); } - static Operation* DownloadInstanceGeometry(const std::string& instanceId, - unsigned int frame) + static Operation* DownloadInstanceGeometry(const std::string& instanceId) { std::auto_ptr<Operation> operation(new Operation(Mode_InstanceGeometry)); operation->instanceId_ = instanceId; + return operation.release(); + } + + static Operation* DownloadFrameGeometry(const std::string& instanceId, + unsigned int frame) + { + std::auto_ptr<Operation> operation(new Operation(Mode_FrameGeometry)); + operation->instanceId_ = instanceId; operation->frame_ = frame; return operation.release(); } @@ -142,6 +154,15 @@ tmp->quality_ = quality; return tmp.release(); } + + static Operation* DownloadSliceRawImage(unsigned int sliceIndex, + const Slice& slice) + { + std::auto_ptr<Operation> tmp(new Operation(Mode_LoadRawImage)); + tmp->sliceIndex_ = sliceIndex; + tmp->slice_ = &slice; + return tmp.release(); + } }; @@ -170,8 +191,12 @@ break; case Mode_InstanceGeometry: - that_.ParseInstanceGeometry(operation->GetInstanceId(), - operation->GetFrame(), answer, answerSize); + that_.ParseInstanceGeometry(operation->GetInstanceId(), answer, answerSize); + break; + + case Mode_FrameGeometry: + that_.ParseFrameGeometry(operation->GetInstanceId(), + operation->GetFrame(), answer, answerSize); break; case Mode_LoadImage: @@ -193,6 +218,10 @@ break; + case Mode_LoadRawImage: + that_.ParseSliceRawImage(*operation, answer, answerSize); + break; + default: throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } @@ -206,7 +235,7 @@ switch (operation->GetMode()) { - case Mode_InstanceGeometry: + case Mode_FrameGeometry: case Mode_SeriesGeometry: that_.userCallback_.NotifyGeometryError(that_); that_.state_ = State_Error; @@ -266,15 +295,25 @@ for (size_t i = 0; i < instances.size(); i++) { OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]); + OrthancPlugins::DicomDatasetReader reader(dataset); + + unsigned int frames; + if (!reader.GetUnsignedIntegerValue(frames, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frames = 1; + } - Slice slice; - if (slice.ParseOrthancFrame(dataset, instances[i], 0 /* todo */)) + for (unsigned int frame = 0; frame < frames; frame++) { - slices_.AddSlice(slice); - } - else - { - LOG(WARNING) << "Skipping invalid instance " << instances[i]; + Slice slice; + if (slice.ParseOrthancFrame(dataset, instances[i], frame)) + { + slices_.AddSlice(slice); + } + else + { + LOG(WARNING) << "Skipping invalid frame " << frame << " within instance " << instances[i]; + } } } @@ -308,7 +347,6 @@ void OrthancSlicesLoader::ParseInstanceGeometry(const std::string& instanceId, - unsigned int frame, const void* answer, size_t size) { @@ -321,6 +359,51 @@ } OrthancPlugins::FullOrthancDataset dataset(tags); + OrthancPlugins::DicomDatasetReader reader(dataset); + + unsigned int frames; + if (!reader.GetUnsignedIntegerValue(frames, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frames = 1; + } + + LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)"; + + state_ = State_GeometryReady; + + for (unsigned int frame = 0; frame < frames; frame++) + { + Slice slice; + if (slice.ParseOrthancFrame(dataset, instanceId, frame)) + { + slices_.AddSlice(slice); + } + else + { + LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; + userCallback_.NotifyGeometryError(*this); + return; + } + } + + userCallback_.NotifyGeometryReady(*this); + } + + + void OrthancSlicesLoader::ParseFrameGeometry(const std::string& instanceId, + unsigned int frame, + const void* answer, + size_t size) + { + Json::Value tags; + if (!MessagingToolbox::ParseJson(tags, answer, size) || + tags.type() != Json::objectValue) + { + userCallback_.NotifyGeometryError(*this); + return; + } + + OrthancPlugins::FullOrthancDataset dataset(tags); state_ = State_GeometryReady; @@ -526,6 +609,19 @@ } + void OrthancSlicesLoader::ParseSliceRawImage(const Operation& operation, + const void* answer, + size_t size) + { + Orthanc::GzipCompressor compressor; + + std::string raw; + compressor.Uncompress(raw, answer, size); + + printf("[%d => %d]\n", size, raw.size()); + } + + OrthancSlicesLoader::OrthancSlicesLoader(ICallback& callback, IWebService& orthanc) : webCallback_(new WebCallback(*this)), @@ -551,8 +647,27 @@ } - void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId, - unsigned int frame) + void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId) + { + if (state_ != State_Initialization) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + state_ = State_LoadingGeometry; + + // Tag "3004-000c" is "Grid Frame Offset Vector", which is + // mandatory to read RT DOSE, but is too long to be returned by default + std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3004-000c"; + orthanc_.ScheduleGetRequest + (*webCallback_, uri, Operation::DownloadInstanceGeometry(instanceId)); + } + } + + + void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId, + unsigned int frame) { if (state_ != State_Initialization) { @@ -563,7 +678,7 @@ state_ = State_LoadingGeometry; std::string uri = "/instances/" + instanceId + "/tags"; orthanc_.ScheduleGetRequest - (*webCallback_, uri, Operation::DownloadInstanceGeometry(instanceId, frame)); + (*webCallback_, uri, Operation::DownloadFrameGeometry(instanceId, frame)); } } @@ -608,10 +723,9 @@ } - void OrthancSlicesLoader::ScheduleSliceImagePng(size_t index) + void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice, + size_t index) { - const Slice& slice = GetSlice(index); - std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + boost::lexical_cast<std::string>(slice.GetFrame())); @@ -638,7 +752,8 @@ } - void OrthancSlicesLoader::ScheduleSliceImageJpeg(size_t index, + void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice, + size_t index, SliceImageQuality quality) { unsigned int value; @@ -662,7 +777,6 @@ } // This requires the official Web viewer plugin to be installed! - const Slice& slice = GetSlice(index); std::string uri = ("/web-viewer/instances/jpeg" + boost::lexical_cast<std::string>(value) + "-" + slice.GetOrthancInstanceId() + "_" + @@ -673,6 +787,7 @@ } + void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index, SliceImageQuality quality) { @@ -681,13 +796,25 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - if (quality == SliceImageQuality_Full) + const Slice& slice = GetSlice(index); + + if (slice.HasOrthancDecoding()) { - ScheduleSliceImagePng(index); + if (quality == SliceImageQuality_Full) + { + ScheduleSliceImagePng(slice, index); + } + else + { + ScheduleSliceImageJpeg(slice, index, quality); + } } else { - ScheduleSliceImageJpeg(index, quality); + std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + + boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz"); + orthanc_.ScheduleGetRequest(*webCallback_, uri, + Operation::DownloadSliceRawImage(index, slice)); } } }