Johann
Johann

Reputation: 83

Create a Dicom from multiple jpg images

I've successfully built dicoms with one images but I cannot find a way to add more... I think the problem may be in my pixel array, can anyone help me correct it ?

# Populate required values for file meta information
meta = pydicom.Dataset()
meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
meta.MediaStorageSOPClassUID = pydicom._storage_sopclass_uids.MRImageStorage
meta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid()

# build dataset
ds = Dataset()
ds.file_meta = meta
ds.fix_meta_info()

# unknown options
ds.is_little_endian = True
ds.is_implicit_VR = False
ds.SOPClassUID = pydicom._storage_sopclass_uids.MRImageStorage
ds.SeriesInstanceUID = pydicom.uid.generate_uid()
ds.StudyInstanceUID = pydicom.uid.generate_uid()
ds.FrameOfReferenceUID = pydicom.uid.generate_uid()
ds.BitsStored = 16
ds.BitsAllocated = 16
ds.SamplesPerPixel = 1
ds.HighBit = 15
ds.ImagesInAcquisition = "1"
ds.InstanceNumber = 1
ds.ImagePositionPatient = r"0\0\1"
ds.ImageOrientationPatient = r"1\0\0\0\-1\0"
ds.ImageType = r"ORIGINAL\PRIMARY\AXIAL"
ds.RescaleIntercept = "0"
ds.RescaleSlope = "1"
ds.PixelRepresentation = 1

# Case options
ds.PatientName = "Anonymous"
ds.PatientID = "123456"
ds.Modality = "MR"
ds.StudyDate = '20200225'
ds.ContentDate = '20200225'

def ensure_even(stream):
    # Very important for some viewers
    if len(stream) % 2:
        return stream + b"\x00"
    return stream

pixel_data_list = []
for root, dir, filenames in walk(folder):
    filenames.sort(key=natural_keys)
    for filename in filenames:
        filename = folder + filename
        # convert image to grayscale
        img = Image.open(filename).convert('L')
        img.save(filename)

        # open image, decode and ensure_even stream
        with open(filename, 'rb') as f:
            arr = decode(f)

        pixel_data_list.append(arr.tobytes())

# required for pixel handler
ds.BitsStored = 8
ds.BitsAllocated = 8
ds.HighBit = 7
ds.PixelRepresentation = 0

# grayscale without compression
ds.PhotometricInterpretation = "MONOCHROME2"
ds.SamplesPerPixel = 1  # 1 color = 1 sampleperpixel
ds.file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
ds.PixelData = array(pixel_data_list)
ds.NumberOfFrames = len(pixel_data_list)

# Image shape
ds['PixelData'].is_undefined_length = False
ds.Columns = img.width
ds.Rows = img.height

# validate and save
pydicom.dataset.validate_file_meta(ds.file_meta, enforce_standard=True)
new_filename = filename.replace('.jpg', name + '.dcm')
ds.save_as(new_filename, write_like_original=False)

Also can't seem to compress the images, only monochrome works (see tries here https://stackoverflow.com/a/68939321/1827162)... That's not as problematic though, the most important thing is to be able to add multiple images. Thanks for any pointer !

Upvotes: 4

Views: 1363

Answers (1)

scaramallion
scaramallion

Reputation: 1315

Pixel Data should be bytes. If your transfer syntax is uncompressed then you need to concatenate the data together and if the length of the concatenated data is odd then you must add a trailing padding byte:

# For uncompressed transfer syntaxes only!
pixel_data = b"".join(pixel_data_list)
ds.PixelData = pixel_data + b"\x00" if len(pixel_data) % 2 else pixel_data

For compressed transfer syntaxes you must use encapsulation

Upvotes: 2

Related Questions