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
J2K Pixel Data is not decoded correctly when Pixel Representation doesn't match J2K sign #1149
Comments
Hmm, this is a strange one
I'm a bit curious about the order of operations here, are you using Horos to view the attached dataset or is the dataset already in Horos and exported as the attached dataset? What application performed the compression? |
Very strange one, I agree.
I imported it to Horos and use Horos only to view it. In addition, I was just able to view it through a cornerstone based web viewer (an internal tool we have). I tried to reverse engineer their open source code to see if there's any discrepancy, but I couldn't find any hint yet.
I am not sure. However, (0002, 0013) Implementation Version Name value is 'OFFIS_DCMTK_354'. Could that be DCMTK? I also tried decompressing it manually using their tools but haven't succeeded. |
DCMTK is likely the backend that was used to transfer the dataset. |
Running GDCM's gdcmconv also produces the same (incorrect) output. |
It seems like Horos is taking the unsigned J2K data then applying the 2s complement correction to make signed data in order to match the Pixel Representation. I guess that would make sense if the J2K Ssiz parameter doesn't match the Pixel Representation in the dataset (such as here), but I'm wondering how generalisable that would be. It's interesting, it didn't occur to me to do that under this situation (I have pylibjpeg-openjpeg printing a warning about the mismatch), but it makes sense. I guess we could add config flags to the various handlers to do the conversion automatically. @amirbar is it OK if we add your dataset to our tests? |
In the meantime you can fix it by converting to 2s complement yourself: import numpy as np
import pydicom
from pydicom.pixel_data_handlers.util import apply_voi_lut
from matplotlib import pyplot as plt
ds = pydicom.dcmread("mydcm.dcm")
ds.PixelRepresentation = 0
bit_shift = ds.BitsAllocated - ds.BitsStored
arr = (ds.pixel_array << bit_shift).astype(np.int16) >> bit_shift
ds.PixelRepresentation = 1
vis = apply_voi_lut(arr, ds)
plt.imshow(vis, cmap='gray')
plt.show() |
That's pretty neat! Sure, you can use it. |
BTW, one assumption in the code above is that |
Oh, good point. This should be more general (for cases where there's a mismatch): import numpy as np
import pydicom
from pydicom.pixel_data_handlers.util import apply_voi_lut, pixel_dtype
from matplotlib import pyplot as plt
ds = pydicom.dcmread("mydcm.dcm")
ds.PixelRepresentation = 0
bit_shift = ds.BitsAllocated - ds.BitsStored
arr = ds.pixel_array
ds.PixelRepresentation = 1
dtype = pixel_dtype(ds)
arr = (arr << bit_shift).astype(dtype) >> bit_shift
vis = apply_voi_lut(arr, ds)
plt.imshow(vis, cmap='gray')
plt.show()
No problem! |
Describe the bug
DCM pixel_data is not decoded correctly. The resulting pixels are clearly in the wrong range (see image)
Looking at few interesting dicom tags:
RescaleIntercept = 0
RescaleSlope = 1
PixelRepresentation = 1
BitsStored = 13
HighBit = 12
BitsAllocated = 16
It seems that like based on PixelRepresentation, the data should already be in int16 and the Rescale values imply there shouldn't be any change applied to the input data. However, the resulting values are clearly wrong.
Expected behavior
When loaded using Horos viewer, this is the result (showing default window):
Steps To Reproduce
mydcm.dcm.zip
Unzip the attached dicom and run the following code:
or alternatively,
use
apply_modality_lut
to view the expected HU scale values.Environment
The text was updated successfully, but these errors were encountered: