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

Transform uint16 to float32 Dicom #1077

Closed
maveLC opened this issue Apr 17, 2020 · 5 comments
Closed

Transform uint16 to float32 Dicom #1077

maveLC opened this issue Apr 17, 2020 · 5 comments
Labels

Comments

@maveLC
Copy link

maveLC commented Apr 17, 2020

Hi all,

I want to transform uint16 to float32 Dicom. This test seems simple, but in reality I want to do some calculations on it and after whrite it in float32, to not loose data. I do not arrived to save it, so I decide to have a more simple test, read, transform and save it. I have done a lot of tests, each on two cases :

  • First, I read the initial uint16 Dicom, transform it and save it. But, if I read the documentation, PixelData may have to manage the float array. But it seems it is not the case, the image is wrong, all white, visualy with wrong data inside... So I decide to work with FloatPixelData, alone, but I have an error that says it need data in PixelData. Okay,I set both, the PixelData contains the float32 in bytes and the FloatPixelData the float32 (flatten then listed, only way do not have an error about the type), but the final image is visualy wrong, all white.
  • So I decide to test with this second way : I try to create a new dicom and so a new ds object. I have set the minimum (maybe some tags are missing ? or wrong ? or too much ?). I set the PixelData only, I have a result, close to the original, not the same, and I cannot check values (see bellow why). If I set only FloatPixelData, no error, but I can read the Dicom with another soft ... If I set the both, the result is similar to set only PixelData.

To visualize the result, first I have used Image J, but float value are very wird. If I put the same array if txt image and read raw data, data are okay. If I save like a tiff, data are okay too. But ImageJ seems do not manage float value for dicom (and @scaramallion confirm it in a post). I decide to try with MicroDicom, but the original image is not right visualy and I cannot see values... And tiff image is wrong (and right with image j) Maybe, it is because of the dicom reader, I do not know ...

Following, you will find the code :

`
first_ds = pydicom.dcmread(os.path.join(firstDicomDir,filename))
first_array = first_ds.pixel_array.astype(np.float32)

        ##only for second option to initialize the new ds object##
        meta = Dataset()
        meta.MediaStorageSOPClassUID = first_ds.file_meta.MediaStorageSOPClassUID
        meta.MediaStorageSOPInstanceUID = first_ds.file_meta.MediaStorageSOPInstanceUID
        meta.TransferSyntaxUID = "1.2.840.10008.1.2"#first_ds.file_meta.TransferSyntaxUID
        
        ds = FileDataset(os.path.join(dicomPath,filename), {}, file_meta=meta, preamble=None)
       ####
       ##From here, this test is with new ds, but tests are also done with first_ds
        ds.is_little_endian = True
        ds.is_implicit_VR = True
        ds.BitsStored = 28
        ds.BitsAllocated = 32
        ds.SamplesPerPixel = first_ds.SamplesPerPixel
        ds.HighBit = 27
        ds.Rows = first_array.shape[0]
        ds.Columns = first_array.shape[1]
        first_ds.SmallestImagePixelValue = int(round(first_array.min()))
        first_ds[0x00280106].VR = 'US'
        first_ds.LargestImagePixelValue = int(round(first_array.max()))
        first_ds[0x00280107].VR = 'US'
        ds.PixelRepresentation = 0

        ds.PixelData = first_array.tobytes()
        ds.FloatPixelData = first_array.flatten().tolist()

        ##I have tried to way to save it, same result
        #first_ds.save_as(os.path.join(dicomPath,filename),False)
        pydicom.dcmwrite(os.path.join(dicomPath,filename), ds, False)

`
@scaramallion, I have tried your fixif I take the original dicom and chaging this line ds.FloatPixelData = first_array.flatten().tolist() by ds.FloatPixelData = first_array.tobytes(), I have this error: AttributeError: Unable to convert the pixel data: one of Pixel Data, Float Pixel Data or Double Float Pixel Data must be present in the dataset. For the new dicom, the result is not changing with the last version, visualy, but like I have written, I do not know if it is the external reader.

@scaramallion
Copy link
Member

scaramallion commented Apr 19, 2020

  1. It's non-conformant to have both Pixel Data and Float Pixel Data in a dataset. The Dataset.pixel_array() property assumes that you have one and only one of the pixel data containing elements. This is why you're getting an exception which literally says (my emphasis)

    Unable to convert the pixel data: one of Pixel Data, Float Pixel Data or Double Float Pixel Data must be present in the dataset

    If you still want to have a dataset with both then you have to delete one before calling pixel_array

  2. It's non-conformant to have float data in Pixel Data. No third-party application will display it correctly.

  3. I was wrong about ImageJ, newer versions like 1.52s should be able to handle Float Pixel Data

The following should work (but the file will be non-conformant because it doesn't meet the IOD):

from pydicom import dcmread
from pydicom.data import get_testdata_file
from pydicom.uid import ImplicitVRLittleEndian

# Original int16 data
ds = dcmread(get_testdata_file("CT_small.dcm"))
arr = ds.pixel_array
ds.FloatPixelData = arr.astype('float32').tobytes()

# Workaround for issue 1075
ds.file_meta.TransferSyntaxUID = ImplicitVRLittleEndian
ds.is_implicit_VR = True
ds['FloatPixelData'].VR = 'OB'

ds.BitsAllocated = 32
ds.BitsStored = 32
ds.HighBit = ds.BitsStored - 1
del ds.PixelData
ds.save_as('float32.dcm')

@maveLC
Copy link
Author

maveLC commented Apr 23, 2020

@scaramallion thank you for all, now I have my image, with write values and with a good visualization !

@maveLC maveLC closed this as completed Apr 23, 2020
@FabianaMorais
Copy link

Hello @scaramallion ,
I’m trying to develop an algorithm to save/write array of data in dicom format. I have two type of data: int16 and uint23 and my greatest difficulty is with the last one.
When I open them with dicom viewers (Microdicom, Amide, Radiant,….) I only obtain a black screen or an error message that said: “the file is generated wrongly”.
I used the validation tool developed by David Clunie to check the dicom header, however I’ obtneid errors message about Bits Stored and Bits Allocated value that can not be 32…
So my doubts is about pixel data types supported by Dicom viewers. Is the maximum bit depth is 16?
Regards
Fabiana

@mrbean-bremen
Copy link
Member

mrbean-bremen commented Dec 22, 2020

The maximum bit depth for image data is indeed 16, meaning grayscale images. The bit depth of RGB images is always 8 bit (with 3 channels). There are other kinds of data (not image data) that use OF (e.g. float data as mentioned in this issue) that will take 32 bit, but these will not be displayable by DICOM image viewers. What kind of image data are you trying to write?

@FabianaMorais
Copy link

FabianaMorais commented Dec 23, 2020 via email

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

4 participants