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')
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 ;)