Mercurial > hg > orthanc
changeset 844:502c49adb5ad jpeg
jpeg lossless
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 05 Jun 2014 14:08:23 +0200 |
parents | 6a5cceec04ef |
children | 48016722c770 |
files | Core/ImageFormats/ImageAccessor.h Core/ImageFormats/ImageBuffer.cpp Core/ImageFormats/ImageBuffer.h Core/ImageFormats/PngWriter.h Resources/CMake/DcmtkConfiguration.cmake UnitTestsSources/JpegLossless.cpp |
diffstat | 6 files changed, 168 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/ImageFormats/ImageAccessor.h Wed Jun 04 17:57:59 2014 +0200 +++ b/Core/ImageFormats/ImageAccessor.h Thu Jun 05 14:08:23 2014 +0200 @@ -77,6 +77,11 @@ return pitch_; } + unsigned int GetSize() const + { + return GetHeight() * GetPitch(); + } + const void* GetConstBuffer() const { return buffer_;
--- a/Core/ImageFormats/ImageBuffer.cpp Wed Jun 04 17:57:59 2014 +0200 +++ b/Core/ImageFormats/ImageBuffer.cpp Thu Jun 05 14:08:23 2014 +0200 @@ -39,6 +39,13 @@ { if (changed_) { + /* + if (forceMinimalPitch_) + { + TODO: Align pitch and memory buffer to optimal size for SIMD. + } + */ + pitch_ = GetBytesPerPixel() * width_; data_.resize(pitch_ * height_); @@ -59,6 +66,7 @@ ImageBuffer::ImageBuffer() : changed_(false) { changed_ = false; + forceMinimalPitch_ = true; format_ = PixelFormat_Grayscale8; width_ = 0; height_ = 0; @@ -106,4 +114,11 @@ accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_); return accessor; } + + + void ImageBuffer::SetMinimalPitchForced(bool force) + { + changed_ = true; + forceMinimalPitch_ = force; + } }
--- a/Core/ImageFormats/ImageBuffer.h Wed Jun 04 17:57:59 2014 +0200 +++ b/Core/ImageFormats/ImageBuffer.h Thu Jun 05 14:08:23 2014 +0200 @@ -45,6 +45,7 @@ bool changed_; std::vector<uint8_t> data_; + bool forceMinimalPitch_; // Currently unused PixelFormat format_; unsigned int width_; unsigned int height_; @@ -85,5 +86,12 @@ ImageAccessor GetAccessor(); ImageAccessor GetConstAccessor(); + + bool IsMinimalPitchForced() const + { + return forceMinimalPitch_; + } + + void SetMinimalPitchForced(bool force); }; }
--- a/Core/ImageFormats/PngWriter.h Wed Jun 04 17:57:59 2014 +0200 +++ b/Core/ImageFormats/PngWriter.h Thu Jun 05 14:08:23 2014 +0200 @@ -32,7 +32,7 @@ #pragma once -#include "../Enumerations.h" +#include "ImageAccessor.h" #include <boost/shared_ptr.hpp> #include <string> @@ -74,5 +74,19 @@ unsigned int pitch, PixelFormat format, const void* buffer); + + void WriteToFile(const char* filename, + const ImageAccessor& accessor) + { + WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetBuffer()); + } + + void WriteToMemory(std::string& png, + const ImageAccessor& accessor) + { + WriteToMemory(png, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetBuffer()); + } }; }
--- a/Resources/CMake/DcmtkConfiguration.cmake Wed Jun 04 17:57:59 2014 +0200 +++ b/Resources/CMake/DcmtkConfiguration.cmake Thu Jun 05 14:08:23 2014 +0200 @@ -58,6 +58,8 @@ ) list(REMOVE_ITEM DCMTK_SOURCES ${DCMTK_SOURCES_DIR}/dcmjpls/libsrc/djcodece.cc) + list(APPEND DCMTK_SOURCES + ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djrplol.cc) endif()
--- a/UnitTestsSources/JpegLossless.cpp Wed Jun 04 17:57:59 2014 +0200 +++ b/UnitTestsSources/JpegLossless.cpp Thu Jun 05 14:08:23 2014 +0200 @@ -40,17 +40,29 @@ #include <dcmtk/dcmdata/dcfilefo.h> #include <dcmtk/dcmjpls/djcodecd.h> +#include <dcmtk/dcmjpls/djcparam.h> +#include <dcmtk/dcmjpeg/djrplol.h> +#include <dcmtk/dcmdata/dcstack.h> +#include <dcmtk/dcmdata/dcpixseq.h> #include "../OrthancServer/ParsedDicomFile.h" #include "../OrthancServer/FromDcmtkBridge.h" +#include "../OrthancServer/ToDcmtkBridge.h" +#include "../Core/OrthancException.h" +#include "../Core/ImageFormats/ImageBuffer.h" +#include "../Core/ImageFormats/PngWriter.h" + +#include <boost/lexical_cast.hpp> using namespace Orthanc; TEST(JpegLossless, Basic) { - DJLSDecoderRegistration::registerCodecs( EJLSUC_default, EJLSPC_restore,OFFalse ); + //DJLSDecoderRegistration::registerCodecs( EJLSUC_default, EJLSPC_restore,OFFalse ); #if 0 + // Fallback + std::string s; Toolbox::ReadFile(s, "IM-0001-1001-0001.dcm"); @@ -67,41 +79,130 @@ parsed.SaveToFile("tutu.dcm"); - FromDcmtkBridge::ExtractPngImage(s, *dataset, 1, ImageExtractionMode_Preview); - //fileformat.saveFile("test_decompressed.dcm", EXS_LittleEndianExplicit); - } -#else - DcmFileFormat fileformat; - if (fileformat.loadFile("IM-0001-1001-0001.dcm").good()) - { - DcmDataset *dataset = fileformat.getDataset(); - // decompress data set if compressed dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL); DcmXfer original_xfer(dataset->getOriginalXfer()); std::cout << original_xfer.getXferName() << std::endl; - printf("OK1\n"); + FromDcmtkBridge::ExtractPngImage(s, *dataset, 1, ImageExtractionMode_Preview); + //fileformat.saveFile("test_decompressed.dcm", EXS_LittleEndianExplicit); + } +#else + DcmFileFormat fileformat; + //if (fileformat.loadFile("IM-0001-1001-0001.dcm").good()) + if (fileformat.loadFile("tata.dcm").good()) + { + DcmDataset *dataset = fileformat.getDataset(); + + // <data-set xfer="1.2.840.10008.1.2.4.80" name="JPEG-LS Lossless"> + + DcmTag k(DICOM_TAG_PIXEL_DATA.GetGroup(), + DICOM_TAG_PIXEL_DATA.GetElement()); + + DcmElement *element = NULL; + if (dataset->findAndGetElement(k, element).good()) + { + DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element); + DcmPixelSequence* pixelSequence = NULL; + if (pixelData.getEncapsulatedRepresentation + (dataset->getOriginalXfer(), NULL, pixelSequence).good()) + { + OFString value; + + if (!dataset->findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_COLUMNS), value).good()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + unsigned int width = boost::lexical_cast<unsigned int>(value.c_str()); + + if (!dataset->findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_ROWS), value).good()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + unsigned int height = boost::lexical_cast<unsigned int>(value.c_str()); + + if (!dataset->findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_BITS_STORED), value).good()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + unsigned int bitsStored = boost::lexical_cast<unsigned int>(value.c_str()); + + if (!dataset->findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_REPRESENTATION), value).good()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + bool isSigned = (boost::lexical_cast<unsigned int>(value.c_str()) != 0); - // check if everything went well - if (1) //dataset->canWriteXfer(EXS_LittleEndianExplicit)) - { - printf("OK2\n"); + unsigned int samplesPerPixel = 1; // By default + if (dataset->findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_SAMPLES_PER_PIXEL), value).good()) + { + samplesPerPixel = boost::lexical_cast<unsigned int>(value.c_str()); + } + + ImageBuffer buffer; + buffer.SetHeight(height); + buffer.SetWidth(width); - fileformat.saveFile("tutu.dcm", EXS_LittleEndianExplicit); + if (bitsStored == 8 && samplesPerPixel == 1 && !isSigned) + { + buffer.SetFormat(PixelFormat_Grayscale8); + } + else if (bitsStored == 8 && samplesPerPixel == 3 && !isSigned) + { + buffer.SetFormat(PixelFormat_RGB24); + } + else if (bitsStored == 16 && samplesPerPixel == 1 && !isSigned) + { + buffer.SetFormat(PixelFormat_Grayscale16); + } + else if (bitsStored == 16 && samplesPerPixel == 1 && isSigned) + { + buffer.SetFormat(PixelFormat_SignedGrayscale16); + } + else + { + throw OrthancException(ErrorCode_NotImplemented); + } + + ImageAccessor accessor(buffer.GetAccessor()); + + // http://support.dcmtk.org/docs/classDJLSLosslessDecoder.html + DJLSLosslessDecoder bb; DJLSCodecParameter cp; + //DJLSNearLosslessDecoder bb; DJLSCodecParameter cp; + + Uint32 startFragment = 0; // Default + OFString decompressedColorModel; // Out + DJ_RPLossless rp; + OFCondition c = bb.decodeFrame(&rp, pixelSequence, &cp, dataset, 0, startFragment, + accessor.GetBuffer(), accessor.GetSize(), decompressedColorModel); + + + + for (unsigned int y = 0; y < accessor.GetHeight(); y++) + { + int16_t *p = reinterpret_cast<int16_t*>(accessor.GetRow(y)); + for (unsigned int x = 0; x < accessor.GetWidth(); x++, p ++) + { + if (*p < 0) + *p = 0; + } + } + + PngWriter w; + w.WriteToFile("tata.png", accessor); + } } } - #endif - // http://support.dcmtk.org/docs/classDJLSLosslessDecoder.html - //DJLSDecoderBase b; - DJLSLosslessDecoder bb; - - DJLSDecoderRegistration::cleanup(); + //DJLSDecoderRegistration::cleanup(); }