-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 531d249
Showing
16 changed files
with
672 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Compiled python modules. | ||
*.pyc | ||
|
||
# Setuptools distribution folder. | ||
/dist/ | ||
|
||
# Python egg metadata, regenerated from source files by setuptools. | ||
/*.egg-info | ||
/*.egg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include README.rst |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/env python | ||
# _ | ||
# Pacs ToolKit Find wrapper | ||
# | ||
# (c) 2016 Fetal-Neonatal Neuroimaging & Developmental Science Center | ||
# Boston Children's Hospital | ||
# | ||
# http://childrenshospital.org/FNNDSC/ | ||
# [email protected] | ||
# | ||
|
||
# FOR DEV PURPOSE | ||
import sys, os | ||
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | ||
|
||
import ptk | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser(description='Echo PACS') | ||
|
||
# PACS settings | ||
parser.add_argument('--aet', action='store', dest='aet', type=str, default='CHRIS-ULTRON-AET', help='aet') | ||
parser.add_argument('--aec', action='store', dest='aec', type=str, default='CHRIS-ULTRON-AEC', help='aec') | ||
parser.add_argument('--serverIP', action='store', dest='server_ip', type=str, default='192.168.1.110', help='PACS server IP') | ||
parser.add_argument('--serverPort', action='store', dest='server_port', type=str, default='4242', help='PACS server port') | ||
|
||
opts = parser.parse_args() | ||
output = ptk.echo(vars(opts)) | ||
print(output) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#!/usr/bin/env python | ||
# _ | ||
# Pacs ToolKit Find wrapper | ||
# | ||
# (c) 2016 Fetal-Neonatal Neuroimaging & Developmental Science Center | ||
# Boston Children's Hospital | ||
# | ||
# http://childrenshospital.org/FNNDSC/ | ||
# [email protected] | ||
# | ||
|
||
# FOR DEV PURPOSE | ||
import sys, os | ||
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | ||
|
||
import ptk | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser(description='Find PACS') | ||
|
||
# PACS settings | ||
parser.add_argument('--aet', action='store', dest='aet', type=str, default='CHRIS-ULTRON-AET', help='aet') | ||
parser.add_argument('--aec', action='store', dest='aec', type=str, default='CHRIS-ULTRON-AEC', help='aec') | ||
parser.add_argument('--serverIP', action='store', dest='server_ip', type=str, default='192.168.1.110', help='PACS server IP') | ||
parser.add_argument('--serverPort', action='store', dest='server_port', type=str, default='4242', help='PACS server port') | ||
|
||
# Query settings | ||
parser.add_argument('--patientID', action='store', dest='PatientID', type=str, default='2175', help='Patient ID') | ||
parser.add_argument('--patientName', action='store', dest='PatientName', type=str, default='', help='Patient name') | ||
parser.add_argument('--patientSex', action='store', dest='PatientSex', type=str, default='', help='Patient sex') | ||
parser.add_argument('--studyDate', action='store', dest='StudyDate', type=str, default='', help='Study date (YYYY/MM/DD)') | ||
parser.add_argument('--modalitiesInStudy', action='store', dest='ModalitiesInStudy', type=str, default='', help='Modalities in study') | ||
parser.add_argument('--performedStationAETitle', action='store', dest='PerformedStationAETitle', type=str, default='', help='Performed station aet') | ||
parser.add_argument('--studyDescription', action='store', dest='StudyDescription', type=str, default='', help='Study description') | ||
parser.add_argument('--seriesDescription', action='store', dest='SeriesDescription', type=str, default='', help='Series Description') | ||
|
||
opts = parser.parse_args() | ||
output = ptk.find(vars(opts)) | ||
print(output) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/usr/bin/env python | ||
# _ | ||
# Pacs ToolKit Listener | ||
# | ||
# (c) 2016 Fetal-Neonatal Neuroimaging & Developmental Science Center | ||
# Boston Children's Hospital | ||
# | ||
# http://childrenshospital.org/FNNDSC/ | ||
# [email protected] | ||
# | ||
|
||
# FOR DEV PURPOSE | ||
import sys, os | ||
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | ||
|
||
import argparse | ||
import ptk | ||
|
||
parser = argparse.ArgumentParser(description='DICOM Listener script (based on DCMTK and PyDicom)') | ||
parser.add_argument('-t', '--tmpdir', action='store', dest='tmp_directory', required=True, type=str, help='Directory to store temporary files.') | ||
parser.add_argument('-l', '--logdir', action='store', dest='log_directory', required=True, type=str, help='Directory to store log files.') | ||
parser.add_argument('-d', '--datadir', action='store', dest='data_directory', required=True, type=str, help='Directory to store DICOM files.') | ||
|
||
opts = parser.parse_args() | ||
ptk.listen(vars(opts)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
## pre-requisites | ||
``` | ||
dcmtk | ||
pydicom | ||
``` | ||
|
||
## configuration | ||
In `xinetd` or in `launchd`, the dicom listener scripts requires the following arguments to be provided: | ||
``` | ||
-t: temporary directory | ||
-l: log directory | ||
-d: data directory | ||
|
||
``` | ||
## service | ||
In `/etc/services` add: | ||
``` | ||
chris-ultron 10401/tcp # chris ultron dicom listener | ||
chris-ultron 10401/udp # chris ultron dicom listener | ||
``` | ||
|
||
## launchd | ||
Add `org.babymri.chris-ultron.plist` in `/Library/LaunchDaemons`. | ||
|
||
Load: `sudo launchctl load -w org.babymri.chris-ultron.plist` | ||
|
||
Unload: `sudo launchctl unload org.babymri.chris-ultron.plist` | ||
|
||
Test: `nc localhost 10401` (must hang) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>UserName</key> | ||
<string>nico</string> | ||
<key>Label</key> | ||
<string>org.babymri.chris-ultron</string> | ||
<key>ProgramArguments</key> | ||
<array> | ||
<string>/Users/nico/work/gitroot/chris-ultron-backend/chris_backend/plugins/services/pacslistener/pacslistener.py</string> | ||
<string>-t</string> | ||
<string>/tmp</string> | ||
<string>-l</string> | ||
<string>/tmp/log</string> | ||
<string>-d</string> | ||
<string>/tmp/data</string> | ||
</array> | ||
<key>inetdCompatibility</key> | ||
<dict> | ||
<key>Wait</key> | ||
<false/> | ||
</dict> | ||
<key>Sockets</key> | ||
<dict> | ||
<key>Listeners</key> | ||
<dict> | ||
<key>SockServiceName</key> | ||
<string>chris-ultron</string> | ||
<key>SockType</key> | ||
<string>stream</string> | ||
</dict> | ||
</dict> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Compiled python modules. | ||
*.pyc | ||
|
||
# Setuptools distribution folder. | ||
/dist/ | ||
|
||
# Python egg metadata, regenerated from source files by setuptools. | ||
/*.egg-info |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from .echo import Echo | ||
from .find import Find | ||
from .listen import Listen | ||
from .move import Move | ||
|
||
def echo(opt={}): | ||
return Echo(opt).run() | ||
|
||
def find(opt={}): | ||
return Find(opt).run(opt) | ||
|
||
def listen(opt={}): | ||
return Listen(opt).run() | ||
|
||
def move(opt={}): | ||
return Move(opt).run(opt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import subprocess | ||
import ptk.utils | ||
|
||
class Echo(): | ||
"""docstring for Echo.""" | ||
def __init__(self, arg): | ||
ptk.utils.init(self, arg) | ||
self.executable = 'echoscu' | ||
|
||
def command(self): | ||
command = ' --timeout 5' #5s timeout | ||
|
||
return self.executable + ' ' + command + ' ' + self.command_suffix | ||
|
||
def run(self): | ||
response = subprocess.run(self.command(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) | ||
result = self.handle(response) | ||
return result | ||
|
||
def handle(self, echo_response): | ||
std = echo_response.stdout.decode('ascii') | ||
response = { | ||
'status': 'success', | ||
'data': '', | ||
'command': echo_response.args | ||
} | ||
if std != '': | ||
response['status'] = 'error' | ||
response['data'] = std | ||
|
||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import subprocess, re | ||
import ptk.utils | ||
|
||
class Find(): | ||
"""docstring for Find.""" | ||
def __init__(self, arg): | ||
|
||
ptk.utils.init(self, arg) | ||
self.executable = 'findscu' | ||
# to be moved out | ||
self.postfilter_parameters = { | ||
'PatientSex': '', | ||
'PerformedStationAETitle': '', | ||
'StudyDescription': '', | ||
'SeriesDescription': '' | ||
} | ||
|
||
def buildCommand(self, opt={}): | ||
parameters = { | ||
'PatientID': '', # PATIENT INFORMATION | ||
'PatientName': '', | ||
'PatientBirthDate': '', | ||
'PatientSex': '', | ||
'StudyDate': '', # STUDY INFORMATION | ||
'StudyDescription': '', | ||
'StudyInstanceUID': '', | ||
'ModalitiesInStudy': '', | ||
'PerformedStationAETitle': '', | ||
'NumberOfSeriesRelatedInstances': '', # SERIES INFORMATION | ||
'InstanceNumber': '', | ||
'SeriesDate': '', | ||
'SeriesDescription': '', | ||
'SeriesInstanceUID': '', | ||
'QueryRetrieveLevel': 'SERIES' | ||
} | ||
|
||
# build query | ||
command = ' -xi' | ||
command += ' -S' | ||
|
||
return self.commandWrap(command, parameters, opt) | ||
|
||
def commandWrap(self, command, parameters, opt={}): | ||
for key, value in parameters.items(): | ||
# update value if provided | ||
if key in opt: | ||
value = opt[key] | ||
# update command | ||
if value != '': | ||
command += ' -k "' + key + '=' + value + '"' | ||
else: | ||
command += ' -k ' + key | ||
|
||
print(command) | ||
|
||
return self.executable + ' ' + command + ' ' + self.command_suffix | ||
|
||
def preparePostFilter(self): | ||
print('prepare post filter') | ||
# $post_filter['PatientSex'] = $patientsex; | ||
# $post_filter['PerformedStationAETitle'] = $station; | ||
# $post_filter['StudyDescription'] = $studydescription; | ||
# $post_filter['SeriesDescription'] = $seriesdescription; | ||
|
||
def run(self, opt={}): | ||
print('run Find') | ||
print(opt) | ||
# | ||
# | ||
# find data | ||
response = subprocess.run(self.buildCommand(opt), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) | ||
# format response | ||
return self.formatResponse(response) | ||
|
||
def checkResponse(self, response): | ||
stdSplit = response.split('\n') | ||
infoCount = 0 | ||
errorCount = 0 | ||
for line in stdSplit: | ||
if line.startswith('I: '): | ||
infoCount += 1 | ||
elif line.startswith('E: '): | ||
errorCount += 1 | ||
|
||
status = 'error' | ||
if errorCount == 0: | ||
status = 'success' | ||
|
||
return status | ||
|
||
def parseResponse(self, response): | ||
data = [] | ||
|
||
uid = 0 | ||
stdSplit = response.split('\n') | ||
|
||
for line in stdSplit: | ||
if line.startswith('I: ---------------------------'): | ||
data.append({}) | ||
data[-1]['uid'] = {} | ||
data[-1]['uid']['tag'] = 0 | ||
data[-1]['uid']['value'] = uid | ||
data[-1]['uid']['label'] = 'uid' | ||
uid +=1 | ||
|
||
elif line.startswith('I: '): | ||
lineSplit = line.split() | ||
if len(lineSplit) >= 8 and re.search('\((.*?)\)', lineSplit[1]) != None: | ||
# extract DICOM tag | ||
tag = re.search('\((.*?)\)', lineSplit[1]).group(0)[1:-1].strip().replace('\x00', '') | ||
|
||
# extract value | ||
value = re.search('\[(.*?)\]', line) | ||
if value != None: | ||
value = value.group(0)[1:-1].strip().replace('\x00', '') | ||
else: | ||
value = 'no value provided' | ||
|
||
# extract label | ||
label = lineSplit[-1].strip() | ||
|
||
data[-1][label] = {} | ||
data[-1][label]['tag'] = tag | ||
data[-1][label]['value'] = value | ||
data[-1][label]['label'] = label | ||
|
||
return data | ||
|
||
def formatResponse(self, response): | ||
std = response.stdout.decode('ascii') | ||
response = { | ||
'status': 'success', | ||
'data': '', | ||
'command': response.args | ||
} | ||
|
||
status = self.checkResponse(std) | ||
if status == 'error': | ||
response['status'] = 'error' | ||
response['data'] = std | ||
else: | ||
response['status'] = 'success' | ||
response['data'] = self.parseResponse(std) | ||
|
||
return response |
Oops, something went wrong.