0

I'm working with multiple DICOM files, most of which are vastly different pixel wise. For example one ranges from -1024 to 2815 and another ranges from 0 to 2378. Is there a way to standardise them all into the same range. Also to note I'm utilising python and the pydicom library. Thanks in advance.

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141
Faffy
  • 63
  • 1
  • 9
  • You can artificially convert them to an arbitrary range but you're going to lose information. If that's acceptable what sort of range would you want? I.e. unsigned 8-bit, signed 16-bit, etc. – scaramallion Mar 13 '20 at 21:55
  • Any range will really do, if I were to specify maybe -1024 to 1024, though again any will really do – Faffy Mar 13 '20 at 22:11
  • Is using the raw pixel values fine or do you need to convert to a unit quantity (like HU or SUV) first? – scaramallion Mar 13 '20 at 22:14
  • As fair as I'm aware the dicom arrays are already in HU values, correct me if I'm wrong there. If not then HU values would be prefered as long as they are in all the same range, otherwise raw pixel values will be alright – Faffy Mar 13 '20 at 22:28
  • 1
    Technically they aren't, but if RescaleSlope is 1 and RescaleIntercept is 0 then the conversion to HU is already done. Speaking generally of course there's no way to guarantee that – scaramallion Mar 13 '20 at 22:33
  • I've played about with windowing the image, as we've spoken, and ensure that the width and center are 80 and 40, this produces the range 0 to 80. Would you suggest this? – Faffy Mar 13 '20 at 22:56
  • Windowing is a separate issue. This all comes back to what your intention is; are you interested in analysing the data in a specific quantity such as HU (in which case no windowing should be applied) or are you interested in analysing the way it was *viewed* by someone (windowing needed, but there can be multiple *views* and hence multiple windows). – scaramallion Mar 13 '20 at 22:59
  • I'm interested in the HU values, I've also tried the your solution though I get an error. module 'pydicom.pixel_data_handlers.util' has no attribute 'apply_modality_lut', I'm running pydicom version 1.4.2 – Faffy Mar 13 '20 at 23:24
  • Weird, I have no explanation for that. [API link](https://pydicom.github.io/pydicom/stable/reference/generated/pydicom.pixel_data_handlers.util.html#pydicom.pixel_data_handlers.util.apply_modality_lut) shows it should be `pydicom.pixel_data_handlers.util.apply_modality_lut`. You're sure its 1.4.2? Also: [source code is here](https://github.com/pydicom/pydicom/blob/2e4a511a/pydicom/pixel_data_handlers/util.py#L187) – scaramallion Mar 13 '20 at 23:26
  • I'm using 1.4.2, I've sorted it but now have a new issue. 'FileDataset' object has no attribute 'RedPaletteColorLookupTableDescriptor', I've looked at the info retrieved from the DICOM and its not there. – Faffy Mar 13 '20 at 23:36
  • How are you even getting that? Are you using `apply_color_lut()`? But even then you shouldn't be getting an error anyway. What's the full traceback on that one? – scaramallion Mar 13 '20 at 23:37
  • Here it is:Traceback (most recent call last): File "g:\test.py", line 7, in hu = util.apply_color_lut(arr, ds) File "C:\Users\..\AppData\Local\Programs\Python\Python37\lib\site-packages\pydicom\pixel_data_handlers\util.py", line 117, in apply_color_lut lut_desc = ds.RedPaletteColorLookupTableDescriptor File "C:\Users\..\AppData\Local\Programs\Python\Python37\lib\site-packages\pydicom\dataset.py", line 783, in __getattr__ return object.__getattribute__(self, name) AttributeError: 'FileDataset' object has no attribute 'RedPaletteColorLookupTableDescriptor' – Faffy Mar 13 '20 at 23:40
  • Yeah, that's a bug, but you don't need `apply_color_lut()` if you're working with CT data. – scaramallion Mar 13 '20 at 23:41
  • My apologise, I've just realised that I'm using the wrong function – Faffy Mar 13 '20 at 23:41
  • Ok so the range is now what I want it to be, thank you for sticking around and helping. – Faffy Mar 13 '20 at 23:46

1 Answers1

4

If you're dealing with the same IOD for all your data (e.g. CT Image) and the image data is already in HU (and to be certain of this you can use the apply_modality_lut() function in pydicom):

from pydicom import dcmread
from pydicom.pixel_data_handlers.util import apply_modality_lut

ds = dcmread('filename.dcm')
arr = ds.pixel_array  # Raw unitless pixel data 
hu = apply_modality_lut(arr, ds)  # Pixel data has been converted to HU (for CT)

Then your data is already in a specific quantity (namely HU). To convert to a specific range then just means deciding what to do with values outside your chosen range:

import numpy as np
# Clip values outside the range to the min/max of the range
clipped_hu = np.clip(hu, -1024, 1024)

Of course this means any clipped pixels should no longer be considered an accurate representation of your input data.

Rescale vs Windowing

I'm going to add a bit of an explanation about the difference between rescaling DICOM data and windowing it.

Imagine you have two rulers, one in cm and one in inches. You apply the DICOM rescale operation to both - in pydicom you use apply_modality_lut() - and you'll get back two rulers in cm. Now you can use your rulers to measure stuff and you'll get the same values back from both, neat!

Now you take your rulers and apply the same DICOM windowing operation to both. The windowing operation is a bit less analogy friendly, in essence you're taking a small window of your rulers (say the section from 10 to 12 cm) and stretching it to be the same length as the entire ruler was beforehand. Your rulers are no longer in cm and can't be used to measure stuff, but perhaps by expanding that section you see some detail that wasn't obvious before (like a tumour). The other nice thing about applying the same rescale + windowing operations to both is that you can still meaningfully compare your two rulers against each other because they've both been stretched the same amount.

So the rescale operation is all about converting raw data to a quantity to allow direct intercomparison while the windowing operation is about visualising something. If you want to know the highest density region of a CT scan you'd use a rescale operation with no windowing. If you want to see what a radiologist saw when writing their report, you'd apply both rescale and windowing operations.

scaramallion
  • 1,251
  • 1
  • 6
  • 14