1

I have a DICOMDIR file with a lot of dcm files in it. I have extracted the .dcm file with Instance Number 1. It has 49 slices/frames. I wnat to convert those frames into an mp4 format. My code gives and output but the video is still and has a yellow hue overlayed over the video. How can I resolve this.

import numpy as np
import pydicom
import os
import cv2

dicomdir_path = 'dcm_files/DICOMDIR'
dicomdir = pydicom.dcmread(dicomdir_path)

record = None
for record in dicomdir.DirectoryRecordSequence:
    if record.DirectoryRecordType =='IMAGE' and record.InstanceNumber == 1:
        break

filename = os.path.join(os.path.dirname('dcm_files/DICOMDIR'), record.ReferencedFileID[1])
ds = pydicom.dcmread(filename)

num_frames = ds.NumberOfFrames

pixel_data = ds.pixel_array

if len(pixel_data.shape) > 2:
    pixel_data = pixel_data[0]

pixel_data = cv2.normalize(pixel_data, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
print(pixel_data.shape)

num_rows, num_cols, _ = pixel_data.shape

pixel_data = pixel_data.reshape((num_rows, num_cols, 3))
pixel_data = [pixel_data] * num_frames
pixel_data = np.array(pixel_data)

print(pixel_data.shape)

fourcc = cv2.VideoWriter_fourcc(*"mp4v")
fps = ds.CineRate
video_writer = cv2.VideoWriter('Output/output.mp4', fourcc, fps, (num_cols, num_rows))

for i in range(num_frames):
    frame = pixel_data[i]
    if len(frame.shape) == 2:
        frame_bgr = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
    else:
        frame_bgr = frame
    video_writer.write(frame)

video_writer.release()
  • Why is `frame_bgr` never used? Shouldn't that be written instead of `frame`? – B Remmelzwaal Feb 28 '23 at 01:42
  • @BRemmelzwaal the `frame_bgr` is used only when the `frame.shape` has more than 2 slices. So the code gives the same output. I would like to know how I can include all 49 slices as the original `pixel_data` size is (49, 600, 800, 3) – user2381342 Feb 28 '23 at 01:50
  • I think it has something to do with this line `if len(pixel_data.shape) > 2:...` I jsut can't figure out the correct code for it – user2381342 Feb 28 '23 at 01:59
  • `pixel_data = pixel_data[0]` sets `pixel_data` to be only the first frame. Whats the Photometric Interpretation? Is it greyscale, RGB or YBR? If it's RGB/YBR then your pixel data will have shape (frames, rows, columns, planes). – scaramallion Feb 28 '23 at 03:18
  • @scaramallion the Photometric Interpretation is YBR_FULL_422. So the pixel data shape is (49, 600, 800, 3). – user2381342 Feb 28 '23 at 22:28
  • I got one way to do this. Extract images from the dcm file and then convert them into a video. In doing so, I get a greenish-blue hue overlayed over the video. Any idea how to get the original color. I tried converting to YCbCr format but the result was same – user2381342 Mar 01 '23 at 01:07

1 Answers1

1

Finally got it. OpenCV has the option to convert dicom files with Photometric Interpretation YBR_FULL_422 to RGB using cv2.COLOR_YUV2RGB. Below is the finalised code

from glob import glob
import pydicom
import os
import cv2
from PIL import Image
import re
import numpy as np

# Load the DICOMDIR file
dicomdir_path = 'dcm_files/DICOMDIR'
dicomdir = pydicom.dcmread(dicomdir_path)

record = None
for record in dicomdir.DirectoryRecordSequence:
    if record.DirectoryRecordType =='IMAGE' and record.InstanceNumber == 1:
        break

filename = os.path.join(os.path.dirname('dcm_files/DICOMDIR'), record.ReferencedFileID[1])
ds = pydicom.dcmread(filename)
# print(ds)
num_frames = ds.NumberOfFrames

pixel_data = ds.pixel_array
pixel_data = cv2.normalize(pixel_data, None, 0, 255, cv2.NORM_MINMAX,cv2.CV_8U)
print(pixel_data.shape)

numbers = re.compile(r'(\d+)')
def numericalSort(value):
    parts = numbers.split(value)
    parts[1::2] = map(int, parts[1::2])
    return parts

# extract images from the dcm
for i in range(pixel_data.shape[0]):
    os.makedirs('Output/dicom_3d_images', exist_ok=True)
    slice = pixel_data[i, :, :, :]
    if ds.PhotometricInterpretation == 'YBR_FULL_422':
        slice = cv2.cvtColor(slice, cv2.COLOR_YUV2RGB)
    img = Image.fromarray(slice)
    img.save(f'Output/dicom_3d_images/image{i}.jpg')

# write images into a video
file_path = glob('Output/dicom_3d_images/*.jpg')
height, width, _ = cv2.imread(file_path[0]).shape
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
fps = ds.CineRate
out = cv2.VideoWriter('Output/image1.mp4', fourcc, fps, size)

for filename in sorted(file_path, key=numericalSort):
    img = cv2.imread(filename)
    out.write(img)
out.release()