【初心者向け】基礎&実践プログラミング

初心者がつまづきやすいところ、最短で実力が身につく方法をお伝えします。

【Python】DICOMからPNGやCSVに変換

f:id:AIProgrammer:20200501170605p:plain

はじめに

AIを作成するために、MRI画像をDICOM形式からPNG形式あるいはCSV形式に変換する必要があった。 件数は1700件ほど。 有名なものとしてはDICOM Cenverterがあるが、大量のDICOMをInputすると固まってしまう。 (199.99$で買わなきゃいけないのか??) そこで、pythonを使ってDICOMからPNG形式あるいはCSV形式に変換するコードを作成した。

前準備

DICOMの読み取りに必要なpydicomとPNGとして保存する上で必要なopencv-pythonを用意する。

$ pip3 install pydicom
$ pip3 install opencv-python

準備

1つのフォルダの中に変換したいDICOMを用意する。

$ ls
instance_1.dcm   instance_14.dcm  instance_19.dcm  instance_6.dcm
instance_10.dcm  instance_15.dcm  instance_2.dcm   instance_7.dcm
instance_11.dcm  instance_16.dcm  instance_3.dcm   instance_8.dcm
instance_12.dcm  instance_17.dcm  instance_4.dcm   instance_9.dcm
instance_13.dcm  instance_18.dcm  instance_5.dcm

実行

以下のコードを実行する。

import numpy as np
import pydicom  
import glob
import cv2

def dcm2png_csv(dcm):
    d = pydicom.read_file(dcm)
    value = d.pixel_array
    wc = d.WindowCenter
    ww = d.WindowWidth
    max, min = wc + ww / 2, wc - ww / 2
    value_std = 255 * (value - min) / (max - min)
    cv2.imwrite((dcm[:-4]+'.png'), value_std)
    np.savetxt((dcm[:-4]+'.csv'),value,delimiter=',')

for dcm in glob.glob('*dcm'):
    dcm2png_csv(dcm)

必要なmoduleのimport

import numpy as np
import pydicom  
import glob
import cv2

DICOMの読み込み

DICOMのヘッダーから値まで読み込める。 "d.pixel_array"画像の画素値にあたる。 (大人の事情でヘッダー等はみせられません(泣))

d = pydicom.read_file(dcm)
value = d.pixel_array

コントラストの調節

値を読み込んでそのままPNGに保存してはコントラストがおかしな画像がでてくる。 MRI画像は16 bitでデータを収集されているのに対し、PNGは8 bitであるためおかしくなる。 DICOMのタグの中でコントラストを決定するWindow Center(WC)とWindow Width(WW)を取得し、それが8 bitの状態で正しく見えるように正規化する。

wc = d.WindowCenter
ww = d.WindowWidth
max, min = wc + ww / 2, wc - ww / 2
value_std = 255 * (value - min) / (max - min)

ここのサイトの画像がわかりやすいです。この例では、12 bitのデータを8 bitに変換しています。

image.png

PNGおよびCSVの保存

PNGとCSVの保存をします。 PNGは8 bitですので正規化され"value_std"をPNGにします。 ですが、16 bitが8 bitですから情報としては少なくなってしまうわけです。 これがAIの判定精度に影響を与える場合があります。 ですので、生の値をCSVに保存することも重要です。 ということで、CSVにするのは"value"。

### PNG保存
cv2.imwrite((dcm[:-4]+'.png'), value_std)
### CSV保存
np.savetxt((dcm[:-4]+'.csv'),value,delimiter=',')

結果

わかりずらいですが、PNGが増えたことがわかります。

$ ls
instance_1.dcm   instance_14.dcm  instance_19.dcm  instance_6.dcm
instance_1.png   instance_14.png  instance_19.png  instance_6.png
instance_10.dcm  instance_15.dcm  instance_2.dcm   instance_7.dcm
instance_10.png  instance_15.png  instance_2.png   instance_7.png
instance_11.dcm  instance_16.dcm  instance_3.dcm   instance_8.dcm
instance_11.png  instance_16.png  instance_3.png   instance_8.png
instance_12.dcm  instance_17.dcm  instance_4.dcm   instance_9.dcm
instance_12.png  instance_17.png  instance_4.png   instance_9.png
instance_13.dcm  instance_18.dcm  instance_5.dcm
instance_13.png  instance_18.png  instance_5.png

とある日のスクリプト 2020/07/09

変換したCSVファイルだけを1つのフォルダにまとめる。
さらに、ログが出るようにした。

import numpy as np
import pydicom
import glob
import os
import shutil


def dcm2png_csv(dcm):
    d = pydicom.read_file(dcm)
    value = d.pixel_array
    np.savetxt('./csv/{}.csv'.format(dcm), value, delimiter=',')


# make save directry
if os.path.isdir('csv'):
    shutil.rmtree('csv')
    os.mkdir('csv')
else:
    os.mkdir('csv')

# convert
dcm_files = [file for file in glob.glob('*') if os.path.isfile(file)]
for i, dcm in enumerate(dcm_files):
    if i % 10 == 0:
        print('Converting {}/{}'.format(i+1, len(dcm_files)))
    dcm2png_csv(dcm)

とある日のスクリプト 2020/07/13

複数の被検者データを変化できるように改良。 ただし、とても姑息的。

import numpy as np
import pydicom
import glob
import os
import shutil


def dcm2png_csv(dcm, output):
    d = pydicom.read_file(dcm)
    value = d.pixel_array
    np.savetxt(output, value, delimiter=',')


# make save directry
if os.path.isdir('csv'):
    shutil.rmtree('csv')
    os.mkdir('csv')
else:
    os.mkdir('csv')

# convert
dcm_folder = [folder for folder in glob.glob('*') if os.path.isdir(folder)]
for i, folder in enumerate(dcm_folder):
    if i % 10 == 0:
        print('Converting {}/{}'.format(i+1, len(dcm_folder)))
    os.makedirs('csv/{}/QRAPMASTER'.format(folder))
    dcm_files = [file for file in glob.glob('{}/QRAPMASTER/*'.format(folder)) if os.path.isfile(file)]
    for dcm in dcm_files:
        output = 'csv/{}.csv'.format(dcm)
        dcm2png_csv(dcm, output)

まとめ

DICOMからPNGやCSVに無料変換するコードを作成した。 このコードをforで回せば一括変換できるので便利かと!



頑張れ!喝!!の代わりにB!ブックマークを押していただけるとただただうれしいです(^^)! ↓