I am trying to take in an RGB fMRI scan as input and output the same scan but in grayscale with the color parts "burned" white essentially.
Whenever I try and modify any of the Data Elements, such as Photometric Interpretation and Samples Per Pixel, and use save_as
to write the new DICOM file, I am unable to open that DICOM scan with the DICOM viewer giving me the error that it isn't a DICOM image.
My code is below.
import pydicom
from pydicom import dcmread
import numpy as np
#function to turn RGB array to grayscale array
#uses dot product of matrices
def rgb2gray(rgb):
fil = [0.299, 0.587, 0.144]
return np.dot(rgb, fil)
ds = pydicom.dcmread("dicom file")
arr = ds.pixel_array
gray_arr = rgb2gray(arr)
#gray_arr = ds.pixel_array[:,:,0]
#Have to change meta tag information when working with dicom images
ds.PhotometricInterpretation = "MONOCRHOME2"
ds.SamplesPerPixel = 1
ds.BitsAllocated = 16
ds.BitsStored = 16
ds.HighBit = 15
del ds.PlanarConfiguration
ds.is_little_endian = True
ds.fix_meta_info()
ds.PixelData = gray_arr.tobytes()
ds.save_as('fMRI.dcm', write_like_original=False)
The main problem is that your array has the wrong type - it is float instead of byte, so what is saved to the pixel data is a byte representation of float values (which are 4 bytes each). Also, you are setting BitsAllocated
to 16, meaning that you expect 2 bytes per pixel, but in your computation you only have a byte range, e.g. you need only 8 bits per pixel.
Lastly, you had a typo in PhotometricInterpretation
("MONOCRHOME2" instead of "MONOCHROME2").
Here is a possible solution, that converts the float array to a byte array:
from pydicom import dcmread
from pydicom.uid import generate_uid
import numpy as np
def rgb2gray(rgb):
fil = [0.299, 0.587, 0.144]
return np.dot(rgb, fil)
ds = pydicom.dcmread("dicom file")
arr = ds.pixel_array
gray_arr = rgb2gray(arr).round().astype(np.uint8)
ds.PhotometricInterpretation = "MONOCHROME2"
ds.SamplesPerPixel = 1
ds.BitsAllocated = 8
ds.BitsStored = 8
ds.HighBit = 7
ds.PixelRepresenation = 0
ds.SOPInstanceUID = uid.generate_uid()
del ds.PlanarConfiguration
ds.is_little_endian = True
ds.fix_meta_info()
ds.PixelData = gray_arr.tobytes()
ds.save_as('fMRI.dcm', write_like_original=False)
A few notes:
PixelRepresentation
to show that these are unsigned valuesSOPInstanceUID
, otherwise the original image would be overwritten by the derived one in a PACS viewerImageType