# HG changeset patch # User Sebastien Jodogne # Date 1647849560 -3600 # Node ID dfbe764995cf8e97f896af285a16139db981af10 # Parent 51e4947aa3b36bbd62f40e27415f65a62bb3d40d added ParsedDicomFile::DecodeAllOverlays() diff -r 51e4947aa3b3 -r dfbe764995cf OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Sun Mar 20 18:03:32 2022 +0100 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Mon Mar 21 08:59:20 2022 +0100 @@ -1920,7 +1920,7 @@ } - void ParsedDicomFile::ListOverlays(std::set& groups) const + void ParsedDicomFile::ListOverlays(std::set& groups) const { DcmDataset& dataset = *const_cast(*this).GetDcmtkObject().getDataset(); @@ -1953,7 +1953,7 @@ ImageAccessor* ParsedDicomFile::DecodeOverlay(int& originX, int& originY, - unsigned int group) const + uint16_t group) const { // https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.9.2.html @@ -2014,6 +2014,67 @@ } + ImageAccessor* ParsedDicomFile::DecodeAllOverlays(int& originX, + int& originY) const + { + std::set groups; + ListOverlays(groups); + + if (groups.empty()) + { + originX = 0; + originY = 0; + return new Image(PixelFormat_Grayscale8, 0, 0, false); + } + else + { + std::set::const_iterator it = groups.begin(); + assert(it != groups.end()); + + std::unique_ptr result(DecodeOverlay(originX, originY, *it)); + assert(result.get() != NULL); + ++it; + + int right = originX + static_cast(result->GetWidth()); + int bottom = originY + static_cast(result->GetHeight()); + + while (it != groups.end()) + { + int ox, oy; + std::unique_ptr overlay(DecodeOverlay(ox, oy, *it)); + assert(overlay.get() != NULL); + + int mergedX = std::min(originX, ox); + int mergedY = std::min(originY, oy); + right = std::max(right, ox + static_cast(overlay->GetWidth())); + bottom = std::max(bottom, oy + static_cast(overlay->GetHeight())); + + assert(right >= mergedX && bottom >= mergedY); + unsigned int width = static_cast(right - mergedX); + unsigned int height = static_cast(bottom - mergedY); + + std::unique_ptr merged(new Image(PixelFormat_Grayscale8, width, height, false)); + ImageProcessing::Set(*merged, 0); + + ImageAccessor a; + merged->GetRegion(a, originX - mergedX, originY - mergedY, result->GetWidth(), result->GetHeight()); + ImageProcessing::Maximum(a, *result); + + merged->GetRegion(a, ox - mergedX, oy - mergedY, overlay->GetWidth(), overlay->GetHeight()); + ImageProcessing::Maximum(a, *overlay); + + originX = mergedX; + originY = mergedY; + result.reset(merged.release()); + + ++it; + } + + return result.release(); + } + } + + #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1 // Alias for binary compatibility with Orthanc Framework 1.7.2 => don't use it anymore void ParsedDicomFile::DatasetToJson(Json::Value& target, diff -r 51e4947aa3b3 -r dfbe764995cf OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Sun Mar 20 18:03:32 2022 +0100 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Mon Mar 21 08:59:20 2022 +0100 @@ -301,10 +301,13 @@ double& rescaleSlope, unsigned int frame) const; - void ListOverlays(std::set& groups) const; + void ListOverlays(std::set& groups) const; ImageAccessor* DecodeOverlay(int& originX, int& originY, - unsigned int group) const; + uint16_t group) const; + + ImageAccessor* DecodeAllOverlays(int& originX, + int& originY) const; }; } diff -r 51e4947aa3b3 -r dfbe764995cf OrthancFramework/Sources/Images/ImageProcessing.cpp --- a/OrthancFramework/Sources/Images/ImageProcessing.cpp Sun Mar 20 18:03:32 2022 +0100 +++ b/OrthancFramework/Sources/Images/ImageProcessing.cpp Mon Mar 21 08:59:20 2022 +0100 @@ -2964,4 +2964,71 @@ throw OrthancException(ErrorCode_NotImplemented); } } + + + template + static void ApplyImageOntoImage(Functor f, + ImageAccessor& image /* inout */, + const ImageAccessor& other) + { + const unsigned int width = image.GetWidth(); + const unsigned int height = image.GetHeight(); + + if (width != other.GetWidth() || + height != other.GetHeight()) + { + throw OrthancException(ErrorCode_IncompatibleImageSize); + } + else if (image.GetFormat() != other.GetFormat() || + GetBytesPerPixel(image.GetFormat()) != sizeof(PixelType)) + { + throw OrthancException(ErrorCode_IncompatibleImageFormat); + } + else + { + for (unsigned int y = 0; y < height; y++) + { + PixelType* p = reinterpret_cast(image.GetRow(y)); + const PixelType* q = reinterpret_cast(other.GetConstRow(y)); + + for (unsigned int x = 0; x < width; x++, p++, q++) + { + f(*p, *q); + } + } + } + } + + + void ImageProcessing::Maximum(ImageAccessor& image, + const ImageAccessor& other) + { + struct F + { + void operator() (uint8_t& a, const uint8_t& b) + { + a = std::max(a, b); + } + + void operator() (uint16_t& a, const uint16_t& b) + { + a = std::max(a, b); + } + }; + + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + ApplyImageOntoImage(F(), image, other); + return; + + case PixelFormat_Grayscale16: + ApplyImageOntoImage(F(), image, other); + return; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } } diff -r 51e4947aa3b3 -r dfbe764995cf OrthancFramework/Sources/Images/ImageProcessing.h --- a/OrthancFramework/Sources/Images/ImageProcessing.h Sun Mar 20 18:03:32 2022 +0100 +++ b/OrthancFramework/Sources/Images/ImageProcessing.h Mon Mar 21 08:59:20 2022 +0100 @@ -218,5 +218,8 @@ static void ConvertJpegYCbCrToRgb(ImageAccessor& image /* inplace */); static void SwapEndianness(ImageAccessor& image /* inplace */); + + static void Maximum(ImageAccessor& image /* inout */, + const ImageAccessor& other); }; }