-
-
Notifications
You must be signed in to change notification settings - Fork 471
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
Re-compressing data results in bright image #1637
Comments
Also, just did a sanity check between bad_ct.dcm and test.dcm, ds.PixelRepresentation = 0 for test.dcm. However, even if I force ds.PixelRepresentation = 1 and confirm with print(ds), when I invoke ds.save_as("test.dcm"), the resultant file has a pixel representation of 0. What is going on? |
Your problem lies with Pillow, not with pydicom. Pillow will treat signed image data as unsigned when compressing J2K, which will give you a non-conformant result. |
Do you have a recommendation of an alternative method of saving 16 bit signed data to J2K and shunting it into frame_data? Also, is PIL encoding the J2K the reason that I can't change PixelRepresentation? |
No, that should work. Could you show us your code?
There's nothing that's particularly straight-forward, but GDCM is probably your best bet. |
The code I'm using: from pydicom import dcmread
from pydicom.encaps import encapsulate
from PIL import Image
from io import BytesIO
ds = dcmread("images/bad_ct.dcm")
img = ds.pixel_array
frame_data = []
pil_img = Image.fromarray(img, "I;16")
with BytesIO() as output:
pil_img.save(output, format="jpeg2000")
frame_data.append(output.getvalue())
ds.PixelData = encapsulate(frame_data)
ds.file_meta.TransferSyntaxUID = "1.2.840.10008.1.2.4.90"
ds['PixelData'].is_undefined_length = True
ds.is_decompressed = False
ds.PixelRepresentation = 1
ds.save_as("test.dcm")
print(ds.PixelRepresentation) The printout confirms that it's set to "1" but when I open test.dcm, it's set to 0 |
I can't reproduce with from pydicom import dcmread
from pydicom.data import get_testdata_file
ds = get_testdata_file("CT_small.dcm", read=True)
assert ds.PixelRepresentation == 1
ds.PixelRepresentation = 0
assert ds.PixelRepresentation == 0
ds.save_as("test.dcm")
ns = dcmread("test.dcm")
assert ns.PixelRepresentation == 0
ns.PixelRepresentation = 1
assert ns.PixelRepresentation == 1
ns.save_as("test2.dcm")
es = dcmread("test2.dcm")
assert es.PixelRepresentation == 1 Could you double check that you're looking at the correct |
That's so bizarre. If I open the file using PyDicom, PixelRepresentation is indeed 1. However, my DICOM viewer (microdicomviewer) shows it as 0. That's strange. I checked in Mango as well, the image does have the correct Pixel Representation of 1. Unfortuantely, the image is still all white. I will try compressing with GDCM. Hopefully I can do it programmatically in Python in memory. Thank you for your help! @scaramallion is there any reason why re-casting the int16 to uint16 and then saving it using PIL still results in a file that doesn't look quite right? Does the JPEG byte values get mapped directly to the window/level of the image? That's essentially what I'm seeing, if I move my level up by +32767, it looks like the original file. Edit 2: Sorry if it seems like I'm rambling here, is it possible that they've directly mapped JPEG pixel values to HU? If so, could I manually set the slope/intercept to re-adjust the recasted uint16 (+32767) automatically for the final viewer? Edit 3: setting ds.RescaleIntercept = -32767 worked. Woohoo :) |
You have to be careful with converting to unsigned then compressing using Pillow because the J2K file will have a flag that it's unsigned while the DICOM dataset will indicate its signed. Some (non-conformant) implementations may not correctly interpret this. It's possible that this is what you're seeing with your viewer and it's claimed Pixel Representation of 0 when it should be 1. |
Sorry, I forgot to add that I also had to manually set ds.PixelRepresentation=0. You're right that it is now unsigned. I'm hoping that I don't have to run into this scenario too often. Hopefully we get an easy way to write signed int16 to J2K through PIL soon! |
Closing as appears not to be pydicom related. |
Describe the issue
I have a DCM that I unfortunately cannot share, but I will do my best to describe the scenario. The file is compressed as a 16 bit JPEG2000. The issue I'm having is that I want to decompress the image, do some actions to the pixels, and then shove it back into the DCM. However, if I extract the image and then immediately recompress and put it back into the .dcm, the image is bad. The blacks become white, while everything else stays the same. It's not inverted, it's more like the values have over-flowed.
Original DCM
New DCM
When I print(img), I get the following:
[[-2048 -2048 -2048 ... -2048 -2048 -2048]
[-2048 -2048 -2048 ... -2048 -2048 -2048]
[-2048 -2048 -2048 ... -2048 -2048 -2048]
...
[-2048 -2048 -2048 ... -2048 -2048 -2048]
[-2048 -2048 -2048 ... -2048 -2048 -2048]
[-2048 -2048 -2048 ... -2048 -2048 -2048]]
min, max = -2065, 1171
Steps to reproduce
I am using the following code to extract the pixel data and then put it back into the same file:
Info about the file:
1.2.840.10008.1.2.4.91
(0028, 0002) Samples per Pixel US: 1
(0028, 0004) Photometric Interpretation CS: 'MONOCHROME2'
(0028, 0010) Rows US: 512
(0028, 0011) Columns US: 512
(0028, 0030) Pixel Spacing DS: [0.892, 0.892]
(0028, 0100) Bits Allocated US: 16
(0028, 0101) Bits Stored US: 16
(0028, 0102) High Bit US: 15
(0028, 0103) Pixel Representation US: 1
(0028, 1050) Window Center DS: '70.0'
(0028, 1051) Window Width DS: '500.0'
(0028, 1052) Rescale Intercept DS: '0.0'
(0028, 1053) Rescale Slope DS: '1.0'
(0028, 2110) Lossy Image Compression CS: '01'
(0028, 2112) Lossy Image Compression Ratio DS: '8.0'
(0028, 2114) Lossy Image Compression Method CS: 'ISO_15444_1'
(7fe0, 0010) Pixel Data OB: Array of 65286 elements
Using Pydicom 2.3.0.
The text was updated successfully, but these errors were encountered: