1
votes

My original image is in DICOM format and I want to save it in lossless jpg format (or at least keep as much information as I can!!!). How can I do that in python? Currently, I am using the following code which produces lossy png image. I call it lossy png because the png image looks different from dicom image when I see dicom image by dicom browser. Also, how can I modify this image to get jpg image rather than png image.

import numpy as np
import png
import pydicom
ds = pydicom.dcmread("./MyImage.dcm")
shape = ds.pixel_array.shape
# Convert to float to avoid overflow or underflow losses.
image_2d = ds.pixel_array.astype(float)
# Rescaling grey scale between 0-255
image_2d_scaled = (np.maximum(image_2d,0) / image_2d.max()) * 256
# Convert to uint
image_2d_scaled = np.uint8(image_2d_scaled)
# Write the PNG file
with open("out.png", 'wb') as png_file:
    w = png.Writer(shape[1], shape[0], greyscale=True)
    w.write(png_file, image_2d_scaled)
2
Why do you expect lossless JPGs when your code explicitly creates PNGs? And IIRC, PNG is always lossless. - Markus
I know this code creates png image. However, the png image looks different from the dicom image when I see dicom image with dicom browser. Also, how can I creat jpg image from a numpy array? - Mehdi
Did you already try using pypi.org/project/med2image instead? Also, if you ask Google for "python dicom to PNG", you will find a lot of possible solutions. - Markus
I used med2image but the resulted jpg image has lost too much critical info which is available in dicom image. - Mehdi
If you mean you're loosing too much image contrast, try scaling to 16 bit and save as 16 bit PNG. - Markus

2 Answers

0
votes

The problem of loosing information depends on pixel depth, not image compression. Your DICOM image has probably around 11 bits per pixel (from -1024 to 1023), it may be even more. And you convert it to 8-bit image without setting an intensity window.

This means that original pixel of value -1024 becomes black, a pixel of +1023 becomes white, but the most important part of image, from around -100 to +300 becomes mean gray color. If you are interested in lungs, then the important values are lower, if you want to see bones, then they are higher etc. The most important is, that you cannot see all parts of DICOM image on single png/jpg/bmp image. You need a special viewer, which allows to set gray levels. The most common non-medical format, which can handle full pixel depth, is TIFF, but still you need a special viewer.

0
votes

There is another efficient way to convert the Dicom image into JPEG or PNG format using OpenCV and pydicom libraries. Here below code converts all set of dicom images into jpeg/png in one run (using for loop).

import pydicom as dicom
import os
import cv2
# make it True if you want in PNG format
PNG = False
# Specify the .dcm folder path
folder_path = "/Image"
# Specify the output .jpg/png folder path
jpg_folder_path = "/JPGImage"
images_path = os.listdir(folder_path)
for n, image in enumerate(sorted(images_path)):
    print(os.path.join(folder_path, image))
    ds = dicom.dcmread(os.path.join(folder_path, image), force=True)
    ds.file_meta.TransferSyntaxUID = dicom.uid.ImplicitVRLittleEndian
    pixel_array_numpy = ds.pixel_array
    if PNG == False:
        image = image.replace('.dcm', '.jpg')
    else:
        image = image.replace('.dcm', '.png')
    pixel_array_numpy2 = cv2.flip(pixel_array_numpy, 0)
    cv2.imwrite(os.path.join(jpg_folder_path, image), pixel_array_numpy2)