はじめに
医療情報技師の資格を取って1年半以上がたった。
医療情報システムの支援先でMWMサーバについての調査が必要となり、DICOMという医用画像のフォーマットや通信に関する規格について学んでいる。規格について知るだけでなく、DICOM自体のソフトウェア的な実装についても学びたいと考え、OSSの実装に触れてみている。一旦、現在の理解度や立ち位置について書き残しておきたい。
DICOMという規格について
JIRA(日本画像医療システム工業会)がボランティアベースで日本語訳を公開してくれているのでこれを読みつつ、Gemini 2.5 Proに質問を投げていく感じで勉強をしている。SCUとか、AEとか英略語が大変多いので自分なりの用語集を作るのが初手として必要なことっぽい。
後述する実装の読み解きや、実際に動かしてみることの方に時間をたくさん割いているので、ここについてはまだ書けることが少ない。
DICOMのOSS実装について
MWMサーバについての調査が必要になり、ChatGPTに以下のように聞いてみた。医療機関で動かすことを考えると脆弱性への対応が素早く行われてほしいので開発の活発さは重要だし、Docker上で動かせると大変便利なので以下のようになった。
あなたは医療情報システムの専門家です。MWMサーバのオープンソース実装のうち有用なものを教えてください。また開発が活発に行われているかどうか、実装言語、dockerイメージの提供があるかどうかそれぞれ教えてください
そうすると、Orthancとdcm4chee-arc-lightを教えてくれた。Orthancのサイトは実にUbuntu的な配色をしていて謎の既視感があり面白い。
dcm4chee-arc-light
以前からdcm4cheというツールキットがあるらしい。(cheはチェ・ゲバラから来ていて革命を意味しているらしい。)これとJBoSSを使いWebの画面が生え、dcm4cheeが生まれたらしい。DICOMのストレージとして動きWebUIがあるのはもちろん、IHEのアクターとして動くとか、HL7を喋れたり、DICOMwebにも対応していたらしい。というのも自分はdcm4chee-arc-light(on Docker)しか使ったことがないので詳しくない。
(リンク先は直PDFであることに注意。OSSのDICOMサーバ実装についての歴史が書かれている)https://www.fujita-hu.ac.jp/~kmuto/webdas/CyberRad2007-T3-kmuto.pdf
dcm4chee-arc-lightは、HL7 FHIRにも対応しているようだし設定をOpenLDAPに置くことで集中管理ができるようになっているそうだが、その分重厚に感じる。調べていてもまだ全体像を把握しきれていない。学べば学ぶほどその重厚さが必要だったとなるのかもしれないが。(実用のためには重厚に見えるような仕組みが必要と気がつくときがありそうという意味)
Dockerを利用する場合の一番シンプルな構成である、"Run minimum set of archive services on a single host" にある docker-compose.ymlはこんな感じで結構長い。これだけでも重厚さが垣間見えるかもしれない。 github.com
ちなみに、rootless dockerで試したところイメージから起動はするのだが、ブラウザでアクセスしても何も表示されないという事象が発生した。詳しく調べても良かったのだが、正直ダルいと感じたので調査できていない。
version: "3" services: ldap: image: dcm4che/slapd-dcm4chee:2.6.7-33.1 logging: driver: json-file options: max-size: "10m" ports: - "389:389" environment: STORAGE_DIR: /storage/fs1 volumes: - /var/local/dcm4chee-arc/ldap:/var/lib/openldap/openldap-data - /var/local/dcm4chee-arc/slapd.d:/etc/openldap/slapd.d db: image: dcm4che/postgres-dcm4chee:17.1-33 logging: driver: json-file options: max-size: "10m" ports: - "5432:5432" environment: POSTGRES_DB: pacsdb POSTGRES_USER: pacs POSTGRES_PASSWORD: pacs volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/db:/var/lib/postgresql/data arc: image: dcm4che/dcm4chee-arc-psql:5.33.1 logging: driver: json-file options: max-size: "10m" ports: - "8080:8080" - "8443:8443" - "9990:9990" - "9993:9993" - "11112:11112" - "2762:2762" - "2575:2575" - "12575:12575" environment: POSTGRES_DB: pacsdb POSTGRES_USER: pacs POSTGRES_PASSWORD: pacs WILDFLY_CHOWN: /storage WILDFLY_WAIT_FOR: ldap:389 db:5432 depends_on: - ldap - db volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/wildfly:/opt/wildfly/standalone - /var/local/dcm4chee-arc/storage:/storage
Orthanc
OrthancはChatGPTによると、軽量・REST連携・柔軟性ありという特徴があるようだ。実際公式サイトにも"Open-source, lightweight DICOM server."という記述がある。
Orthancのdockerイメージデプロイはシンプルだった
version: '3.1' # Secrets are only available since this version of Docker Compose services: orthanc: image: jodogne/orthanc-plugins:1.12.7 command: /run/secrets/ # Path to the configuration files (stored as secrets) ports: - 4242:4242 - 8042:8042 secrets: - orthanc.json environment: - ORTHANC_NAME=HelloWorld secrets: orthanc.json: file: orthanc.json
上記のdocker-compose.ymlと、下記のorthanc.jsonを置くだけで簡単に使い始めることができた。画面もシンプル
{ "Name" : "${ORTHANC_NAME} in Docker Compose", "RemoteAccessAllowed" : true }
ruby-dicomについて
自分はRubyが好きだし、RubyでDICOMを扱えるソフトウェアがないかと探したところruby-dicomというのを発見した。しかし、last commitは5年前だし、RequirementsにはRuby 1.9.3とありもうメンテナンスがされていないようだ。
先述の歴史資料にもあるDCMTKやdcm4che-toolなどを使えばDICOM画像の送信はできるのだが、せっかくruby-dicomを知ったのでこれを使ってDocker上のOrthancやdcm4chee-arc-lightにDICOM画像を送りつけたいと考えた。実際にDICOM画像を送ろうとしても、DICOM画像持っていないなと思ったが、ruby-dicomにはsamplesフォルダ内にDICOM画像がありこれを使った。
やってみると実際むずかしいことはなく、送る手順としては苦労しなかった。dcm4chee-arc-lightは、host_aeが必要かつ、指定するAEはDCM4CHEE上で登録されている必要があった。
require "dicom" include DICOM node = DClient.new("<docker host ip>", 4242) node.send("./samples/explicit-big-endian_us_8bit_rgb.dcm") I, [2025-06-11T00:56:17.118573 #124473] INFO -- DICOM: Association successfully negotiated with host DEFAULT (<docker host ip>). I, [2025-06-11T00:56:17.118666 #124473] INFO -- DICOM: The presentation context was accepted by host DEFAULT. I, [2025-06-11T00:56:17.255220 #124473] INFO -- DICOM: Receipt for successful execution of the desired operation has been received. I, [2025-06-11T00:56:17.255769 #124473] INFO -- DICOM: Association released properly from host DEFAULT. => false # dcm4chee-arc-lightにDICOM画像を送りつけるには、host_aeが必要かつ、指定するAEはDCM4CHEE上で登録されている必要がある irb(main):003:0> che = DClient.new("<docker host ip>", 11112, host_ae: "DCM4CHEE") irb(main):004:0> che.send("./samples/explicit-big-endian_us_8bit_rgb.dcm") W, [2025-06-11T04:51:34.528162 #126256] WARN -- DICOM: A presentation context was rejected by the host, reason: 'Transfer syntax not supported' I, [2025-06-11T04:51:34.528701 #126256] INFO -- DICOM: Association successfully negotiated with host DCM4CHEE (<docker host ip>). I, [2025-06-11T04:51:34.528942 #126256] INFO -- DICOM: APPROVED: Ultrasound Image Storage (Implicit VR Little Endian: Default Transfer Syntax for DICOM) W, [2025-06-11T04:51:34.529085 #126256] WARN -- DICOM: REJECTED: Ultrasound Image Storage (Explicit VR Big Endian) W, [2025-06-11T04:51:34.529164 #126256] WARN -- DICOM: 1 of 2 your presentation contexts were rejected by host DCM4CHEE! I, [2025-06-11T04:51:34.750754 #126256] INFO -- DICOM: Receipt for successful execution of the desired operation has been received. I, [2025-06-11T04:51:34.751531 #126256] INFO -- DICOM: Association released properly from host DCM4CHEE. => false irb(main):005:0> che.send("./samples/CR_JPG_IR6a.dcm") I, [2025-06-11T04:52:00.967245 #126256] INFO -- DICOM: Association successfully negotiated with host DCM4CHEE (<docker host ip>). I, [2025-06-11T04:52:00.967339 #126256] INFO -- DICOM: The presentation context was accepted by host DCM4CHEE. I, [2025-06-11T04:52:01.101037 #126256] INFO -- DICOM: Receipt for successful execution of the desired operation has been received. I, [2025-06-11T04:52:01.101775 #126256] INFO -- DICOM: Association released properly from host DCM4CHEE. => false # host_aeが無いとASSOCIATEがrejectされる irb(main):006:0> che = DClient.new("<docker host ip>", 11112) irb(main):007:0> che.send("./samples/CR_JPG_IR6a.dcm") W, [2025-06-11T04:56:39.540970 #126256] WARN -- DICOM: ASSOCIATE Request was rejected by the host. Error codes: Result: 1, Source: 1, Reason: 7 (See DICOM PS3.8: Table 9-21 for details.) E, [2025-06-11T04:56:39.541058 #126256] ERROR -- DICOM: Association was denied from host DEFAULT (<docker host ip>)! E, [2025-06-11T04:56:39.591888 #126256] ERROR -- DICOM: Association released from host DEFAULT, but a release response was not registered.
ruby-dicomのRuby3対応について
自分の詳しいところや得意分野ではないのだが、せっかく見つけたgemがRuby 1.9.3までしか対応していないのはさみしいと思い、Rubyバージョンアップ対応をしてみようかなと思っている。実際思っているだけではなく、調べたり対応を試しているのだがDICOM自体の知識がまだ足りないうえに、Ruby自体やバージョンアップ対応のノウハウが足りてなくて現状うまくいっていない。Gemini 2.5 Proに相談しているものの、アドバイスをしてくれる人がほしいところだ。
RSpecのテストコードはすでにあるが、GitHub ActionsとかCIは無いようだったのでバージョンアップ対応の初手としてGitHub Actionsでテストを実行させるようにしてみたのがこちら。