dicom thumbs
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
import base64
|
import base64
|
||||||
import mimetypes
|
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):
|
def image_as_base64(image_file):
|
||||||
"""
|
"""
|
||||||
:param `image_file` for the complete path of image.
|
:param `image_file` for the complete path of image.
|
||||||
@@ -15,3 +22,36 @@ def image_as_base64(image_file):
|
|||||||
encoded_string = base64.b64encode(image_file.file.read())
|
encoded_string = base64.b64encode(image_file.file.read())
|
||||||
mimetype, enc = mimetypes.guess_type(image_file.path)
|
mimetype, enc = mimetypes.guess_type(image_file.path)
|
||||||
return "data:image/{};base64,{}".format(mimetype, encoded_string.decode("utf-8"))
|
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
|
||||||
@@ -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()
|
||||||
@@ -198,6 +198,8 @@ THUMBNAIL_ALIASES = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THUMBNAIL_SOURCE_GENERATORS = ('easy_thumbnails.source_generators.pil_image', 'helpers.images.pil_dicom_image')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .settings_local import *
|
from .settings_local import *
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ psycopg2-binary
|
|||||||
django-sortedm2m
|
django-sortedm2m
|
||||||
pytesseract
|
pytesseract
|
||||||
opencv-python
|
opencv-python
|
||||||
|
pydicom
|
||||||
Reference in New Issue
Block a user