changeset 706:c62539d00251

Conversions between Orthanc and Python images
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 11 Jun 2021 12:42:39 +0200
parents 745d93684b0b
children daf07750e901
files Sphinx/source/plugins/python.rst Sphinx/source/plugins/python/pil-conversions.py
diffstat 2 files changed, 72 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- /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)