From b95d1ef36c80dca0dff936faa9320015aed80582 Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 13 Feb 2021 20:13:57 +0000 Subject: [PATCH] dicom thumbs --- helpers/images.py | 42 ++++++++++++++++- helpers/pydicom_PIL.py | 103 +++++++++++++++++++++++++++++++++++++++++ rad/settings.py | 4 +- requirements.txt | 3 +- 4 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 helpers/pydicom_PIL.py diff --git a/helpers/images.py b/helpers/images.py index 7bea4e8f..b3344920 100644 --- a/helpers/images.py +++ b/helpers/images.py @@ -1,6 +1,13 @@ import base64 import mimetypes +from io import BytesIO + +from PIL import Image, ImageFile + +import pydicom +from .pydicom_PIL import get_PIL_image + def image_as_base64(image_file): """ :param `image_file` for the complete path of image. @@ -14,4 +21,37 @@ def image_as_base64(image_file): # encoded_string = base64.b64encode(img_f.read()) encoded_string = base64.b64encode(image_file.file.read()) mimetype, enc = mimetypes.guess_type(image_file.path) - return "data:image/{};base64,{}".format(mimetype, encoded_string.decode("utf-8")) \ No newline at end of file + return "data:image/{};base64,{}".format(mimetype, encoded_string.decode("utf-8")) + + + +def pil_dicom_image(source, exif_orientation=True, **options): + """ + Try to open the source file directly using PIL, ignoring any errors. + exif_orientation + If EXIF orientation data is present, perform any required reorientation + before passing the data along the processing pipeline. + """ + # Use a BytesIO wrapper because if the source is an incomplete file like + # object, PIL may have problems with it. For example, some image types + # require tell and seek methods that are not present on all storage + # File objects. + #if not source: + # return + #source = BytesIO(source.read()) + + ds = pydicom.read_file("filename") + + image = get_PIL_image(ds) + + #with Image.open(source) as image: + # # Fully load the image now to catch any problems with the image contents. + # try: + # ImageFile.LOAD_TRUNCATED_IMAGES = True + # image.load() + # finally: + # ImageFile.LOAD_TRUNCATED_IMAGES = False + + #if exif_orientation: + # image = utils.exif_orientation(image) + return image \ No newline at end of file diff --git a/helpers/pydicom_PIL.py b/helpers/pydicom_PIL.py new file mode 100644 index 00000000..6b5fcbf2 --- /dev/null +++ b/helpers/pydicom_PIL.py @@ -0,0 +1,103 @@ +# pydicom_PIL.py + +"""View DICOM images using Python image Library (PIL) +Usage: +>>> import pydicom +>>> from pydicom.contrib.pydicom_PIL import show_PIL +>>> ds = pydicom.read_file("filename") +>>> show_PIL(ds) +Requires Numpy: + http://numpy.scipy.org/ +and Python Imaging Library: + http://www.pythonware.com/products/pil/ +""" +# Copyright (c) 2009 Darcy Mason, Adit Panchal +# This file is part of pydicom, relased under an MIT license. +# See the file LICENSE included with this distribution, also +# available at https://github.com/pydicom/pydicom + +# Based on image.py from pydicom version 0.9.3, +# LUT code added by Adit Panchal +# Tested on Python 2.5.4 (32-bit) on Mac OS X 10.6 +# using numpy 1.3.0 and PIL 1.1.7b1 + +have_PIL = True +try: + import PIL.Image +except ImportError: + have_PIL = False + +have_numpy = True +try: + import numpy as np +except ImportError: + have_numpy = False + + +def get_LUT_value(data, window, level): + """Apply the RGB Look-Up Table for the given + data and window/level value.""" + if not have_numpy: + raise ImportError("Numpy is not available." + "See http://numpy.scipy.org/" + "to download and install") + + return np.piecewise(data, + [data <= (level - 0.5 - (window - 1) / 2), + data > (level - 0.5 + (window - 1) / 2)], + [0, 255, lambda data: ((data - (level - 0.5)) / + (window - 1) + 0.5) * (255 - 0)]) + + +def get_PIL_image(dataset): + """Get Image object from Python Imaging Library(PIL)""" + if not have_PIL: + raise ImportError("Python Imaging Library is not available. " + "See http://www.pythonware.com/products/pil/ " + "to download and install") + + if ('PixelData' not in dataset): + raise TypeError("Cannot show image -- DICOM dataset does not have " + "pixel data") + # can only apply LUT if these window info exists + if ('WindowWidth' not in dataset) or ('WindowCenter' not in dataset): + bits = dataset.BitsAllocated + samples = dataset.SamplesPerPixel + if bits == 8 and samples == 1: + mode = "L" + elif bits == 8 and samples == 3: + mode = "RGB" + elif bits == 16: + # not sure about this -- PIL source says is 'experimental' + # and no documentation. Also, should bytes swap depending + # on endian of file and system?? + mode = "I;16" + else: + raise TypeError("Don't know PIL mode for %d BitsAllocated " + "and %d SamplesPerPixel" % (bits, samples)) + + # PIL size = (width, height) + size = (dataset.Columns, dataset.Rows) + + # Recommended to specify all details + # by http://www.pythonware.com/library/pil/handbook/image.htm + im = PIL.Image.frombuffer(mode, size, dataset.PixelData, + "raw", mode, 0, 1) + + else: + ew = dataset['WindowWidth'] + ec = dataset['WindowCenter'] + ww = int(ew.value[0] if ew.VM > 1 else ew.value) + wc = int(ec.value[0] if ec.VM > 1 else ec.value) + image = get_LUT_value(dataset.pixel_array, ww, wc) + # Convert mode to L since LUT has only 256 values: + # http://www.pythonware.com/library/pil/handbook/image.htm + im = PIL.Image.fromarray(image).convert('L') + + return im + + +def show_PIL(dataset): + """Display an image using the Python Imaging Library (PIL)""" + im = get_PIL_image(dataset) + im.show() diff --git a/rad/settings.py b/rad/settings.py index 1371a688..ca177d50 100644 --- a/rad/settings.py +++ b/rad/settings.py @@ -198,7 +198,9 @@ THUMBNAIL_ALIASES = { }, } +THUMBNAIL_SOURCE_GENERATORS = ('easy_thumbnails.source_generators.pil_image', 'helpers.images.pil_dicom_image') + try: from .settings_local import * except ImportError: - pass \ No newline at end of file + pass diff --git a/requirements.txt b/requirements.txt index 733a804c..a77810be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,5 @@ django-filer psycopg2-binary django-sortedm2m pytesseract -opencv-python \ No newline at end of file +opencv-python +pydicom \ No newline at end of file