Does readImageDICOMFileSeries handle uint16 encoded dicoms?

Hello,
I am using readimageDICOMFileSeries with the code as below. Everything worked perfectly when I had dicoms with data in UINT8 arrays. When I tested it with images with intensity values more than 255, I also received object with data encoded with 8 bytes, i.e.
{
“dimension”: 3,
“componentType”: “uint8_t”,
“pixelType”: 1,
“components”: 1
}
and all the points with intensity over 255 (as i checked in ITK-snap) were having wrong values (see pictures below).

My code for reading series :

              function(extractedFiles) {
                                    files= extractedFiles.map((el)=>{return new File([el.buffer],el.name)});
                                    itkreadImageDICOMFileSeries(null, files)
                                        .then(({ image: itkImage, webWorker }) => {
                                    console.log(itkImage.imageType) // result as above                                             
                                    const vtkImage = vtkITKHelper.convertItkToVtkImage(itkImage);
                                   //...ctd
                                        })
                                        .catch((err)=>{
                                            console.log(err);
                                            dispatch(errorFunc("Can't read ITK",imageId))});
                                },
                    }

How can I handle different encoding?
Thank you for help
Andrzej

obraz

MR images are normally 16-bit, and ITK handles that well. I think the problem is in vtkITKHelper.convertItkToVtkImage which converts and ITK image into a VTK one. It is probably forcing 8-bit output.

readimageDICOMFileSeries usually works fine with 16-bit DICOMs, but this may be one of the many DICOM corner cases.

readimageDICOMFileSeries is using ITK/DCMTK under the hood: you could try readImageFile with one of the DICOM slices, which is using ITK/GDCM like ITK-SNAP, to understand if the issue is in ITK/DCMTK.

Thank you guys for suggestions,
@dzenanz, I think that the problem occurs before vtkITKHelper.convertItkToVtkImage , since I have found 16-bit dicom series where everything works perfect. In these cases, image type returned by readingDICOMFileSeries is as follows:
{
“dimension”: 3,
“componentType”: “uint16_t”,
“pixelType”: 1,
“components”: 1
}
The problem is that for some reasons for a chosen 16-bit dicom series, the improper type, ie. "componentType": "uint8_t" is returned by readingDICOMFileSeries.
So I think Matt is right that the problem is related more to “DICOM corner cases”. BTW, all these image series are read by ITK-SNAP properly. Probably I will have to look more closely to differences in headers. I will appreciate if you have any suggestions about that.
Thanks
Andrzej

1 Like

Hi Matt ,

I just checked with 3Dslicer and ITK-Snap two different series of dicoms:

  • one which is read correctly by itkreadImageDICOMFileSeries,
  • one read incorrectly.
    Both series were done on the same station, by the same person for the same patient.

They have many identical attributes (images are coregistered), eg.
[0008,0022] AcquisitionDate 20130523 DA 8
[0008,0023] ContentDate 20130523 DA 8
[0008,0060] Modality MR CS 2
[0008,0070] Manufacturer SIEMENS LO 8
[0018,0023] MRAcquisitionType 3D CS 2
[0018,1000] DeviceSerialNumber 35436 LO 6
[0018,1020] SoftwareVersions syngo MR B17 LO 12
[0020,1040] PositionReferenceIndicator LO 0
[0020,1041] SliceLocation -86.748882811953 DS 16
[0028,0002] SamplesPerPixel 1 US 2
[0028,0004] PhotometricInterpretation MONOCHROME2 CS 12
[0028,0010] Rows 256 US 2
[0028,0011] Columns 256 US 2
[0028,0030] PixelSpacing [2] 1, 1 DS 4
[0028,0100] BitsAllocated 16 US 2
[0028,0101] BitsStored 12 US 2
[0028,0102] HighBit 11 US 2
[0028,0103] PixelRepresentation 0 US 2
[0028,0106] SmallestImagePixelValue 0 US 2
[0028,1055] WindowCenterWidthExplanation Algo1 LO 6
[0029,0010] PrivateCreator SIEMENS CSA HEADER LO 18
[0029,0011] PrivateCreator SIEMENS MEDCOM HEADER2 LO 22
[0029,1008] CSAImageHeaderType IMAGE NUM 4 CS 12
[0029,1009] CSAImageHeaderVersion 20130523 LO 8

Differences are (apart from series name and sequence info):

The one read properly (MPRAGE), has the following attriutes:
[0018,0020] ScanningSequence [2] GR, IR CS 6
[0018,0021] SequenceVariant [2] SP, MP CS 6
[0018,0022] ScanOptions IR CS 2
[0018,0095] PixelBandwidth 130 DS 4
[0018,1310] AcquisitionMatrix [4] 0, 256, 256, 0 US 8
[0028,0107] LargestImagePixelValue 271 US 2
[0028,1050] WindowCenter 50 DS 2
[0028,1051] WindowWidth 139 DS 4

The bad one (T2):
[0018,0020] ScanningSequence SE CS 2
[0018,0021] SequenceVariant [2] SK, SP CS 6
[0018,0022] ScanOptions PFP CS 4
[0018,0095] PixelBandwidth 751 DS 4
[0018,1310] AcquisitionMatrix [4] 0, 256, 262, 0 US 8
[0028,0107] LargestImagePixelValue 31 US 2
[0028,1050] WindowCenter 21 DS 2
[0028,1051] WindowWidth 52 DS 2

Is it possible that ImageIO.worker.js is misleaded by one of these parameters?
IMHO, value of LargestImagePixelValue is strange in both cases (which I was checking with ITK-SNAP which was showing me 391 in first case and 32 in second,
but in both images I found pixels with values greater than 400). BTW, both are displayed properly by ITK-SNAP.
What happens if the first dcm in series has different params than others?
Is it possible that I could solve this problem by myself?

I checked files in “bad” series with readImageFile and seems that about more than half of them is encoded with uint8 and the rest with uint16.

Best regards and thank you
Andrzej Marciniak

1 Like

If the first file in the series is encoded as uint8, that would explain the behavior. Series reader takes most information from the first file.

LargestImagePixelValue might be per file (per slice) information. Most image readers ignore the value, as it can be recomputed and is not always reliable.

1 Like

itk/readImageDICOMFileSeries is using itk::ImageSeriesReader:

So, the fix for this could happen there. @Andrzej_Marciniak, the best approach would anonomize a subset of the series for a test case, and create a patch for ITK. We can then backport it to itk.js.

@agirault