Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I have a question about compression. #1532

Closed
cslee99 opened this issue Nov 16, 2021 · 7 comments
Closed

I have a question about compression. #1532

cslee99 opened this issue Nov 16, 2021 · 7 comments
Labels

Comments

@cslee99
Copy link

cslee99 commented Nov 16, 2021

I am using pydicom version 2.2.2.
I tried DICOM compression by referring to Compressing Pixel Data in the pydicom User Guide.
Implicit Little Endian and Explicit Little Endian compressed well, as described in the guide.
However, in compressed DICOM such as J2K, an error occurs during the compression process.

ds = dcmread(filePath)
ds.compress(transferSyntax, encoding_plugin='pylibjpeg')
ds.save_as(filePath.replace('.dcm', '') + "_" + str(transferSyntax) + ".dcm")
@mrbean-bremen
Copy link
Member

You mean you try to compress data that is already compressed in another transfer syntax? You would have to decompress that first.

@cslee99
Copy link
Author

cslee99 commented Nov 19, 2021

You mean you try to compress data that is already compressed in another transfer syntax? You would have to decompress that first.

I modified it with the code below, but an error occurs.

        ds = dcmread(filePath)
        if (ds.file_meta.TransferSyntaxUID.is_compressed):
            ds.decompress("pylibjpeg")
            ds.compress(transferSyntax, encoding_plugin='pylibjpeg')
        else:
            ds.compress(transferSyntax, encoding_plugin='pylibjpeg')
        ds.save_as(filePath.replace('.dcm', '') + "_" + str(transferSyntax) + ".dcm")

Do you have any more code to add?

@scaramallion
Copy link
Member

Could you post a minimally reproducible code example and the full error traceback you're getting? It's really hard to figure out what's going on without seeing executable code (what's transferSyntax, for example).

@cslee99
Copy link
Author

cslee99 commented Nov 25, 2021

Could you post a minimally reproducible code example and the full error traceback you're getting? It's really hard to figure out what's going on without seeing executable code (what's transferSyntax, for example).

Sorry. The question was insufficient.
I want to change from 1.2.840.10008.1.2.4.91 (JPEG2000) to 1.2.840.10008.1.2.5 (RLELossless).
The executable code is the same as the example above.

Error code ==> ds.compress(transferSyntax, encoding_plugin='pylibjpeg')
Exception : Unable to encode as the actual length of the frame (190434 bytes) is less than the expected length of 524288 bytes
Any more code to add to the example?

@scaramallion
Copy link
Member

scaramallion commented Nov 25, 2021

The error indicates that the amount of uncompressed pixel data doesn't match the expected amount, likely because the Pixel Data element itself is still compressed (which is weird, the docstring for Dataset.decompress() says its an in-place change?). The compress() function uses the Pixel Data in the dataset as its source unless a numpy ndarray arr is passed.

I'd pass the uncompressed array to the compress function:

ds = dcmread(...)
ds.decompress("pylibjpeg")
ds.PhotometricInterpretation = <whatever>
ds.compress(RLELossless, ds.pixel_array, encoding_plugin="pylibjpeg")

Where Photometric Interpretation is probably going to either be RGB or MONOCHROME1 or 2.

@cslee99
Copy link
Author

cslee99 commented Nov 26, 2021

The error indicates that the amount of uncompressed pixel data doesn't match the expected amount, likely because the Pixel Data element itself is still compressed (which is weird, the docstring for Dataset.decompress() says its an in-place change?). The compress() function uses the Pixel Data in the dataset as its source unless a numpy ndarray arr is passed.

I'd pass the uncompressed array to the compress function:

ds = dcmread(...)
ds.decompress("pylibjpeg")
ds.PhotometricInterpretation = <whatever>
ds.compress(RLELossless, ds.pixel_array, encoding_plugin="pylibjpeg")

Where Photometric Interpretation is probably going to either be RGB or MONOCHROME1 or 2.

The comments were very helpful. thank you.
1 more question.
gdcm seems to support most compress and decompress.
However, pydicom supports decompress for most compressions, but compress only supports RLELossless?

@scaramallion
Copy link
Member

scaramallion commented Nov 26, 2021

A couple of reasons:

  • I really haven't had much free time this year
  • I don't want to include any compression that isn't conformant to the DICOM standard - including non-conformant compression would be simple!
  • I'd rather focus on lossless JPEG compression functionality (because lossy JPEG is a dumpster fire)
  • GDCM's default implementation of JPEG2000 compression was weird (and a non-default implementation is buggy on Python)
  • Pillow's JPEG2000 compression doesn't allow signed pixel data or the use of MCT
  • Which leaves adding encoding to pylibjpeg (see point 1)

So in summary, the real reason is a lack of third-party support for DICOM conformant JPEG encoding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants