なんだか数年前に戻ってしまったような感じがしますが、dcm4chee のデータベース pacsdb の中身を読んでファイルの格納場所を探し、sftp でローカルにダウンロードして閲覧します。
これは pacs と呼べる代物ではありませんが、dicom ファイルを閲覧することはできます。
ホスト側の設定
サーバーのデータベースにアクセスするためには、サーバー側でクライアントをユーザー登録し権限を与える必要があります。
ユーザー登録と権限を与えます。
mysql>
CREATE USER 'heno'@'192.168.0.8' IDENTIFIED BY 'moheno';
mysql>
GRANT SELECT ON pacsdb.* TO 'heno'@'192.168.0.8';
/etc/mysql/mysql.conf.d/mysqld.cnf の設定変更。
以下のようにコメントアウトします。
#bind-address = 127.0.0.1
ポートを開放します。
sudo ufw allow 3306
再起動。
sudo ufw reload
sudo service mysql restart
クライアント側からアクセス
クライントからアクセスします。
mysql -h 192.168.56.101 -u heno -p
データベース確認。
mysql>
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| pacsdb |
+--------------------+
2 rows in set (0.00 sec)
データベースからfile の保存場所を抽出
検査IDが 1 の dicom ファイルの保管場所を抽出するのは、
SELECT filepath
FROM files
WHERE instance_fk IN
(SELECT pk
FROM instance
WHERE series_fk IN
(SELECT pk
FROM series
WHERE study_fk IN
(SELECT pk
FROM study
WHERE pk = 1
)
)
);
結果は、
+----------------------------------------+
| filepath |
+----------------------------------------+
| 2022/6/30/5/D60B419F/E8228881/6124F6E9 |
| 2022/6/30/5/D60B419F/E8228881/6124F9D5 |
+----------------------------------------+
2 rows in set (0.00 sec)
dicom ファイルの格納場所は「/var/www/html/DICOM」としたので、ファイルの絶対パスは「/var/www/html/DICOM/2022/6/30/5/D60B419F/E8228881/6124F6E9」となります。
python で抽出
外から pk を与えて、dicom ファイルを抽出します。
def selectDfile( self, pk ):
conn = pymysql.connect(host=self.host,
user=self.user,
db=self.db,
password=self.password,
cursorclass=pymysql.cursors.DictCursor)
try:
with conn.cursor() as cursor:
sql = "SELECT filepath FROM files WHERE instance_fk IN (SELECT pk FROM instance WHERE series_fk IN (SELECT pk FROM series WHERE study_fk = %s));"
cursor.execute( sql, pk )
return cursor.fetchall()
conn.commit()
finally:
conn.close()
ダウンロードディレクトリとweasisを動的に
dcm4hee などでは、weasis.jnlp がダウンロードされてきますが、dicom ファイルも /tmp にダウンロードされます。
それを真似て、dicom ファイルをダウンロードするディレクトリを「/tmp/dcmtmp/年月日+pk」とします。
そして、weasis が読み込むディレクトリを「/tmp/dcmtmp/年月日+pk」に動的に変更します。
まずは、「/tmp/dcmtmp/202207031」というディレクトリを作成。
同時に「/tmp/dcmtmp/202207031.jnlp」という jnlp ファイルをテンプレートから作成。
その jnlp ファイルが読み込む先を「/tmp/dcmtmp/202207031」にします。
def createtmp( self, pk ):
with open( self.template, encoding="utf8" ) as f:
data_lines = f.read()
dt_now = datetime.datetime.now()
self.tmpdir = '/tmp/dcmtmp/' + dt_now.strftime('%Y%m%d') + pk + '/'
self.tmpweasis = '/tmp/dcmtmp/' + dt_now.strftime('%Y%m%d') + pk + '.jnlp'
data_lines = data_lines.replace( "tmpdirectory", self.tmpdir )
os.makedirs( self.tmpdir, exist_ok=True )
with open( self.tmpweasis, mode="w", encoding="utf8" ) as f:
f.write(data_lines)
jnlp のテンプレートは「/var/www/html/weasis/weasistemplate/weasisStart.jnlp」です。
/var/www/html/weasis/weasistemplate/weasisStart.jnlp
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.6+" codebase="http://localhost/weasis" href="">
<information>
<title>Weasis</title>
<vendor>Weasis Team</vendor>
<description>DICOM images viewer</description>
<description kind="short">An application to visualize and analyze DICOM images.</description>
<description kind="one-line">DICOM images viewer</description>
<description kind="tooltip">Weasis</description>
</information>
<security>
<all-permissions />
</security>
<resources>
<!-- Requires Java SE 6 update 10 release for jnlp extension without codebase (substance.jnlp) -->
<j2se version="1.6.0_10+" initial-heap-size="128m" max-heap-size="512m" />
<jar href="http://localhost/weasis/weasis-launcher.jar" main="true" />
<jar href="http://localhost/weasis/felix.jar" />
<extension href="http://localhost/weasis/substance.jnlp" />
<!-- Allows to get files in pack200 compression, only since Weasis 1.1.2 -->
<property name="jnlp.packEnabled" value="true" />
<!-- ================================================================================================================= -->
<property name="jnlp.weasis.felix.config.properties" value="http://localhost/weasis/conf/config.properties" />
<property name="jnlp.weasis.felix.extended.config.properties" value="http://localhost/weasis-ext/conf/ext-config.properties" />
<property name="jnlp.weasis.weasis.codebase.url" value="http://localhost/weasis" />
<property name="jnlp.weasis.weasis.codebase.ext.url" value="http://localhost/weasis-ext" />
<property name="jnlp.weasis.gosh.args" value="-sc telnetd -p 17179 start" />
<property name="jnlp.weasis.apple.laf.useScreenMenuBar" value="true" />
<property name="jnlp.weasis.weasis.i18n" value="http://localhost/weasis-i18n" />
<!-- ================================================================================================================= -->
</resources>
<application-desc main-class="org.weasis.launcher.WebstartLauncher">
<argument>$dicom:get -l tmpdirectory</argument>
</application-desc>
</jnlp>
下の方の「tmpdirectory」を「/tmp/dcmtmp/202207031」に編集して、この jnlp ファイルを「/tmp/dcmtmp/202207031.jnlp」という名前で保存します。
dicom ファイルを sftp でダウンロード
dicom ファイルの絶対パスはわかったので、それらのファイルをローカルの「/tmp/dcmtmp/202207031」に sftp でダウンロードします。
def sftp_connection(self):
self.client = paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
self.client.connect(self.config['host'],
port = self.config['port'],
username = self.config['username'],
password = self.config['password'])
sftp_con = self.client.open_sftp()
return sftp_con
def dcmdn( self, fps ):
sftp_con = self.sftp_connection()
for fp in fps:
remote_path = '/var/www/html/DICOM/' + fp['filepath']
local_path = self.tmpdir + os.path.basename( remote_path )
sftp_con.get( remote_path, local_path )
self.client.close()
weasis 起動
dicom ファイルは「/tmp/dcmtmp/202207031」にあり、それを読み込んで表示する jnlp ファイルは「202207031.jnlp」という名前で「/tmp/dcmtmp」にあります。
それを起動します。
def weasis(self):
subprocess.Popen('javaws ' + self.tmpweasis, shell=True)
全プログラム
selectpk.py
import os
import paramiko
import pymysql
import datetime
import subprocess
class DCM4CHE():
def __init__( self ):
self.host = '192.168.56.101'
self.user = 'heno'
self.password = 'moheno'
self.db = 'pacsdb'
self.config = {
"host" : "192.168.56.101",
"port" : 22,
"username" : "user",
"password" : "pass"
}
self.tmpdir = ''
self.template = "/var/www/html/weasis/weasistemplate/weasisStart.jnlp"
self.tmpweasis = ''
def selectDfile( self, pk ):
conn = pymysql.connect(host=self.host,
user=self.user,
db=self.db,
password=self.password,
cursorclass=pymysql.cursors.DictCursor)
try:
with conn.cursor() as cursor:
sql = "SELECT filepath FROM files WHERE instance_fk IN (SELECT pk FROM instance WHERE series_fk IN (SELECT pk FROM series WHERE study_fk = %s));"
cursor.execute( sql, pk )
return cursor.fetchall()
conn.commit()
finally:
conn.close()
def sftp_connection(self):
self.client = paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
self.client.connect(self.config['host'],
port = self.config['port'],
username = self.config['username'],
password = self.config['password'])
sftp_con = self.client.open_sftp()
return sftp_con
def dcmdn( self, fps ):
sftp_con = self.sftp_connection()
for fp in fps:
remote_path = '/var/www/html/DICOM/' + fp['filepath']
local_path = self.tmpdir + os.path.basename( remote_path )
sftp_con.get( remote_path, local_path )
self.client.close()
def createtmp( self, pk ):
with open( self.template, encoding="utf8" ) as f:
data_lines = f.read()
dt_now = datetime.datetime.now()
self.tmpdir = '/tmp/dcmtmp/' + dt_now.strftime('%Y%m%d') + pk + '/'
self.tmpweasis = '/tmp/dcmtmp/' + dt_now.strftime('%Y%m%d') + pk + '.jnlp'
data_lines = data_lines.replace( "tmpdirectory", self.tmpdir )
os.makedirs( self.tmpdir, exist_ok=True )
with open( self.tmpweasis, mode="w", encoding="utf8" ) as f:
f.write(data_lines)
def weasis(self):
subprocess.Popen('javaws ' + self.tmpweasis, shell=True)
if __name__ == '__main__':
pk = '2'
ftptr = DCM4CHE()
dcmfarr = ftptr.selectDfile(pk)
ftptr.createtmp(pk)
ftptr.dcmdn(dcmfarr)
ftptr.weasis()