pythondicompydicom

Create pydicom file from numpy array


I'm trying to create a new dicom image from a standard-sized (512 x 512 or 256 x 256) numpy array.

import dicom, dicom.UID
from dicom.dataset import Dataset, FileDataset

def write_dicom(pixel_array,filename):
    
    file_meta = Dataset()
    ds = FileDataset(filename, {},file_meta = file_meta,preamble="\0"*128)
    ds.PixelData = pixel_array.tostring()
    ds.save_as(filename)
    return

if __name__ == "__main__":
    import numpy as np
    pixel_array = np.tile(np.arange(256).reshape(16,16), (16,16)) * 4
    write_dicom(pixel_array,'pretty.dcm')

Solution

  • I was able to reduce @Corvin's great answer even more. Here is a minimalist code example allowing one to save a (dummy) 3D numpy array to a valid DICOM image that can be opened with Amide:

    #!/usr/bin/python3
    import numpy
    import pydicom
    import pydicom._storage_sopclass_uids
    
    # dummy image
    image = numpy.random.randint(2**16, size=(512, 512, 512), dtype=numpy.uint16)
    
    # metadata
    fileMeta = pydicom.Dataset()
    fileMeta.MediaStorageSOPClassUID = pydicom._storage_sopclass_uids.CTImageStorage
    fileMeta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid()
    fileMeta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
    
    # dataset
    ds = pydicom.Dataset()
    ds.file_meta = fileMeta
    
    ds.Rows = image.shape[0]
    ds.Columns = image.shape[1]
    ds.NumberOfFrames = image.shape[2]
    
    ds.PixelSpacing = [1, 1] # in mm
    ds.SliceThickness = 1 # in mm
    
    ds.BitsAllocated = 16
    ds.PixelRepresentation = 1
    ds.PixelData = image.tobytes()
    
    # save
    ds.save_as('image.dcm', write_like_original=False)
    

    As one might observe, a lot of fields are missing if the output image.dcm file is passed to dciodvfy. The filling of these fields is left to the reader ;)