福岡人データサイエンティストの部屋

データサイエンスを極めるため、日々の学習を綴っています。

【医療画像AI】DICOMファイルは扱いが難しい?#002



こんにちは!こーたろーです。


再開したばかりですが、早速壁が・・・・医療画像の取扱いは結構難しいことが分かってきました。


なぜなら、今回テーマに挙げているように、DICOMファイルを使うからです。


DICOMデータの変換をするツールができたら、公開したいと思いますので、こうご期待!


今回は、DICOMファイルをTensorflowで扱えるようにする処理を行っていきます。


DICOMファイルとは

今回調べて初めて知ったのですが、DICOMファイルとは、医療データ通信の国際標準規格で、Digital Imaging and Communications in Medicineの略だそうです。


略称は「ダイコム」と呼ぶらしい。。


主に、CTやMRI、CRの医療画像で用いるらしいです。


つまり、DICOMを使えないと医療画像は扱えないということです。(本当かどうかは確認していませんが。。汗)


オープンデータを調べてみるとDICOMデータの状態で提供されているものが多いという感じでした。


もちろん、これまで同様、JPEGPNGなどもあるようですが、DICOMが使えるようにならなくてはなりません。


さらに調べると、DICOM画像はタグ情報を含んでおり、フォーマット名やデータ超、ユニークなインスタンスUID、患者情報、撮影時間など、多くのタグ情報があるそうです。

DICOMデータのダウンロード

さて、DICOM画像データってどこにあるの?という話ですが、ここでは「https://www.cancerimagingarchive.net/」という、がん研究のための医療画像オープンデータベースを紹介します。



こちらのサイトで、「Access the Data」⇒「Browse Data Collections」と進むと、いろいろと提供されたデータがダウンロードできます。


今回は、この中から「SPIE-AAPM Lung CT Challenge」を探してダウンロードします。





「TCIA_SPIE-AAPM_Lung_CT_Challenge_06-22-2015」


というファイルがダウンロードされます。
しかしこのファイル、開けないのです!(展開できず、データがそのままでは使えない)

なんと「.tcia」というファイル形式!なにこれ?

TCIAファイルを開く!画像データを入手!

どうやらこのtciaファイル、開くにはJavaベースのツールが必要らしいのです。


そこで、「NBIA Data Retriever」をインストールすることに!

Downloading TCIA Images - TCIA Online Help - Cancer Imaging Archive Wiki
こちらから、OSにあったインストーラーをダウンロードし、インストールをします。

すると、先ほどダウンロードしたtciaファイルが、図のようになります。

これで、ファイルが開けるようになります。

ファイルを開くと、Javaプログラムが走り、ダウンロード用の画面がでてきますので、パスを指定してダウンロードします。


ライブラリ、オブジェクトのインポート



それでは、画像の前処理を行っていきます。


まずはライブラリ及び必要なオブジェクトのインポートです。


pydicomは、DICOMファイルを利用するためのライブラリのため、仮想環境にインストールされていない場合は、インストールを行います。


Anacondaから該当の仮想環境Terminalを開いて、以下を実行します。

anaconda show conda-forge/pydicom
conda install --channel https://conda.anaconda.org/conda-forge pydicom 



それでは、pythonを開いて、必要なライブラリ・オブジェクトをインポートします。

import numpy as np
import cv2
import os
import pydicom
from os import listdir
from keras.preprocessing.image import load_img, img_to_array



データのロード

ダウンロードしたファイルは、分かりやすい場所にフォルダを作成してから保存しておきます。
画像を1つロードしてみます。

CTimage = pydicom.read_file('./CTimages/1-001.dcm')



pydicomのread_fileメソッドを使って、画像データの情報を配列に格納します。

画像をプロットしてみます。

plt.imshow(CTimage.pixel_array, cmap='gray')









データ配列変換



TensorFlowに入力できる構造とするために、4次元配列にする。


4次元データとしては、「画像のインデックス」「横(幅)」「縦(高さ)」「色彩(チャネル)」の次元で構成される。


配列を始めに準備するために、以下のようなコードを実行し、空の4次元配列を準備する。


w,hはそれぞれ画像あたりの横(幅)と縦(高さ)を画像から抽出して、画素数を表している。

w = CTimage.Columns
h = CTimage.Rows
D4d = np.zeros((1,h,w,1))



空の箱を作ったら、次はh,wの配列に対して、画像のデータを抽出して、4次元配列に入れていく。



tmp = np.zeros((h,w))
tmp=CTimage.pixel_array
tmp2= np.reshape(tmp,(h,w,1))

D4d[0]=tmp2

4次元配列の0番目に、tmp2として、1枚の画像データが入ったことになる。
これを、フォルダにある全画像に対して行い、全ての画像をD4dの4次元配列に格納することで、データの処理が終わる。



files = sorted([filename for filename in listdir('./CTimages/') if not filename.startswith('.')])
n-file = len(files)

tmp = np.zeros((h,w),dtype="float32")
CTdata = np.zeros((n-file, h, w, 1),dtype="float32")

for i in range(0, n-file):
    Img = pydicom.read_file('./CTimages/%s'%files_CT[i]) 
    
    intercept = Img.RescaleIntercept
    slope = Img.RescaleSlope
    slicenum = Img.InstanceNumber
    
    tmp = Img.pixel_array
    tmp = slope*tmp+intercept

    tmp3d = np.reshape(tmp,(h,w,1))
    CTdata[slicenum-1] = tmp3d



先述の通り、「画像のインデックス」「横(幅)」「縦(高さ)」「色彩(チャネル)」


「画像のインデックス」・・・上記のコードでは、画像をfiles配列に取り込み、そのデータ長さ(ファイル数)を取り出している。
その他の部分は、h,w,1構造でできてる。
これらをforループにて、tmp3に格納することで、4次元データが完成する。

なお、途中のintercept(リスケール切片)とintercept(リスケール傾斜)については、調べたところ、

Assigned pixel values now have the following logic:

If the image has the Rescale Slope, Rescale Intercept and the Pixel Intensity Relationship Sign attributes, all of them are applied with a simple linear correction:
Pcorrected=Sign∗Slope∗PPraw+Intercept
Images from newer linac platforms appear more likely to have this attribute.

If the image only has the Rescale Slope and Rescale Intercept but not the relationship tag then it is applied as:
Pcorrected=Slope∗Praw+Intercept.
This is the most common scenario encountered to date.

DICOMデータにリスケール切片とリスケール傾斜のデータがある場合は、ピクセルデータを線形式で変換する処理が一般的ということらしいです。



医療画像の世界は奥が深いですね。


引き続きやっていきます!




ではでは。