The Slice view is of different intensity than the actual object

Operating system: Linux Centos
Slicer version: 4.11
Expected behavior: I am trying to view the tooth. The 3D slicer loads the slice views with the intensity shown in the first image. As you can see the slice images for R, G and Y loaded in 3D slicer shows a unexpected black(dark) shaded region at the corner regions of the tooth.
Actual behavior: The same set of dicom files loaded with other softwares such as Matlab or Dicom Browser on same OS loads the slices with accurate intensity across the whole tooth as shown in the second, third and fourth image, with white(bright) color corners. It is also to be noted that every other region of slice, loaded with any software including 3d Slicer has matching intensity, for example, areas in the background, central gray region of the tooth and the region at the middle.

I wanted to understand why is there an intensity difference in 3D slicer and that too only at the specified area, which is the boundary region, and everything else is looking fine.
I would highly appreciate if someone could guide or point to something that I might change or tweak in any of the module to load my images with correct intensity in 3D slicer as well.

Thanks,
Pranay
3Dslicer_image
matlab_image1
matlab_image2
matlab_image3

Where does the data come from, what format is it in, and what method do you use to load it in Slicer?

That looks like an overflow or data type error. If you load a image data as signed integers when they are supposed to be unsigned integers this kind of error can happen. For example, an unsigned 8-bit voxel can store values 0-255 (0 to 2^8-1), whereas a signed 8-bit voxel stores values -128 to 127 (-2^7 to 2^7-1). The way itā€™s set up, values 0 to 127 are represented the same way whether the representation is signed or unsigned, so any gray values in that range look the same even if you use the wrong interpretation. However, the representation for unsigned 128 is the same as the representation -128 (I think) for the signed version (because the leading bit is interpreted as indicating the sign instead of indicating a larger value). The representation for unsigned representation 129 would then be -127, and so forth. So, voxel values which are greater than a threshold of 127 would suddenly look black because they would be interpreted as negative values. For 16-bit voxels, the threshold would be 32,767 (2^15-1, values greater than this become negative numbers when interpreted as signed).

Iā€™ve seen things like this happen before with CT images with sharpening filters or metal artifacts which pushed some voxel values above the normal range of values and very dense areas turned black because the imaging software assumed signed integers and the values were actually supposed to be interpreted as unsigned integers.

This problem could arise by 1) the file you are loading from being ambiguous about whether values are signed or unsigned, or 2) because the loading software makes the wrong assumption, or 3) because the wrong values were stored originally because of a calculation overflow error. In the first case, Slicer would need an adjustment to a heuristic or input from you to do the right thing; In the second case, Slicer might have a bug in interpreting a properly specified input or the input might not be properly specified (and the other software you use makes a beneficial assumption for your case). In the third case, Slicer is doing the correct thing, and you need to fix your data (which is easy, just add 32,768 to any negative number and store as 16 bit unsigned instead of 16 bit signed).

Hi, Thanks for the reply.
The data is CT scan of our samples that was performed by a local lab in India.
The format is Dicom. I loaded it in Slicer using GUI asā€¦
Module > DICOM > Import Dicom files > then I imported the dicom directory from my system.
To load it, I used, Module > DICOM > Show Dicom database > then clicked on above imported database and click load tab.
Thatā€™s the same way the documentation teaches.
Then I can view all my slices as usual, or do volume rendering and everything. But couldnā€™t fix the problem stated in the question.

If thereā€™s something wrong with the way to load or any further information required, kindly let me know.

Thanks,
Pranay

Hi, Thank you so much for replying back.

I gave a thought about the possibilities you suggested, indeed it could be one of the problems you mentioned. Thanks for shedding the light on that. I would like to mention a few more things:
I was analyzing the slices in numpy array to see the pixel values, I couldnā€™t find any negative values in the array, suggesting that the values are unsigned.
Also, when I analyzed the pixel values of same slice, exported via matlab, I noticed that there was a difference, For example, for gray region in the middle, in the matlab image, a pixel that has the intensity value of around say, 150. The same pixel in the image exported by 3D slicer will have the intensity of 150-127(=23) at that very location.

What could probably serve as a great convenience for me is, if thereā€™s a way in 3D slicer where I can specify the data type(signed or unsigned) while loading the dicom files. If thereā€™s an assumption made by the 3D slicer itself, I would like to override that assumption by explicitly specifying the correct data type. I couldnā€™t find any settings for that. If itā€™s there It would be lot helpful if you could point out the module.
Even if thereā€™s any additional observation you could make by above points, I would love to hear.

Thanks,
Pranay

If you have a data set which shows this issue without patient information (either a non-patient scan or a patient scan where all identifying information has been removed) that you can share, that would be helpful for figuring out what exactly is happening.

Sure, Iike I can share a couple of my DICOM files, if you load in 3D slicer, you would be able to view the Axial view of the tooth as I posted in the screenshot in the question, with black colored corners. I hope that serves the purpose, let me know for the additionals.

here are they -
https://drive.google.com/drive/folders/1EnEGzXneSd4remUXUkFI0yBFHdWZl0Bw?usp=sharing

Thanks,
Pranay

Also, this is metadata information given by 3D slicer

Tag Attribute Value VR Length
[0008,0005] SpecificCharacterSet ISO_IR 100 CS 10
[0008,0016] SOPClassUID 1.2.840.10008.5.1.4.1.1.7 UI 26
[0008,0018] SOPInstanceUID 2.25.296958948774992279876467636149074931855 UI 44
[0008,0021] SeriesDate 20210122 DA 8
[0008,0031] SeriesTime 153256 TM 6
[0008,103e] SeriesDescription LO 0
[0010,0010] PatientName Unspecified Patient PN 20
[0010,0020] PatientID 2.25.277744876348196707507775220078483990376 LO 44
[0020,000d] StudyInstanceUID 1.2.276.0.7230010.3.1.2.568124770.6912.1611309776.784 UI 54
[0020,000e] SeriesInstanceUID 2.25.42204707247853066808077597454226435009 UI 44
[0020,0011] SeriesNumber 1 IS 2
[0020,0013] InstanceNumber 1 IS 2
[0020,0032] ImagePositionPatient [3] -7.591317, -54.826260, -8.552629 DS 30
[0020,0037] ImageOrientationPatient [6] 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000 DS 54
[0028,0002] SamplesPerPixel 1 US 2
[0028,0004] PhotometricInterpretation MONOCHROME2 CS 12
[0028,0010] Rows 1024 US 2
[0028,0011] Columns 1000 US 2
[0028,0030] PixelSpacing [2] 0.015527, 0.015527 DS 18
[0028,0100] BitsAllocated 16 US 2
[0028,0101] BitsStored 15 US 2
[0028,0102] HighBit 14 US 2
[0028,0103] PixelRepresentation 0 US 2
[0028,1050] WindowCenter 29157 DS 6
[0028,1051] WindowWidth 58314 DS 6
[0028,1052] RescaleIntercept 0.000 DS 6
[0028,1053] RescaleSlope 1.000 DS 6
[7fe0,0010] PixelData 0000 OW 2048000

Thanks for sharing. I can confirm that I see that same phenomenon as you where the densest areas inappropriately show up with low pixel values. The images you shared are clearly not directly off the scanner and appear to have been processed using DCMTK, perhaps because that is how you anonymized them? When I look at these files with non-Slicer DICOM readers, they show the same problem as shown in Slicer, is that the case for you also?

However, where I expected that the dark areas would have large negative pixel values (high unsigned voxel values being reinterpreted as large negative signed voxel values), I instead see small positive voxel values. I still think itā€™s highly likely that the problem is related to misinterpreted binary values somewhere in the processing chain, but Iā€™m not sure how much more Iā€™ll be able to help you. This is supported by the highest pixel values in the images being exactly 32767, implying that the adjacent dark areas are probably values that crossed the 2^16 threshold and were misinterpreted.

I think you are looking in the right areas to get this figured out. I would examine the DICOM header for the original files and see if there is anything which changes or is illuminating in the BitsAllocated, BitsStored, HighBit, PixelRepresentation, RescaleIntercept, or RescaleSlope fields. Slicer wonā€™t change the header at all on import, so you can safely do the examination in Slicer. If MATLAB is your other tool, Slicerā€™s DICOM processing is usually better than MATLABā€™s, so there is definitely a chance that Slicer is respecting the DICOM header in a way that MATLAB is not, and there is a problem or inconsistency in the original DICOM file. You might also try another DICOM tool to take a look at the original images (MicroDicom viewer on Windows or Osirix on Mac) and see how they look there.

Good luck going forward!

Thaks alot Mike, thatā€™s really helpful analysis.

I used 2 softwares, matlab and Dicom browser, but I didnā€™t see the problem there as shown in 3d slicer. I have posted matlabā€™s output in the question.
I am curious to know which software did you use where you found the same problem as shown by 3D slicer.

I was thinking of trying 2 methods for my problem, first was to try loading the dicom files in another format, like first converting the Dicom files into .nrrd format. Itā€™s just one of the many formats supported by 3d slicer to load the data, then I will load the nrrd files to see if the problem still exists.
The second approach would be yet another file format supported by 3D slicer, which is ā€˜raw volumeā€™ format (.raw), according to the documentation, it requires manual setting of header parameters. I am hoping i can manually supply the right parameters about the data via this approach.

Thanks alot for narrowing down my suspicion about the problem. I will see if above mentioned things work out.

Best,
Pranay

I used https://www.microdicom.com/ as the outside DICOM viewer, where your uploaded anonymized image looked like this:
image

However, I just tried the same image using MATLABā€™s dicomread(), and it shows in MATLAB like this:

Slicerā€™s ā€œVolumesā€ module shows the ā€œScalar Typeā€ of this image as ā€œunsigned shortā€, which is the same as 16 bit unsigned integer. MATLAB shows the loaded image data type as ā€œuint16ā€, which is also 16 bit unsigned integer. However, comparing the exact same voxel (755, 414) in each gives, 11919 in Slicer and 43995 in MATLAB. Iā€™m a bit baffled by this.

OK, hereā€™s a theory: The DICOM header says that 16 bits are allocated per pixel, but that only 15 bits actually store image information (and that the high bit is bit 14, which I think means that the 15th bit is related to the sign). However, I think MATLAB is ignoring this, and reading each pixel as a 16bit number. It must be, because the largest 15 bit number is 32767 (2^15-1), and 43995 is larger than this. Slicer, on the other hand, is ignoring the value in the 16th bit (which is what the DICOM standard says should be done) and only reading the remaining 15 (or 14, Iā€™m not sure which because the 15th bit for 43995 would be 0). If I try dropping the 16th bit from the binary representation for 43995, I get 11227, which is pretty close to the values in Slicer, but not an exact match. Wait, just remembered that MATLAB indexing is 1-based, and Slicer indexing is 0-based, so the matching voxel index for (755, 414) in MATLAB would be (754, 413) in Slicer! And there, the voxel value is 11227, exactly 2^16 less than 43995! So, I think this must be whatā€™s going on.

To summarize:

  • The DICOM header is incorrect
    • While it says that there are only 15 bits of image data in each pixel, there are in fact 16 bits of image data
  • MATLAB very likely ignores this in the DICOM header, just reading that 16 bits are allocated to each pixel value, and then loading the pixel data as 16 bit unsigned integers
  • Slicer, following the DICOM standard, ignores the 16th bit as the header indicates it should

I think the correct fix for you is to fix the DICOM headers of your images so that BitsStored is 16 and the HighBit is 15 (it looks to me in DICOM reference info that the HighBit is now always supposed to be one less than BitsStored). I think then they will load correctly in both Slicer and MATLAB.

1 Like

Hi Mike,

I would like to say a huge thanks to you for generously guiding me to the solution.
I looked at the meta and understood the point you raised, finally as what you suggested I corrected the dicom header using pydicom and saved it again.
Loaded the corrected dicom files in 3D slicer and the problem was fixed finally.

Thanks alot for that. :grin:
Regards,
Pranay

1 Like

Great! Iā€™m glad we figured it out and itā€™s working for you now.

Best wishes,
Mike

1 Like