DICOMオブジェクト:データエレメントのエンコード
以前の記事で紹介した例を用いて、話を進めていきたいと思います。
まだ読んでいない方は、ここで生まれてはじめてDICOMオブジェクトを作成することになります。めちゃめちゃ難しいので覚悟しましょう(ウソ)。
次の文章をDICOM化したいと思います。
属性は、患者名、性別、生年月日を利用できることがわかります。これらの属性を使用して、属性名をタグに置き換えて、VRフォーマットを適用すると、次のようになります。
これが、現実世界にある情報を、データやコマンドとして符号化し、伝達・保存するためのDICOMコミュニケーション(会話とでも言いましょうか)で用いられるDICOM語のイメージです。
すべてのDICOMデータ(画像、処理コマンドおよびレポートなど)は、常にこのようなDICOMオブジェクト形式で表されます。このフォーマットで、DICOMオブジェクトは、データとして、DICOMネットワーク上のさまざまなDICOM機器間を移動し、DICOMファイルとして保存されることになります。実際のところ、画像などのDICOMファイルは、DICOMオブジェクトをファイルメディアにしているのです。
DICOMデータ辞書とVRの解説から、DICOMはすべての実世界のデータをその構成要素であるデータエレメント(属性)に分解し、34種類のVRタイプでエンコードしていることを示しました。
DICOMオブジェクトは、属性のコレクションに他なりません。例えば、デジタルな医用画像を考えてみましょう。画像の幅、高さ、色、画像の取得日など、いくつかの属性で医用画像は構成されます。これらの属性はすべてDICOMデータ辞書に定義があります。これに基づき、それぞれをタグに照らし合わせ、値を格納し、DICOMデータエレメント(属性)として表現します。最終的に、これらのデータエレメントは、一つのDICOMオブジェクトとして束ねられ、画像のDICOMオブジェクトになります。
DICOMオブジェクトは、単純にデータエレメントを縦に列挙するだけでなく、エレメントを入れ子にして、ツリー状に構造化させることができます。このような階層構造を作るときは、SQ VRのフォーマットを持つタグを利用します。
SQ VRフォーマットを持つタグは、一連のデータエレメントのセットを保持できるように設計されています。各セットは、個別のDICOMオブジェクトです。
つまり、DICOMオブジェクトは、他のDICOMオブジェクト単体、あるいはDICOMオブジェクトのセットをデータエレメントとして含むことができます。このように入れ子にしていくと、DICOMオブジェクトをデータツリーのように、DICOMオブジェクトを枝、データエレメントを葉として、より複雑なツリー状の構造を作成できます。
DICOMはこのような複雑な分岐データをどのように書き込んでいるのでしょうか?
ここから、基本的なデータエンコーディングルールを確認していきます。
データエレメントのエンコーディング
DICOMにおけるエンコーディングとは、データエレメント(属性)データをDICOM固有のフォーマットで記述することであり、構造化されたDICOMオブジェクトに含まれる複雑なDICOM属性を、一連のバイトのシーケンスに変換することを意味します。ここでいうシーケンスは、SQタグのことではなく、一般的な意味でのシーケンスです。ひと繋ぎの列や配列と捉えることもできます。
実際にDICOMオブジェクトを記述するためには、個々のデータエレメントをどのようにバイトデータとしてエンコードするかを知る必要があります。PS 3.5では、暗黙的VRエンコーディング(Implicit VR)と明示的VRエンコーディング(Explicit VR)の2種類のエンコーディングが定義されています。
Implicit VR エンコーディングは最も単純なもので、DICOMのデフォルトとして使用されます。次のように定義されています。
Tag Group番号を2 byteで表現する
Tag Element番号を2 byteで表現する
データ長(VR length; L)を4 byteで表現する
データ長で指定された量(L)のデータ値を表現する
※リスト番号はエンコードの順番に対応しています。
例として、いつも利用させていただいている、患者名"Smith Joe"で考えてみましょう。
DICOMデータ辞書の患者名属性のグループ番号は 0x0010、エレメント(要素)番号は0x0010です。
"Smith^Joe"という文字列の値の長さ(文字数)は9ですが、DICOMはこれを偶数で扱うというルールを決めているため、最後に半角スペースを追加して、名前の文字列を"Smith^Joe "に変換します。
これで、属性へ格納される値となる名前の長さは、L =10(10進数) = 0x0A(16進数)とできました。あとは、患者名属性を次に示すようにエンコードします。
DICOMのデフォルトのエンディアンはリトルエンディアンです。リトルエンディアンでは、マルチバイトの数値を最下位バイトから読み込みます。したがって、Group番号 0010の場合、最下位(右端)のバイト"10"が最初に来て、最上位のバイト"00"が次に来ます。エレメントやデータ長のエンコーディングも同様です。
Binary(Hex)行に示した18バイトが、まさにDICOMがエンコードしたSmith^Joeという患者名です。
複数のデータ要素をエンコードする場合、DICOMは単純にエンコードした属性のバイナリを電車の車両のように連結して1つのバイナリ文字列を作ります。
各属性のデータ長(VR Length)は、患者名属性で示した通り、属性のエンコーディング内に含まれています。グループ番号、エレメント番号、VR lengthのフィールドは固定サイズですし、属性に格納される値のサイズもデータ長で示されていますから、連結された属性は、あとから別々の要素に分割することができる仕組みです。
先ほどの例では、患者名をImplicitエンディアンでエンコードする場合、最初の2+2=4バイトで(Group番号, Element番号)タグを読み、次の4バイトからデータ長(L)を読み、そしてLバイト分の値を読み取るということができます。属性が複数ある場合でも、このうしろに、次の属性が始まり、繋がります。この繰り返しで、複数の属性が連結され、DICOMオブジェクトができあがります。
もう一つのエンコーディング方式である、Explicit VR エンコーディングは、Implicitと非常によく似ています。2バイトを別のことに使うだけという違いです。
Implicitでデータ長フィールドにあてがわれていた4バイトのうち、先の2バイトをVRタイプ、残り2バイトにデータ長を記録するために使います。
Explicit VRエンコーディングで、患者名属性を表現してみると、次のようになります。
このように、VRタイプとデータ長をフィールドへ明示するExplicit VRエンコーディング方法は、OB, OD, OF, OL, OV, OW, SQ, UNを除いて、他すべてのVRに適用可能です。
除外されたVR(OB, OD, OF, OL, OV, OW, SQ, UN)については、明示のやり方が変わります。
次に示すように、VRタイプの後に続くデータ長にあてがっていた2バイト分に、予約バイト(0000に設定)を置き、(ややこしいのですが)さらにそのうしろへ、データ長フィールドの4バイトを確保します(データ長を4バイト分で表現することは、Implicitの場合と同様)。
例えば、256×256 の 8 bit グレースケール画像のピクセルデータをOB VRタイプで符号化する場合、1ピクセルあたり8 bit = 1バイト、合計で、256×256 = 65536 = 0x00010000バイトとなりますから、これを表にすると、次のようになります。
注意点として、同じDICOMオブジェクトの中で、明示的なVRエンコーディングと暗黙的なVRエンコーディングを混在させることはできず、一貫して1つのエンコーディングを使用しなければなりません。
明示的エンコーディングは、わざわざVRタイプを示すため、やや冗長に見えますが、利点もあります。それは、VRタイプが分かることにより、データエンコーディングエラーを回避できます(特にプライベートタグなど)。
VRのデータ長は、DICOMデータの読み込み(デコード)において、重要な役割を担っています。
例えば、DICOMアプリケーションが理解できない属性を読み込もうとした場合、データ長がわかることで、データ長:Lのバイトをスキップして、次の属性の読み込みを継続できます。
最後に、データサイズが未知の場合(Undefined Lengthの場合)、データのおしりを示すために使われる「Sequence Delimitation Item」という特殊なデータエレメントをデータの区切りとして、未定義のデータ長のおしりを明示的に示します。
さて、ここまでくれば、この解説を読む前に比べて、DICOMオブジェクトを理解するための大きな不安要素の存在感はだいぶ薄まったのではないでしょうか。
DICOMオブジェクトは、DICOMデータエレメント(属性)のまとまりであり、これらはタグによって順序付けられ、並んでいます。
データエレメントとして、SQ VRな属性を含むかもしれませんが、それは先に述べたように、ネストされたDICOMオブジェクトの枝に相当します。これは一見複雑に見えるかもしれませんが、DICOMオブジェクトとしての原則は変わりません。
Stay Visionary
この記事が気に入ったらサポートをしてみませんか?