# HG changeset patch # User Sebastien Jodogne # Date 1623408159 -7200 # Node ID c62539d0025142057a1e064e55405af2dd8d32ec # Parent 745d93684b0b56329a7d388ac8e5c282f2faf9b5 Conversions between Orthanc and Python images diff -r 745d93684b0b -r c62539d00251 Sphinx/source/plugins/python.rst --- a/Sphinx/source/plugins/python.rst Fri Jun 11 10:50:45 2021 +0200 +++ b/Sphinx/source/plugins/python.rst Fri Jun 11 12:42:39 2021 +0200 @@ -502,6 +502,26 @@ :language: python +.. _python_pil_conversions: + +Conversions between Orthanc and Python images (new in 3.2) +.......................................................... + +The Python method ``orthanc.Image.GetImageBuffer()`` returns a copy of +the memory buffer of an image that is handled Orthanc. Conversely, the +Python function ``orthanc.CreateImageFromBuffer()`` can be used to +create an Orthanc image from a Python buffer. Taken together, these +two functions can be used to do bidirectional conversions between +Orthanc images and Python images. + +Here is a full working example using PIL/Pillow that shows how to +decode a DICOM instance using Orthanc, then to modify this image using +PIL, and finally to upload the modified image as a new DICOM instance: + +.. literalinclude:: python/pil-conversions.py + :language: python + + .. _python_dicom_scp: Handling DICOM SCP requests (new in 3.2) diff -r 745d93684b0b -r c62539d00251 Sphinx/source/plugins/python/pil-conversions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sphinx/source/plugins/python/pil-conversions.py Fri Jun 11 12:42:39 2021 +0200 @@ -0,0 +1,52 @@ +import json +import PIL.Image +import PIL.ImageDraw +import orthanc + +URL = 'http://hg.orthanc-server.com/orthanc-tests/raw-file/Orthanc-1.9.3/Database/LenaTwiceWithFragments.dcm' +USERNAME = '' +PASSWORD = '' + +def OnChange(changeType, level, resource): + if changeType == orthanc.ChangeType.ORTHANC_STARTED: + + # (1) Download a sample DICOM instance and decode it + orthanc.LogWarning('Downloading: %s' % URL) + lena = orthanc.HttpGet(URL, USERNAME, PASSWORD) + + dicom = orthanc.CreateDicomInstance(lena) + orthanc.LogWarning('Number of frames: %d' % dicom.GetInstanceFramesCount()) + + # (2) Access the first frame of the instance as a PIL image + frame = dicom.GetInstanceDecodedFrame(0) + size = (frame.GetImageWidth(), frame.GetImageHeight()) + + if frame.GetImagePixelFormat() == orthanc.PixelFormat.RGB24: + mode = 'RGB' + else: + raise Exception('Unsupported pixel format') + + image = PIL.Image.frombuffer(mode, size, frame.GetImageBuffer(), 'raw', mode, 0, 1) + + # (3) Draw a red cross over the PIL image + draw = PIL.ImageDraw.Draw(image) + draw.line((0, 0) + image.size, fill=(255,0,0), width=10) + draw.line((0, image.size[1], image.size[0], 0), fill=(255,0,0), width=10) + + # (4) Convert back the modified PIL image to an Orthanc image + buf = image.tobytes() + a = orthanc.CreateImageFromBuffer(frame.GetImagePixelFormat(), image.size[0], image.size[1], + len(buf) / image.size[1], buf) + + # (5) Create and upload a new DICOM instance with the modified frame + tags = { + 'SOPClassUID' : '1.2.840.10008.5.1.4.1.1.1', + 'PatientID' : 'HELLO', + 'PatientName' : 'WORLD', + } + + s = orthanc.CreateDicom(json.dumps(tags), a, orthanc.CreateDicomFlags.GENERATE_IDENTIFIERS) + orthanc.RestApiPost('/instances', s) + orthanc.LogWarning('Image successfully modified and uploaded!') + +orthanc.RegisterOnChangeCallback(OnChange)