# HG changeset patch # User Sebastien Jodogne # Date 1402482182 -7200 # Node ID 87791ebc1f50c278c49862db7255cf6c3fc08aa1 # Parent fc34356283e17432848ce82de1698b7104fb4489 download matlab images diff -r fc34356283e1 -r 87791ebc1f50 Core/ChunkedBuffer.cpp --- a/Core/ChunkedBuffer.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/Core/ChunkedBuffer.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -65,6 +65,15 @@ } + void ChunkedBuffer::AddChunk(const std::string& chunk) + { + if (chunk.size() > 0) + { + AddChunk(&chunk[0], chunk.size()); + } + } + + void ChunkedBuffer::Flatten(std::string& result) { result.resize(numBytes_); diff -r fc34356283e1 -r 87791ebc1f50 Core/ChunkedBuffer.h --- a/Core/ChunkedBuffer.h Wed Jun 11 09:18:07 2014 +0200 +++ b/Core/ChunkedBuffer.h Wed Jun 11 12:23:02 2014 +0200 @@ -64,6 +64,8 @@ void AddChunk(const char* chunkData, size_t chunkSize); + void AddChunk(const std::string& chunk); + void Flatten(std::string& result); }; } diff -r fc34356283e1 -r 87791ebc1f50 Core/ImageFormats/ImageAccessor.cpp --- a/Core/ImageFormats/ImageAccessor.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/Core/ImageFormats/ImageAccessor.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -34,13 +34,72 @@ #include "ImageAccessor.h" #include "../OrthancException.h" +#include "../ChunkedBuffer.h" #include #include #include +#include namespace Orthanc { + template + static void ToMatlabStringInternal(ChunkedBuffer& target, + const ImageAccessor& source) + { + target.AddChunk("double([ "); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const PixelType* p = reinterpret_cast(source.GetConstRow(y)); + + std::string s; + if (y > 0) + { + s = "; "; + } + + s.reserve(source.GetWidth() * 8); + + for (unsigned int x = 0; x < source.GetWidth(); x++, p++) + { + s += boost::lexical_cast(static_cast(*p)) + " "; + } + + target.AddChunk(s); + } + + target.AddChunk("])"); + } + + + static void RGB24ToMatlabString(ChunkedBuffer& target, + const ImageAccessor& source) + { + assert(source.GetFormat() == PixelFormat_RGB24); + + target.AddChunk("double(permute(reshape([ "); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); + + std::string s; + s.reserve(source.GetWidth() * 3 * 8); + + for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++) + { + s += boost::lexical_cast(static_cast(*p)) + " "; + } + + target.AddChunk(s); + } + + target.AddChunk("], [ 3 " + boost::lexical_cast(source.GetHeight()) + + " " + boost::lexical_cast(source.GetWidth()) + " ]), [ 3 2 1 ]))"); + } + + void* ImageAccessor::GetBuffer() const { if (readOnly_) @@ -128,4 +187,35 @@ assert(GetBytesPerPixel(format_) * width_ <= pitch_); } + + + void ImageAccessor::ToMatlabString(std::string& target) const + { + ChunkedBuffer buffer; + + switch (GetFormat()) + { + case PixelFormat_Grayscale8: + ToMatlabStringInternal(buffer, *this); + break; + + case PixelFormat_Grayscale16: + ToMatlabStringInternal(buffer, *this); + break; + + case PixelFormat_SignedGrayscale16: + ToMatlabStringInternal(buffer, *this); + break; + + case PixelFormat_RGB24: + RGB24ToMatlabString(buffer, *this); + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + + buffer.Flatten(target); + } + } diff -r fc34356283e1 -r 87791ebc1f50 Core/ImageFormats/ImageAccessor.h --- a/Core/ImageFormats/ImageAccessor.h Wed Jun 11 09:18:07 2014 +0200 +++ b/Core/ImageFormats/ImageAccessor.h Wed Jun 11 12:23:02 2014 +0200 @@ -106,5 +106,7 @@ unsigned int height, unsigned int pitch, void *buffer); + + void ToMatlabString(std::string& target) const; }; } diff -r fc34356283e1 -r 87791ebc1f50 NEWS --- a/NEWS Wed Jun 11 09:18:07 2014 +0200 +++ b/NEWS Wed Jun 11 12:23:02 2014 +0200 @@ -2,6 +2,7 @@ =============================== * Support of JPEG and JPEG-LS decompression +* Download DICOM images as Matlab/Octave arrays * Precompiled headers for Microsoft Visual Studio diff -r fc34356283e1 -r 87791ebc1f50 OrthancCppClient/OrthancCppClient.cpp --- a/OrthancCppClient/OrthancCppClient.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancCppClient/OrthancCppClient.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -35,6 +35,7 @@ * avoid problems with precompiled headers. **/ +#include "../Core/ChunkedBuffer.cpp" #include "../Core/Enumerations.cpp" #include "../Core/HttpClient.cpp" #include "../Core/ImageFormats/ImageAccessor.cpp" diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/FromDcmtkBridge.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -428,71 +428,6 @@ } - void FromDcmtkBridge::ExtractPngImage(std::string& result, - DcmDataset& dataset, - unsigned int frame, - ImageExtractionMode mode) - { - ImageBuffer tmp; - bool ok = false; - - switch (mode) - { - case ImageExtractionMode_UInt8: - ok = DicomImageDecoder::DecodeAndTruncate(tmp, dataset, frame, PixelFormat_Grayscale8); - break; - - case ImageExtractionMode_UInt16: - ok = DicomImageDecoder::DecodeAndTruncate(tmp, dataset, frame, PixelFormat_Grayscale16); - break; - - case ImageExtractionMode_Int16: - ok = DicomImageDecoder::DecodeAndTruncate(tmp, dataset, frame, PixelFormat_SignedGrayscale16); - break; - - case ImageExtractionMode_Preview: - ok = DicomImageDecoder::DecodePreview(tmp, dataset, frame); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (!ok) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - ImageAccessor accessor(tmp.GetAccessor()); - PngWriter writer; - writer.WriteToMemory(result, accessor); - } - - - void FromDcmtkBridge::ExtractPngImage(std::string& result, - const std::string& dicomContent, - unsigned int frame, - ImageExtractionMode mode) - { - DcmInputBufferStream is; - if (dicomContent.size() > 0) - { - is.setBuffer(&dicomContent[0], dicomContent.size()); - } - is.setEos(); - - DcmFileFormat dicom; - if (dicom.read(is).good()) - { - ExtractPngImage(result, *dicom.getDataset(), frame, mode); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - std::string FromDcmtkBridge::GetName(const DicomTag& t) { diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/FromDcmtkBridge.h Wed Jun 11 12:23:02 2014 +0200 @@ -58,16 +58,6 @@ const std::string& path, unsigned int maxStringLength = 256); - static void ExtractPngImage(std::string& result, - DcmDataset& dataset, - unsigned int frame, - ImageExtractionMode mode); - - static void ExtractPngImage(std::string& result, - const std::string& dicomContent, - unsigned int frame, - ImageExtractionMode mode); - static std::string GetName(const DicomTag& tag); static DicomTag ParseTag(const char* name); diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/Internals/DicomImageDecoder.cpp --- a/OrthancServer/Internals/DicomImageDecoder.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/Internals/DicomImageDecoder.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -77,6 +77,9 @@ +#include "../PrecompiledHeadersServer.h" +#include "DicomImageDecoder.h" + #include "../../Core/OrthancException.h" #include "../../Core/ImageFormats/ImageProcessing.h" #include "../../Core/ImageFormats/PngWriter.h" // TODO REMOVE THIS @@ -323,7 +326,7 @@ << (info.IsPlanar() ? ", planar" : ", non-planar"); throw OrthancException(ErrorCode_NotImplemented); } - + target.SetHeight(info.GetHeight()); target.SetWidth(info.GetWidth()); target.SetFormat(format); diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -202,9 +202,11 @@ std::string dicomContent, png; context.ReadFile(dicomContent, publicId, FileContentType_Dicom); + ParsedDicomFile dicom(dicomContent); + try { - FromDcmtkBridge::ExtractPngImage(png, dicomContent, frame, mode); + dicom.ExtractPngImage(png, frame, mode); call.GetOutput().AnswerBuffer(png, "image/png"); } catch (OrthancException& e) @@ -228,6 +230,39 @@ } + static void GetMatlabImage(RestApi::GetCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + std::string frameId = call.GetUriComponent("frame", "0"); + + unsigned int frame; + try + { + frame = boost::lexical_cast(frameId); + } + catch (boost::bad_lexical_cast) + { + return; + } + + std::string publicId = call.GetUriComponent("id", ""); + std::string dicomContent; + context.ReadFile(dicomContent, publicId, FileContentType_Dicom); + + ParsedDicomFile dicom(dicomContent); + ImageBuffer buffer; + dicom.ExtractImage(buffer, frame); + + ImageAccessor accessor(buffer.GetConstAccessor()); + + std::string result; + accessor.ToMatlabString(result); + + call.GetOutput().AnswerBuffer(result, "text/plain"); + } + + static void GetResourceStatistics(RestApi::GetCall& call) { @@ -587,10 +622,12 @@ Register("/instances/{id}/frames/{frame}/image-uint8", GetImage); Register("/instances/{id}/frames/{frame}/image-uint16", GetImage); Register("/instances/{id}/frames/{frame}/image-int16", GetImage); + Register("/instances/{id}/frames/{frame}/matlab", GetMatlabImage); Register("/instances/{id}/preview", GetImage); Register("/instances/{id}/image-uint8", GetImage); Register("/instances/{id}/image-uint16", GetImage); Register("/instances/{id}/image-int16", GetImage); + Register("/instances/{id}/matlab", GetMatlabImage); Register("/patients/{id}/protected", IsProtectedPatient); Register("/patients/{id}/protected", SetPatientProtection); diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/ParsedDicomFile.cpp Wed Jun 11 12:23:02 2014 +0200 @@ -82,8 +82,10 @@ #include "FromDcmtkBridge.h" #include "ToDcmtkBridge.h" +#include "Internals/DicomImageDecoder.h" #include "../Core/Toolbox.h" #include "../Core/OrthancException.h" +#include "../Core/ImageFormats/ImageBuffer.h" #include "../Core/ImageFormats/PngWriter.h" #include "../Core/Uuid.h" #include "../Core/DicomFormat/DicomString.h" @@ -1214,4 +1216,67 @@ throw OrthancException(ErrorCode_InternalError); } } + + + void ParsedDicomFile::ExtractImage(ImageBuffer& result, + unsigned int frame) + { + DcmDataset& dataset = *pimpl_->file_->getDataset(); + + if (!DicomImageDecoder::Decode(result, dataset, frame)) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + + void ParsedDicomFile::ExtractImage(ImageBuffer& result, + unsigned int frame, + ImageExtractionMode mode) + { + DcmDataset& dataset = *pimpl_->file_->getDataset(); + + bool ok = false; + + switch (mode) + { + case ImageExtractionMode_UInt8: + ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_Grayscale8); + break; + + case ImageExtractionMode_UInt16: + ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_Grayscale16); + break; + + case ImageExtractionMode_Int16: + ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_SignedGrayscale16); + break; + + case ImageExtractionMode_Preview: + ok = DicomImageDecoder::DecodePreview(result, dataset, frame); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + if (!ok) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + + void ParsedDicomFile::ExtractPngImage(std::string& result, + unsigned int frame, + ImageExtractionMode mode) + { + ImageBuffer buffer; + ExtractImage(buffer, frame, mode); + + ImageAccessor accessor(buffer.GetConstAccessor()); + PngWriter writer; + writer.WriteToMemory(result, accessor); + } + } diff -r fc34356283e1 -r 87791ebc1f50 OrthancServer/ParsedDicomFile.h --- a/OrthancServer/ParsedDicomFile.h Wed Jun 11 09:18:07 2014 +0200 +++ b/OrthancServer/ParsedDicomFile.h Wed Jun 11 12:23:02 2014 +0200 @@ -36,6 +36,7 @@ #include "../Core/RestApi/RestApiOutput.h" #include "ServerEnumerations.h" #include "../Core/ImageFormats/ImageAccessor.h" +#include "../Core/ImageFormats/ImageBuffer.h" namespace Orthanc { @@ -92,6 +93,17 @@ void EmbedImage(const ImageAccessor& accessor); void EmbedImage(const std::string& dataUriScheme); + + void ExtractImage(ImageBuffer& result, + unsigned int frame); + + void ExtractImage(ImageBuffer& result, + unsigned int frame, + ImageExtractionMode mode); + + void ExtractPngImage(std::string& result, + unsigned int frame, + ImageExtractionMode mode); }; }