166 lines
4.6 KiB
Python
Executable File
166 lines
4.6 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Orthanc - A Lightweight, RESTful DICOM Store
|
|
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
|
|
# Department, University Hospital of Liege, Belgium
|
|
# Copyright (C) 2017-2023 Osimis S.A., Belgium
|
|
# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
|
|
# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
|
|
#
|
|
# This program is free software: you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
URL = 'http://127.0.0.1:8042'
|
|
TARGET = 'sample'
|
|
|
|
|
|
#
|
|
# This sample code shows how to setup a simple, high-performance DICOM
|
|
# auto-routing. All the DICOM instances that arrive inside Orthanc
|
|
# will be sent to a remote modality. A producer-consumer pattern is
|
|
# used. The target modality is specified by the TARGET variable above:
|
|
# It must match an entry in the Orthanc configuration file inside the
|
|
# "DicomModalities" section.
|
|
#
|
|
# NOTE: This sample only works with Orthanc >= 0.5.2. Make sure that
|
|
# Orthanc was built with "-DCMAKE_BUILD_TYPE=Release" to get the best
|
|
# performance.
|
|
#
|
|
|
|
import Queue
|
|
import sys
|
|
import time
|
|
import threading
|
|
|
|
import RestToolbox
|
|
|
|
|
|
#
|
|
# Queue that is shared between the producer and the consumer
|
|
# threads. It holds the instances that are still to be sent.
|
|
#
|
|
|
|
queue = Queue.Queue()
|
|
|
|
|
|
#
|
|
# The producer thread. It monitors the arrival of new instances into
|
|
# Orthanc, and pushes their ID into the shared queue. This code is
|
|
# based upon the "ChangesLoop.py" sample code.
|
|
#
|
|
|
|
def Producer(queue):
|
|
current = 0
|
|
|
|
while True:
|
|
r = RestToolbox.DoGet(URL + '/changes', {
|
|
'since' : current,
|
|
'limit' : 4 # Retrieve at most 4 changes at once
|
|
})
|
|
|
|
for change in r['Changes']:
|
|
# We are only interested in the arrival of new instances
|
|
if change['ChangeType'] == 'NewInstance':
|
|
queue.put(change['ID'])
|
|
|
|
current = r['Last']
|
|
|
|
if r['Done']:
|
|
time.sleep(1)
|
|
|
|
|
|
#
|
|
# The consumer thread. It continuously reads the instances from the
|
|
# queue, and send them to the remote modality. Each time a packet of
|
|
# instances is sent, a single DICOM connexion is used, hence improving
|
|
# the performance.
|
|
#
|
|
|
|
def Consumer(queue):
|
|
TIMEOUT = 0.1
|
|
|
|
while True:
|
|
instances = []
|
|
|
|
while True:
|
|
try:
|
|
# Block for a while, waiting for the arrival of a new
|
|
# instance
|
|
instance = queue.get(True, TIMEOUT)
|
|
|
|
# A new instance has arrived: Record its ID
|
|
instances.append(instance)
|
|
queue.task_done()
|
|
|
|
except Queue.Empty:
|
|
# Timeout: No more data was received
|
|
break
|
|
|
|
if len(instances) > 0:
|
|
print('Sending a packet of %d instances' % len(instances))
|
|
start = time.time()
|
|
|
|
# Send all the instances with a single DICOM connexion
|
|
RestToolbox.DoPost('%s/modalities/sample/store' % URL, instances)
|
|
|
|
# Remove all the instances from Orthanc
|
|
for instance in instances:
|
|
RestToolbox.DoDelete('%s/instances/%s' % (URL, instance))
|
|
|
|
# Clear the log of the exported instances (to prevent the
|
|
# SQLite database from growing indefinitely). More simply,
|
|
# you could also set the "LogExportedResources" option to
|
|
# "false" in the configuration file since Orthanc 0.8.3.
|
|
RestToolbox.DoDelete('%s/exports' % URL)
|
|
|
|
end = time.time()
|
|
print('The packet of %d instances has been sent in %d seconds' % (len(instances), end - start))
|
|
|
|
|
|
#
|
|
# Thread to display the progress
|
|
#
|
|
|
|
def PrintProgress(queue):
|
|
while True:
|
|
print('Current queue size: %d' % (queue.qsize()))
|
|
time.sleep(1)
|
|
|
|
|
|
#
|
|
# Start the various threads
|
|
#
|
|
|
|
progress = threading.Thread(None, PrintProgress, None, (queue, ))
|
|
progress.daemon = True
|
|
progress.start()
|
|
|
|
producer = threading.Thread(None, Producer, None, (queue, ))
|
|
producer.daemon = True
|
|
producer.start()
|
|
|
|
consumer = threading.Thread(None, Consumer, None, (queue, ))
|
|
consumer.daemon = True
|
|
consumer.start()
|
|
|
|
|
|
#
|
|
# Active waiting for Ctrl-C
|
|
#
|
|
|
|
while True:
|
|
time.sleep(0.1)
|