マイブログ リスト

医療言語処理講座

2019年2月4日月曜日

Pyゼミ1.03 DICOMのタグ情報を読む

DICOM画像のタグ情報を読んでみよう。


keyword:DICOM, Tag, SOP Instance UID

医用画像の標準規格であるDICOM(Digital Imaging and COmmunication in Medicine)の画像の付帯情報(メタ情報)について学びます。
このメタ情報には患者情報や検査情報などが格納されています。
これらの情報を読み込むことにより,適切な画像の表示や取り扱いができます。

DICOM画像はデータエレメントの集合である


DICOM画像はデータエレメントと呼ばれる情報の単位の連続で構成されています。
このデータエレメントは4バイトのタグ(Tag),値表現(Value Representation, VR),値の長さ(Value Length, VL)と(Value)そのものから構成されています。
例えば,患者ID(院内で用いられるユニークな患者番号)は以下のようになっています。
  Tag   0010,0020
  VR          LO
  VL    8
  Value  '09005315 '

Tagの最初の’0010’はグループ番号と呼ばれ16進数,2バイトで表現されれす。
'0010'は患者情報が格納されているグループであることを示します。
次の2バイト'0020’はエレメント番号と呼ばれグループ内の情報を特定する番号です。
エレメント番号'0020'は患者IDを示します。
詳細はここに書かれています。

次にVRはこのデータエレメントに格納されている値が文字なのか数字なのかなどを表す2文字のコードが入っています。
’LO’はLOng Stringを表し,最大長は64バイトの文字列を表します。
また,DICOMの転送構文(転送方式)であるImplicit VR Little Endian形式のとき,Valueを暗黙的(implicite)であり存在しない。
他のExplicite VR LittleとExplicite VR Big Endianでは明示的にVRを含み,値の意味をしまします。

VLはValueの実際の長さが入ります。
ここでは8バイトの値が入っていることを示しています。

Valueは実際の患者ID,'09005315’です。

ひとつのデータエレメントにはひとつの情報(患者氏名や検査日など)が格納され,それがDICOM画像ファイル中に連続しています。
そして最後のデータエレメント(7fe0, 0010)に画像が格納されています。


主要なDICOMのタグを表示してみる。


それではDICOM画像の主要なタグ情報を読み込み表示してみよう。
下のプログラム(dicomTagDisplay.py)を入力して実行してみよう。

dicomTagDisplay.py

import os, sys
import pydicom

def displayDicomMainTag(fnm):
    print("\n\nFILE NAME:",fnm)
  
    ds = pydicom.read_file(fnm)
  
    #Basic Information(Group:0008)
    print("SOP Instance UID   :", ds.SOPInstanceUID)
    print("検査日             :", ds.StudyDate)
    print("検査時間       :", ds.StudyTime)
    print("アクセッション番号 :", ds.AccessionNumber)
    print("画像診断装置       :", ds.Modality)
  
    #Patient Information(Group:0010)
    print("\n患者名    :", ds.PatientName)
    print("患者ID    :", ds.PatientID)

    #Study Information(Group:0018)
    print("\n検査部位    :", ds.BodyPartExamined)
    print("スライス厚   :", ds.SliceThickness)
    print("画像再構成関数 :", ds.ConvolutionKernel)

    #(Group:0020)
    print("\nStudy Instance UID  :", ds.StudyInstanceUID)
    print("Series Instance UID :", ds.SeriesInstanceUID)
    print("Series Number       :", ds.SeriesNumber)
    print("Image Position (Patient):",ds.ImagePositionPatient)
    print("Slice Location      :", ds.SliceLocation)
  
    #Image Information(Group:0028)
    print("\n光度測定解釈        :", ds.PhotometricInterpretation)
    print("画像の列数(幅)    :", ds.Rows)
    print("画像の行数(高さ) :", ds.Columns)
    print("画素間隔      :", ds.PixelSpacing)
    print("Bits Allocated      :", ds.BitsAllocated)
    print("Bits Stored         :", ds.BitsStored)
    print("High Bit            :", ds.HighBit)
    print("Pixel Representation:", ds.PixelRepresentation)
    print("Window Center       :", ds.WindowCenter)
    print("Window Width        :", ds.WindowWidth)
    print("Rescale Intercept   :", ds.RescaleIntercept)
    print("Rescale Slope       :", ds.RescaleSlope)
  
if __name__ == '__main__':
    dirname = "../dcmdir1/"
    files = os.listdir( dirname )
    for filename in files:
        displayDicomMainTag(dirname + filename)



プログラムはディレクトリ'../dcmdir1'の中のDICOM画像ファイル名を読み込み,各ファイルのタグ情報を表示します。

※DICOM画像はここにあります。私のCT画像です。この実験以外では使用しないでください。


基本情報の表示


DICOM画像の主な基本情報が以下のように表示される(Brain01を例に)。

FILE NAME: ../dcmdir1/Brain01
SOP Instance UID   : 1.2.392.200036.9116.2.6.1.16.1613469034.1289543971.629951
検査日             : 20101112
検査時間       : 153820.000
アクセッション番号 : 838
画像診断装置       : CT


DICOM画像は世界で唯一のID(Uniqe ID)が振られています。
それがSOP Instance UIDと呼ばれるIDです。
ここでは'1.2.392.200036.9116.2.6.1.16.1613469034.1289543971.629951'という値がデータエレメントに格納されています。
このピリオドで区切られた数値の意味は次のようになります。
  1: ISO
  2: 加盟機関(経済産業省)
  392: 日本工業標準調査会
  200036: 日本画像医療システム工業会 (JIRA)
  9116: ベンダーコード(JIRA ホームページで検索可能 )   
  2.6.1.16.1613469034.1289543971.629951': ベンダーが自由に決める枝番

SOP Instance UIDは世界に一つしかない値なので,この値でDICOM画像のファイル名をリネームすれば,絶対に重複して存在になります。

各画像には検査日検査時間も格納されています。

アクセッション番号はオーダエントリシステム等上位の病院情報システムから発行されMWM(Modality Worklist Management)により画像診断装置に転送され,DICOM画像のデータエレメントに格納されます。
電子カルテなど病院情報システムからこの値を使って画像を呼び出すことができます。

画像診断装置は'CT'です。


患者情報の表示


患者情報には患者氏名やIDだけでなく,生年月日や性別,年齢も格納されています。

患者名    : UESUGI^MASAHITO
患者ID    : 09005315



検査情報の表示


検査情報にはCT撮影に関する情報がデータエレメントに格納されています。

検査部位は検査の対象とする名称が格納されています。
ここでは頭部CTなので'HEAD'になっています。

スライス厚は画像の厚みを示し,mm単位です。
ここでは5mmの厚みの画像であることを示しています。

画像再構成関数は,骨や肺野など詳細な構造を見る場合と,脳や肝臓などの充実組織みる場合で最適な関数用います。
再構成に使用した関数名が格納されています。


検査部位    : HEAD
スライス厚   : 8.0
画像再構成関数 : FC21

Study Instance UID  : 1.2.392.200036.9116.2.6.1.16.1613469034.1289543900.390492
Series Instance UID : 1.2.392.200036.9116.2.6.1.16.1613469034.1289543929.202106
Series Number       : 1
Image Position (Patient): ['-120.000', '-119.7761', '-462.6741']
Slice Location      : +430.00


Study Instance UIDは,1検査にユニークに付けられるIDでです。

Series Instance UIDは1つの検査内で複数の異なる手法(例えば造影剤なしとあり)で行った場合,それぞれにUIDが振られます。

Series Numberは,通常Series Instance UIDが変わるごとにシーケンシャルに振られる番号です。
検査画像をシリーズ毎に分けたい場合,この値を使ってディレクトリに分ける(後述の応用を参照)ことができます。

Image Position (Patient)は画像の撮影位置を表しています。
値は3次元のリスト(配列)で,[x, y, z]で表され,mm単位です。
xとyは患者ののる寝台の水平,垂直位置を表し,zは体軸方向の基準位置からの距離を表します。

Slice Locationは画像平面上の相対的な位置を表します。
Image Positionとは異なるので注意が必要です。


画像情報の表示


画像表示するのに必要な情報がこのグループのデータエレメントに格納されています。

光度測定解釈        : MONOCHROME2
画像の列数(幅)    : 512
画像の行数(高さ) : 512
画素間隔      : ['0.468', '0.468']
Bits Allocated      : 16
Bits Stored         : 16
High Bit            : 15
Pixel Representation: 1
Window Center       : 40
Window Width        : 80
Rescale Intercept   : 0
Rescale Slope       : 1


光度測定解釈はグレー画像の場合,'MONOCHROME1'または'MONOCHROME2'が入っています。
画素値の最低と最大を白または黒と判断するために使います。
画素値が最低の時,'MONOCHROME1'は白,'MONOCHROME2'は黒と解釈します。
また,Pixel Representationはモノクロで1チャンネルの画像なので'1'が格納されています。

一方,カラー画像の場合は光度測定解釈に’RGB’と格納され,Pixel Representationの値は'3'になります。

画像の列数(幅)画像の行数(高さ)はDICOM画像の幅と高さを表します。
ここでは512×512の画素数の画像であることを示しています。

画素間隔は1画素の大きさをmm単位で表します。
この値のおかげで,腫瘍などの大きさを知ることができる。

Bits AllocatedBits StoredHigh Bitは1画素に関する情報を表しています。
Bits Allocatedは1画素に割りつけられたビット数を表し,Bits Storedは実際に画素値として有効なビット数を表し,High Bitは最上位ビットのビット位置を表しています。

次の2つの場合,1画素の解釈が異なります。
  Bits Allocated      : 16
  Bits Stored         : 10
  High Bit            : 15

  Bits Allocated      : 16
  Bits Stored         : 10
  High Bit            : 9
上の場合,16ビットのうち上位10bitが有効な画素データです。
下の場合,下位10bitが有効な画素データです。
同じ有効な10ビットのデータでも,High Bitの値で解釈が変わります。

Window CenterWindow Widthは16bitの画素を最適に表示(8bitスケールに変換)するための条件が入っています。
Brian(脳)では WC=40, WW=80が格納されていますが
Abdomen(腹部)では WC=25, WW=300が格納されています。
部位により表示する条件が異なります。

Rescale InterceptRescale Slopeは(7fe0,0010)の画像のデータが入ったデータエレメントの画素データをCTであればCT値に,MRIであればMR信号値に変換するパラメータです。
CT値は通常ー1000から+1000の値をとります。
もし,データエレメントに格納されている画素値が符号なしの0から2000までの値が格納されているのであれば,Rescale Interceptに変換のための適当な値が格納されます。

応用:DICOM画像をシリーズ単位に保存する


いつもの'../dcmdir1'の頭部,胸部と腹部のCT画像を'./Series'のディレクトリの中にシリーズ番号のディレクトリに分けて保存することを考えてみます。

また,ファイル名を'元のファイル名.SOP Instance UID'に変換して各シリーズ番号のディレクトリに保存します。

dicomRename.py

import os, sys
import pydicom

def saveSeries(dirname, savedir):
    files = os.listdir(dirname)
  
    if not os.path.isdir(savedir):
        os.mkdir(savedir)
  
    for filename in files:
        ds = pydicom.read_file(dirname + filename)
        print(filename, ds.SeriesNumber)
      
        seriesdir = savedir + str(ds.SeriesNumber) + "/"
            
        if not os.path.isdir(seriesdir):
            os.mkdir(seriesdir)
          
        newfilename = seriesdir + filename + "." + ds.SOPInstanceUID
        ds.save_as(newfilename)
      
if __name__ == '__main__':
    dirname = "../dcmdir1/"
    savedir = "./Series/"
  
    saveSeries(dirname, savedir)


実行結果は以下のように表示されます。
頭部CT画像はシリーズ1のディレクトリに,胸腹部のCT画像はシリーズ2のディレクトリに保存されます。

ファイル名もSOP Instance UIDが付加されていることがわかります。


$ python dicomRename.py
Abdomen01 2
Chest02 2
Chest01 2
Brain01 1
Abdomen03 2
Abdomen02 2
Brain02 1
Chest03 2



プログラムの概要


プログラム実行時に最初に実行されるmain関数を見ると,
'../dcmdir1/'は元のDICOM画像が格納されたディレクトリ
'./Series/'はシリーズ毎に分類して保存するディレクトリです。

saveSerise関数は,
はじめに変数dirname内のDICOM画像のリストを作成しリストfilesに格納します。
    files = os.listdir( dirname )

シリーズ単位で保存するディレクトリsavedirがもしなければ,savedirを作成します。
    os.mkdir( savedir )

for文でリストfilesのファイルを一つづつfilenameに入れ以下の処理を行います。
DICOM画像をdsに読み込み,シリーズ番号を得て,シリーズのディレクトリを作成する。
ここでds.SeriesNumberは数値であるためIntegerと解釈される。そのためメソッドstr()を使って明示的に文字列に変換しています。
    seriesdir = savedir + str(ds.SeriesNumber) + "/"
もし,このディレクトリがなければ作成します。

次に既存のファイル名にSOP Instance UIDを付加した新しいファイル名のパスを作成する。
    newfilename = seriesdir + filename + "." + ds.SOPInstanceUID

この新しいファイル名を用いて,DICOM画像をシリーズディレクトリに保存します。  
    ds.save_as( newfilename )

以上でファイル名にSOP Instance UIDを加え,シリーズに分けて画像を保存することができます。


まとめ

DICOM画像のメタ情報について学びました。
メタ情報には患者の基本的な情報や,検査や画像を管理するためのユニークなID(UID)があることを学びました。
また,画像を表示するための表示条件も含まれることを学びました。




0 件のコメント:

コメントを投稿