2021-09-26に更新

これだけは知っておきたいDICOM

はじめに

DICOMとは何ぞやとか成り立ちとかはおいておいて、DICOM勉強しはじめたときに手助けになるようなことを書いておく

お勉強用資料

DICOM Standard Status

最近は年間5回(a→b→c→d→e)更新される
現時点(2021年9月)で1~22章(9,13はリタイア)まであり、気が付いたら増えてたりする。
よく見かけるPS3.Xという書き方のXは章番号を表している。ちなみに3の方はDICOMのVersionだが長らく変わっていない。

とても全部は読めないのでおそらく大半の人が最初に必要になる、3~5章を眺めるといい。
こんな情報が知りたいけどどこ見たらいいのかわからない場合は以下参考。

知りたいこと 章番号
画像種・操作ごとに必要なタグが知りたい 3章(情報オブジェクト定義)
画像種・操作の組み合わせが知りたい 4章(サービスクラス)
VRの意味、DICOMデータの構造、バイナリデータの持ち方、文字コードの表し方、画像自体・輝度の計算が知りたい 5章(データ構造と符号化)
タグNo、タグ名、VR、VMが知りたい 6章(データ辞書)
DICOMメッセージのやり取りが知りたい 7章(メッセージ交換)
匿名化の対象や方法が知りたい 15章(セキュリティ辞書)
造影剤などコードとその意味の定義が知りたい 16章(コンテンツマッピング)

JIRA DICOMの世界

DICOM規格の和訳(但し結構古いので注意)や、勉強会の資料などが置いてある。
「現場でDICOM接続に慌てないための知識」とか割と役立つので初心者は一度目を通しておくとよい。

DICOM通信はオブジェクト+サービスの組み合わせ

オブジェクトをどうする(サービス)かの組み合わせになる。まずはオブジェクトとサービス(クラス)の説明から。

オブジェクト(IOD=Information Object Definitions)

要するに扱うもの。
MR画像やCT画像といったもの。
* MR Image IOD Modules
* CT Image IOD Modules
* Enhanced MR Image IOD Modules
* SC Image IOD Modules

など。
Modulesと複数形になっている通り一つのオブジェクトを複数のモジュールで構成している。
モジュールはまた複数のタグで構成されている。
例えばMR画像に関してはPS3.3のA4.3にモジュール群が書かれているが、各モジュールのReference列の節に飛ぶことで詳細なタグ情報がわかる。
※基本、DICOM規格読むときは飛びまくるので迷子にならないように注意すること。

つまりこういう組み合わせ。

IOD Module Tag
MR Image IOD Modules Patient Patient's Name(0010,0010)
Patient ID(0010,0020)
General Studies Study Instance UID(0020,000D)
Study Date(0008,0020)

ちなみにIODの表のUsage欄に書かれている記号はA1.3までさかのぼると書いてある。
* Mandatory (see Section A.1.3.1), abbreviated M
* Conditional (see Section A.1.3.2), abbreviated C
* User Option (see Section A.1.3.3), abbreviated U

こういうのもどこに書いてあるかわからなくなることが多々あるので、次に見つけたらメモしておこうと毎回思って忘れる。

サービスクラス

上記オブジェクトを「どうするか」の部分。
分かりやすいので言えば、「転送する」「印刷する」
* Storage Management Service Ckass:転送する
* Print Management Service Class:印刷
* Modality Worklist Management Service Class(MWM):検査オーダ受信

など。もっといっぱいあるが一個ずつ説明が重いので別で説明する、つもり。

オブジェクト+サービスの組み合わせ(SOP=Service Object Pair)

オブジェクトとどうする(サービス)かの組み合わせのことをSOP Classと表す。
SOP Class UID(0008,0016)はその組み合わせを示すユニークなIDとなり、通信時に必須となる。
要はこれからこういう通信を行うよ、と伝えるのにDICOM共通のIDがあると一発で伝えるため。
SOP Instance UID(0008,0018)はあくまでインスタンスなので個別につける。但しUID=ユニークなIDなので1画像ずつ違うこと、上位の方はルールがあるので従う。それについてもそのうち書くかもしれない。

SCUとSCP

サービスを使いたい人とそれを提供する人。別の言い方をすればメッセージを投げる人と受け取る人。
* SCU=Service Class User=サービスを使う人
* SCP=Service Class Provider=サービスを提供する人

Storage SCU(画像を送る人)、Storage SCP(画像を受け取る人)のように表される、慣れるまではどっちがどっちかよく忘れるのでわからなくなったら都度確認すること。

Service SCU SCP
Storage 画像を転送したい(する)人(Modality) 画像を受け取る人(PACS)
Print 画像を印刷したい人(Modality) 画像を受け取り印刷する人(Printer)
MWM 検査オーダがないか知りたい人(Modality) 検査オーダを返す人(RIS)

DICOM通信は3ステップ

DICOMの通信は大雑把に3ステップ

  1. アソシエーション確立(相互認証)
  2. データ通信(オブジェクト交換)
  3. アソシエーション解放(エラーの確認)

当たり前だが、SCU側がアソシエーションを要求するところから始まる

SCU SCP
アソシエーション要求
アソシエーション要求承諾
データ送信(続きあるよ)
データ受信
データ送信(ここで終わり)
データ受信
アソシエーション解放要求
アソシエーション解放要求承諾

実際にはアソシエーション張る時にAEタイトルやAbstruct Syntax(SOP Class)、Transfer Syntax(ILE、ELE、JPEGLossyとか)確認する。
データの送信中もC-STOREとかC-FINDとかそれぞれに応じたメッセージを使う。
それはまた別で説明。

DICOMタグの構造

患者名や検査日時、検査した結果の各種数値などなどはタグという形で保存されている。
バイナリ的に見れば
* TagNo
* VR(Implicitだと省略)
* Length
* Value

という構造になる。

データ構造

PS3.5の7.1を見ると色々書いてある。ILE,ELEとかパターン分けがあるが、簡単にだけ書いておくと
* ILE=Implicit VR Little Endian:VRを省略する書き方(たぶん主流)
* ELE=Explicit VR Little Endian:VRを明示的に書き出す書き方(メディア出力時とかはたまにこれの人がいる気がする)

※Little EndianのあたりはDICOM関係ないから他所でどうぞ。ただEBEとかはRETIREしたからあまり考えなくていいかもしれない。

要は
TagNoがあって、VRがあるかないか、長さがあって、値がある
というだけ。
知らないとわからないけど知ってればたいしたことはない。あとのVMとかSQタグとかでまた少し頭使うけど基本はこんな感じ。

TagNo

TagNoの構造はGroupTagと呼ばれるうえ4桁、ElementTagと呼ばれる下4桁の計8桁の16進数で表される。GroupTag、ElementTagに従って(gggg,eeee)という書かれ方をすることもある。
タグには大きく2種類あり、DICOM共通の標準タグ、標準タグで補えない情報がある場合に各団体が発行するプライベートタグ(PrivateTag)がある。

標準タグもだいたいGroupでどんな内容が入っているか決まっていて

GroupTag 内容
0008 検査情報
0010 患者情報
0018 画像収集情報
0020 画像付帯情報(たしか0018が多すぎてこっちに広がったと聞いた気がする)
0028 画像表示情報
7FE0 画素情報.(7FE0,0010)が画像のバイナリデータ

※7FE0に関しては0008(Float)とか0009(Double Float)もあるけど使われてるのを知らない。

PrivateTag

PrivateTagの見分けは簡単でGroupTagが奇数であること。逆に偶数であれば標準タグ。
PrivateTagを発行した場合、必ず発行者を示すPrivateCreatorタグが必要となる。
PrivateCreatorは(gggg,00ee)と決まっており、ElementTagの上位2桁は00と固定である。
また、このPrivateCreatorが保証する範囲は(gggg,ee00-eeFF)までとなる。
具体例を挙げると

(0031,0033)="WATASHIDA"

が保証するのは

(0031,3300)
(0031,3301)
(0031,3302)
…
(0031,33FF)

までということ。PrivateCreatorのElement頭2桁が00なのもこれが理由。

当たり前のことだけど独自のPrivateTagを出して、他所で使ってもらいたいならDICOM C/Sにちゃんと書いておくこと。

VR=Value Representation

そのタグの値が何で表されるか。
例えばSSならSigned Short、ULならUnsigned Long、STならShort Textといった具合に数値なら型が色々、文字列系なら長さや使用できる文字などの制限が様々、日付や時間、一部タグに特化したVRまで定義されているのでわからないうちはPS3.5の6.2の表を印刷して持っておくといい。

VM=Value Multiplicity

そのタグがいくつの値で構成されているか。
例えば患者の向きなどの情報の場合、3軸で表すのでVM=3。
バイナリで見たときにVMを示す領域はないので、
数値のように固定長の場合、VRとLengthから割り出す。SS(2byte)でLengthが6ならVM=6/2=3。
文字列のような可変長の場合は、区切り文字"バックスラッシュ(\)[5CH]"が入るのでそこから割り出す。ImageType(0008,0008)が「ORIGINAL\PRIMARY\HOGEHAGE」の場合、区切り文字が2個なのでVM=3。

SQタグ

ちょっと特殊なタグでこのタグ自体に値はないが子供を持つことができるタグ
例えばこんな風に

Referenced SOP Sequence(0008,1199)[SQ]
>Referenced SOP Class UID(0008,1150)[UI]
>Referemced SOP Instance UID(0008,1155)[UI]

※親子関係を表すのに">"を使う

バイナリ的にはまた複雑でPS3.5の7.5.2を参照した方が早い。
おそらくすごいこんがらがるから実際のデータをバイナリエディタで開きながら見たほうがいい。
ポイントは
* SQもVM複数のことがある
* SQの場合、他のタグの値に当たる部分に、さらにItemがあり、他のタグと同様のセットが現れる
* 長さが分からないときに区切りになるタグが存在する
* (FFFE,E000)、(FFFE,E00D)、(FFFE,E0DD)に注意する

このへんを頭に入れながら一つずつ読み解いていくとそのうち理解できるはず。

Type

SOPごとに必要なタグ、あったらいいななタグなど違ってくるので、それぞれの場合の必要度を示すものがType、なぜかDICOM C/SではTypeで書かない(VNAPとかで書く)。
* Type1:必ず必要、値も必要。=ALWAYS
* Type2:タグは必ず必要、ただし値はなくてもいい。=VNAP(Value Not Always Present)
* Type3:タグも値もなくてもいい。=ANAP(Attribute Not Always Present)
* Type1C:Conditionを満たす場合Type1として振る舞う。


とりあえずここまで。

ツイッターでシェア
みんなに共有、忘れないようにメモ

RedCol

医療モダリティの開発に携わる底辺PG。主にDICOM周りをやるも毎度英語の壁にぶち当たり、泣きそうになりながら調べ続けて10年、いい加減アウトプットしときたいなと思ってようやく書き始める。飽き性なのでいつまで続くか心配。 スクリプト言語が好き、同じことを5回以上やるならスクリプト書こうとする。但し、書いたスクリプト保存しようとすると似たようなスクリプトが既に保存先にあることが多々あって困る。

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント