Mercurial > hg > orthanc-book
changeset 1048:0d8089ca8183
merge
author | Alain Mazy <am@osimis.io> |
---|---|
date | Wed, 27 Mar 2024 09:17:05 +0100 |
parents | e5e6841e13b1 (current diff) 63edb430f259 (diff) |
children | 056b66f83c6b |
files | |
diffstat | 3 files changed, 64 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/Sphinx/source/plugins/python.rst Wed Mar 27 09:16:33 2024 +0100 +++ b/Sphinx/source/plugins/python.rst Wed Mar 27 09:17:05 2024 +0100 @@ -397,6 +397,8 @@ :language: python +.. _python-pil-thumbnail: + Rendering a thumbnail using PIL/Pillow ...................................... @@ -899,6 +901,25 @@ the :ref:`Orthanc Explorer 2 <orthanc-explorer-2>` interface. +.. _python_mosaic: + +Generating a mosaic for a DICOM series +...................................... + +Thanks to the fact that Python plugins have access to :ref:`PIL/Pillow +<python-pil-thumbnail>`, it is quite easy to generate a mosaic from a +DICOM series: + +.. image:: python/mosaic.png + :align: center + :width: 512 + +Here is the source code: + +.. literalinclude:: python/mosaic.py + :language: python + + Performance and concurrency ---------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sphinx/source/plugins/python/mosaic.py Wed Mar 27 09:17:05 2024 +0100 @@ -0,0 +1,43 @@ +import PIL.Image +import io +import json +import math +import orthanc + +def generate_mosaic(output, uri, **request): + # Sort the slices of the series, using the REST API of Orthanc + seriesId = request['groups'][0] + slices = json.loads(orthanc.RestApiGet('/series/%s/ordered-slices' % seriesId)) ['Slices'] + + # Retrieve the first slice of the mosaic + firstSliceBytes = orthanc.RestApiGet(slices[0] + '/preview') + firstSliceDecoded = PIL.Image.open(io.BytesIO(firstSliceBytes)) + + # Compute the size of the mosaic + sliceWidth, sliceHeight = firstSliceDecoded.size + side = math.ceil(math.sqrt(len(slices))) + + # Create a PIL image to store the mosaic + image = PIL.Image.new(mode = 'L', size = (side * sliceWidth, side * sliceHeight)) + + # Loop over the instances of the series to populate the mosaic + x = 0 + y = 0 + for i in range(len(slices)): + sliceBytes = orthanc.RestApiGet(slices[i] + '/preview') + sliceDecoded = PIL.Image.open(io.BytesIO(sliceBytes)) + + image.paste(sliceDecoded, (x * sliceWidth, y * sliceHeight)) + + x += 1 + if x == side: + x = 0 + y += 1 + + # Answer with the mosaic encoded as a PNG image + with io.BytesIO() as png: + image.save(png, format = 'PNG') + png.seek(0) + output.AnswerBuffer(png.read(), 'image/png') + +orthanc.RegisterRestCallback('/series/(.*)/mosaic', generate_mosaic)