# HG changeset patch # User Sebastien Jodogne # Date 1584046115 -3600 # Node ID 113a7b994a12f824b1297d7bffee111ae3d258cc # Parent accf1b60b1083fe515cc019ca38a836e128a78c3 extracting the raw frame in the transcoder diff -r accf1b60b108 -r 113a7b994a12 Core/DicomParsing/Internals/DicomFrameIndex.cpp --- a/Core/DicomParsing/Internals/DicomFrameIndex.cpp Thu Mar 12 17:58:34 2020 +0100 +++ b/Core/DicomParsing/Internals/DicomFrameIndex.cpp Thu Mar 12 21:48:35 2020 +0100 @@ -68,7 +68,10 @@ uint32_t length = item->getLength(); if (length == 0) { - table.clear(); + // Degenerate case: Empty offset table means only one frame + // that overlaps all the fragments + table.resize(1); + table[0] = 0; return; } @@ -146,7 +149,6 @@ throw OrthancException(ErrorCode_BadFileFormat); } - // Loop over the fragments (ignoring the offset table). This is // an alternative, faster implementation to DCMTK's // "DcmCodec::determineStartFragment()". @@ -318,46 +320,10 @@ }; - - bool DicomFrameIndex::IsVideo(DcmFileFormat& dicom) + unsigned int DicomFrameIndex::GetFramesCount(DcmDataset& dicom) { - // Retrieve the transfer syntax from the DICOM header - const char* value = NULL; - if (!dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() || - value == NULL) - { - return false; - } - - const std::string transferSyntax(value); - - // Video standards supported in DICOM 2016a - // http://dicom.nema.org/medical/dicom/2016a/output/html/part05.html - if (transferSyntax == "1.2.840.10008.1.2.4.100" || // MPEG2 MP@ML option of ISO/IEC MPEG2 - transferSyntax == "1.2.840.10008.1.2.4.101" || // MPEG2 MP@HL option of ISO/IEC MPEG2 - transferSyntax == "1.2.840.10008.1.2.4.102" || // MPEG-4 AVC/H.264 High Profile / Level 4.1 of ITU-T H.264 - transferSyntax == "1.2.840.10008.1.2.4.103" || // MPEG-4 AVC/H.264 BD-compat High Profile / Level 4.1 of ITU-T H.264 - transferSyntax == "1.2.840.10008.1.2.4.104" || // MPEG-4 AVC/H.264 High Profile / Level 4.2 of ITU-T H.264 - transferSyntax == "1.2.840.10008.1.2.4.105" || // MPEG-4 AVC/H.264 High Profile / Level 4.2 of ITU-T H.264 - transferSyntax == "1.2.840.10008.1.2.4.106") // MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2 of the ITU-T H.264 - { - return true; - } - - return false; - } - - - unsigned int DicomFrameIndex::GetFramesCount(DcmFileFormat& dicom) - { - // Assume 1 frame for video transfer syntaxes - if (IsVideo(dicom)) - { - return 1; - } - const char* tmp = NULL; - if (!dicom.getDataset()->findAndGetString(DCM_NumberOfFrames, tmp).good() || + if (!dicom.findAndGetString(DCM_NumberOfFrames, tmp).good() || tmp == NULL) { return 1; @@ -378,12 +344,12 @@ } else { - return count; + return static_cast(count); } } - DicomFrameIndex::DicomFrameIndex(DcmFileFormat& dicom) + DicomFrameIndex::DicomFrameIndex(DcmDataset& dicom) { countFrames_ = GetFramesCount(dicom); if (countFrames_ == 0) @@ -392,10 +358,8 @@ return; } - DcmDataset& dataset = *dicom.getDataset(); - // Test whether this image is composed of a sequence of fragments - DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset); + DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dicom); if (pixelSequence != NULL) { index_.reset(new FragmentIndex(pixelSequence, countFrames_)); @@ -404,18 +368,18 @@ // Extract information about the image structure DicomMap tags; - FromDcmtkBridge::ExtractDicomSummary(tags, dataset); + FromDcmtkBridge::ExtractDicomSummary(tags, dicom); DicomImageInformation information(tags); // Access to the raw pixel data - if (DicomImageDecoder::IsPsmctRle1(dataset)) + if (DicomImageDecoder::IsPsmctRle1(dicom)) { - index_.reset(new PsmctRle1Index(dataset, countFrames_, information.GetFrameSize())); + index_.reset(new PsmctRle1Index(dicom, countFrames_, information.GetFrameSize())); } else { - index_.reset(new UncompressedIndex(dataset, countFrames_, information.GetFrameSize())); + index_.reset(new UncompressedIndex(dicom, countFrames_, information.GetFrameSize())); } } diff -r accf1b60b108 -r 113a7b994a12 Core/DicomParsing/Internals/DicomFrameIndex.h --- a/Core/DicomParsing/Internals/DicomFrameIndex.h Thu Mar 12 17:58:34 2020 +0100 +++ b/Core/DicomParsing/Internals/DicomFrameIndex.h Thu Mar 12 21:48:35 2020 +0100 @@ -67,7 +67,7 @@ unsigned int countFrames_; public: - DicomFrameIndex(DcmFileFormat& dicom); + DicomFrameIndex(DcmDataset& dicom); unsigned int GetFramesCount() const { @@ -77,8 +77,6 @@ void GetRawFrame(std::string& frame, unsigned int index) const; - static bool IsVideo(DcmFileFormat& dicom); - - static unsigned int GetFramesCount(DcmFileFormat& dicom); + static unsigned int GetFramesCount(DcmDataset& dicom); }; } diff -r accf1b60b108 -r 113a7b994a12 Core/DicomParsing/ParsedDicomFile.cpp --- a/Core/DicomParsing/ParsedDicomFile.cpp Thu Mar 12 17:58:34 2020 +0100 +++ b/Core/DicomParsing/ParsedDicomFile.cpp Thu Mar 12 21:48:35 2020 +0100 @@ -1557,7 +1557,9 @@ { if (pimpl_->frameIndex_.get() == NULL) { - pimpl_->frameIndex_.reset(new DicomFrameIndex(*pimpl_->file_)); + assert(pimpl_->file_ != NULL && + pimpl_->file_->getDataset() != NULL); + pimpl_->frameIndex_.reset(new DicomFrameIndex(*pimpl_->file_->getDataset())); } pimpl_->frameIndex_->GetRawFrame(target, frameId); @@ -1589,7 +1591,9 @@ unsigned int ParsedDicomFile::GetFramesCount() const { - return DicomFrameIndex::GetFramesCount(*pimpl_->file_); + assert(pimpl_->file_ != NULL && + pimpl_->file_->getDataset() != NULL); + return DicomFrameIndex::GetFramesCount(*pimpl_->file_->getDataset()); } diff -r accf1b60b108 -r 113a7b994a12 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Thu Mar 12 17:58:34 2020 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Thu Mar 12 21:48:35 2020 +0100 @@ -1917,7 +1917,7 @@ #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -#include "../Core/DicomFormat/DicomImageInformation.h" +#include "../Core/DicomParsing/Internals/DicomFrameIndex.h" #include #include @@ -1954,12 +1954,11 @@ class DcmtkTranscoder : public IDicomTranscoder { private: - std::unique_ptr dicom_; - DicomTransferSyntax transferSyntax_; - std::string sopClassUid_; - std::string sopInstanceUid_; - DicomMap tags_; - std::unique_ptr info_; + std::unique_ptr dicom_; + std::unique_ptr index_; + DicomTransferSyntax transferSyntax_; + std::string sopClassUid_; + std::string sopInstanceUid_; void Setup(DcmFileFormat* dicom) { @@ -1972,12 +1971,8 @@ } DcmDataset& dataset = *dicom_->getDataset(); + index_.reset(new DicomFrameIndex(dataset)); - tags_.Clear(); - FromDcmtkBridge::ExtractDicomSummary(tags_, dataset); - - info_.reset(new DicomImageInformation(tags_)); - E_TransferSyntax xfer = dataset.getOriginalXfer(); if (xfer == EXS_Unknown) { @@ -1997,12 +1992,20 @@ "Unsupported transfer syntax: " + boost::lexical_cast(xfer)); } - if (!tags_.LookupStringValue(sopClassUid_, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) || - !tags_.LookupStringValue(sopInstanceUid_, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false)) + const char* a = NULL; + const char* b = NULL; + + if (!dataset.findAndGetString(DCM_SOPClassUID, a).good() || + !dataset.findAndGetString(DCM_SOPInstanceUID, b).good() || + a == NULL || + b == NULL) { throw OrthancException(ErrorCode_BadFileFormat, "Missing SOP class/instance UID in DICOM instance"); } + + sopClassUid_.assign(a); + sopInstanceUid_.assign(b); } public: @@ -2034,7 +2037,7 @@ virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE { - return info_->GetNumberOfFrames(); + return index_->GetFramesCount(); } virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE @@ -2046,55 +2049,27 @@ virtual void GetCompressedFrame(std::string& target, unsigned int frame) ORTHANC_OVERRIDE { +#if 1 + index_->GetRawFrame(target, frame); + printf("%d: %d\n", frame, target.size()); +#endif + +#if 1 assert(dicom_->getDataset() != NULL); DcmDataset& dataset = *dicom_->getDataset(); DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset); - if (pixelSequence == NULL) - { - // This is an uncompressed frame - - DcmElement* element = NULL; - if (dataset.findAndGetElement(DCM_PixelData, element).good() && - element != NULL) - { - Uint8* pixelData = NULL; - - if (element->getUint8Array(pixelData).good() && - pixelData != NULL) - { - // TODO => use "pixelData" - printf("RAW %d\n", element->getLength()); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot access uncompressed pixel data"); - } - } - else - { - std::string decoded; - if (DicomImageDecoder::DecodePsmctRle1(decoded, dataset)) - { - // TODO => use "decoded" - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot access uncompressed pixel data"); - } - } - } - else + if (pixelSequence != NULL && + frame == 0 && + pixelSequence->card() != GetFramesCount() + 1) { printf("COMPRESSED\n"); - + // Check out "djcodecd.cc" - + printf("%d fragments\n", pixelSequence->card()); - + // Skip the first fragment, that is the offset table for (unsigned long i = 1; ;i++) { @@ -2109,6 +2084,7 @@ } } } +#endif } virtual IDicomTranscoder* Transcode(std::set syntaxes, @@ -2210,8 +2186,20 @@ transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(), transcoder.GetFramesCount()); - std::string f; - transcoder.GetCompressedFrame(f, 0); + for (size_t i = 0; i < transcoder.GetFramesCount(); i++) + { + std::string f; + transcoder.GetCompressedFrame(f, i); + + if (i == 0) + { + static unsigned int i = 0; + char buf[1024]; + sprintf(buf, "/tmp/frame-%06d.dcm", i++); + printf(">> %s\n", buf); + Orthanc::SystemToolbox::WriteFile(f, buf); + } + } printf("\n"); } @@ -2271,6 +2259,7 @@ } TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Multiframe.dcm"); + TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Issue44/Monochrome1-Jpeg.dcm"); } }