マイブログ リスト

医療言語処理講座

2021年6月13日日曜日

 

Pyゼミ1.07 CT画像にDICOM Color LUTを使ってヒートマップ画像などを重ねてFusion画像を作ってみる

 

今回は何らかの結果(ヒートマップや推論マップなど)とその元画像を重ねるプログラムを作成します。

何らかの結果にはPydicomが提供するとColor LUTを利用してカラー画像に変換します。

Pyゼミ1.06ではImageJのColor LUTを使いましたが、ここではPydicomが提供するColor LUTを使います。

Color LUTを適用した画像をDICOM画像に重ねてFusion画像を作成してみます。


医療の世界ではFusionと呼んでいますが、Computer Visonの世界ではSuperimposeと呼んでいます。

 

具体的には下に示すような画像を作成します(グレイのCT画像に模擬的な結果のカラー画像を重ねています)。

     

fusion.png

 

ポイント

  • 何らかの結果を疑似的に2次元ガウス分布を用いて作成する。
  • pydiocmLUT適応機能を使ってグレイ画像をカラー画像に変換する。
  • グレイ画像のDICOM画像を読み込み、RGBのモノクロ画像(3チャンネル)を作成する。
  • OpneCVaddweighted()メソッドを使ってCT画像と重ね合わせる。


プログラムはここから

サンプルのDICOM画像はここから


まずは必要なライブラリについて

以下のライブラリをインポートします。


import cv2, math

import numpy as np

import pydicom

from pydicom.pixel_data_handlers.util import apply_color_lut



pydicomが提供するLUTを設定する

pydicom8つのLUTを提供しています。

DICOM画像にLUTを適応するためにはapply_color_lut( )メソッドを使います。

引数にはpydicomが提供するLUTの名称を与える必要があります。

ここでは、このLUTの名称を予めリストlutarrに格納しておきましょう。


lutarr = ["PET",                        #0

          "HOT_IRON",                 #1

          "HOT_METAL_BLUE",  #2

          "PET_20_STEP",           #3

          "SPRING",                      #4

          "SUMMER",                    #5

          "FALL",                           #6

          "WINTER"]                      #7

 lutnm = lutarr[0]           # Set LUT Name with index of lutarr


LUTの名称をindexの値で変数lutnmに格納しておくと、数値を変えるだけでLUTを変更することができて便利です。


 

ガウス分布を作成する関数gaussianを作成する

 

この関数は引数にガウス分布の中心の座標、cxcyと標準偏差sgm、そし生成する画像のサイズsizeを与えます。

はじめに2次元のガウス分布を用いてグレイ画像を作成するためにgaussian()関数を作成します。


# Gaussian distribution

def gaussian(cx, cy, sgm, size):

    mapimg = np.zeros((size, size))

 

    for h in range(size):

        ph = 1/math.sqrt(2.0*math.pi*sgm)*math.exp(-math.pow((h - cy), 2)/2/sgm)

        for w in range(size):

            pw = 1/math.sqrt(2.0*math.pi*sgm)*math.exp(-math.pow((w-cx), 2)/2/sgm)     

            mapimg[h,w] = ph*pw

 

    vmax = np.max(mapimg)

    print(">>max gaussinan=", vmax)

 

    mapimg = mapimg / vmax

    return mapimg


ガウス分布の中心座標cxcy、ガウス分布の広がりsgmと生成画像サイズsizeを指定します。

ここでは、以下の値を与えて、gaussian関数を呼びだし、2次元ガウス分布をpmapに代入します。2次元ガウス分布は最大値が1.0になるように正規化されています。

 

# Set gaussian condition

size = 512            # map size

x, y = 350, 256     # coordination of Gaussian center

sgm  = 500           # Sigma of Gaussian distribution

pmap = gaussian(x,y,sgm, size)

 

pmapの最大値は1.0なので、8ビットの最大値255になるように変換して画像に保存します。

 

pmap *= 255         # convert [0.0~1.0] to [0.0~255.0]

print(">>Max =", np.max(pmap))

cv2.imwrite("mapOrg.png", pmap)

 

保存されたmapOrg.pngは以下のようになります。

mapOrg.png

 

この画像にPydicomが提供するColor LUTを適用してみましょう。

 

cimg = apply_color_lut(pmap, palette=lutnm)

cimg = cimg[ : , : , : : -1]

cv2.imwrite("mapLut.png", cimg)

 

カラー画像保存する際、BGRRGBに変換するので cimg = cimg[ : , : , : : -1] とします。

 

結果の画像mapLut.pngは次のように表示されます。

mapLut.png


グレイスケールを画像に入れる

画素値と色の関係がよくわからないので、グレイスケールを左に入れてみましょう。

このグレイスケールはColor LUTを適用するとカラースケールになります。

 

# Add color scale

for y in range(256):

    pmap[350-y, :15] = y

 

cimg = apply_color_lut(pmap, palette=lutnm)

cimg = cimg[ : , : , : : -1]

cv2.imwrite("mapLut2.png", cimg)

 

このスケールはpmapの縦350の位置から上に向かって画素値0から255を代入します。

スケールの幅は15画素です(:15で指定しています)

結果mapLut2.pngは以下のように表示されます。


mapLut2.png

 

DICOM画像を読み込む

それではDICOM画像Brain01を読み込んでみます。

 

# Read Dicom file   

dcmfnm = "../dcmdir1/Brain01"

ds = pydicom.dcmread(dcmfnm)

print(">>ds =",ds)

 

wc  = ds.WindowCenter         

ww  = ds.WindowWidth                 

img = ds.pixel_array                        

 

max = wc + ww/2                    

min = wc - ww/2     

  

img = (img - min)/(max - min) * 255    

img[img > 255] = 255                  

img[img < 0]   = 0                         

img = img.astype('uint8')   # float32 → uint8

print(">> image shape=",img.shape, img.dtype)

 

# Save png image and read png image

cv2.imwrite("./brain01.png", img)

 

DICOMのタグ情報を読み込みウインドウセンタwcとウインドウ幅wwを使ってウインドニング処理を行います。

また、デフォルトfloat32uint8の符号なし8ビットに変換しているます。

この画像のshapeとタイプを表示すると次のように表示されます。

 

>1> image shape= (512, 512) uint8

 

shape(512,512)と表示され、512×512のグレイ画像であることを示しています。

Fusionを行うためには2つの画像がカラー画像であることが必要です。

 

グレイ画像をカラー画像に変換する3つの方法

 1チャンネルのグレイ画像を3チャンネルのカラー画像に変換する方法を紹介します。


方法1:保存した画像をimread()メソッドで読み込む。

CV2imreadのデフォルトはグレイ画像もカラー画像として読み込まれます。

 

img2 = cv2.imread("./brain01.png")

print(">2> image2 shape=", img2.shape, img2.dtype)

 

結果は以下のように、読み込まれた画像img23チャンネルである、つまりRGBのカラー画像であることを示しています。

 

>2> image2 shape= (512, 512, 3) uint8


明示的にimread()グレイ画像として読み込むときには引数にcv2.IMREAD_GRAYSCALEを使って、v2.imread(filename, cv2.IMREAD_GRAYSCALE)として読み込むか、cv2.IMREAD_GRAYSCALEの代わりに を使ってもOKです。

 

方法2cv2merge()メソッドを使います。

merge()メソッドを使って同じ3枚の画像imgを統合します。

 

# Merge 3 imags

img3 = cv2.merge((img, img, img))

print(">3> image3 shape=", img3.shape, img3.dtype)

 

RGBに同じimgをマージして3チャンネルの画像を作成しています。

結果は次のように、確かに512×512画素の3チャンネルの画像img3ができています。


>3> image3 shape= (512, 512, 3) uint8


逆に複数のチャンネルをもつ画像を分割するにはsplit()メソッドを使って、r, g, b = cv2.split(img) のように記述します。

  

方法3numpyzerosメソッドを使って3チャンネルの画像を作成する。

 zeros()メソッドを使い、512×512の3チャンネル、符号なし8ビットの画像img4をあらかじめ作成します。


# Assing image to 3 chanel image

img4 = np.zeros((512, 512, 3), dtype=np.uint8)

img4[ : , : , 0] = img

img4[ : , : , 1] = img

img4[ : , : , 2] = img

print(">4> image4 shape=", img4.shape, img4.dtype)

 

あらかじめ作成したimg4の012の各チャンネルに画像imgを代入します。

実行結果は3チャンネルの画像img4ができています。


>4> image4 shape= (512, 512, 3) uint8

 

画像にカラースケールの背景を入れる

3チャンネルに変換した画像img2にカラースケールの発色をよくするため画素値128で埋めます。

これを入れないとカラースケールが暗くなります。

 

# For color scale

img2[350-256 : 350, : 15] = 128

 


2つの画像を重ね合わせる

それではaddWeighted()メソッドを使って2つの画像img2cimgを重ね合わせます。

 

# Create fusion image with addWeighted()

rimg = cv2.addWeighted(src1=img2, alpha=1.0, src2=cimg, beta=0.5, gamma=0)

cv2.imwrite("fusion.png", rimg)


結果画像fusion.pngは次のように表示されます。

fusion.png

 

addWeighted()メソッドの引数alphabetaは2つの画像の重ねるときの重みになります。

主たる画像、ここではBrain CT画像のimg21.0とし、ガウス分布画像のcimg0.5と重みを小さくして重ね合わせています。

bataの値については場合により調整してみましょう。

 

 

Post Script:

実はaddWeighted()メソッドを使った画像の重ね合わせは結構はまりました。

大前提は2つの画像はカラー画像であることです。

しかし、DICOM画像をpydicomで読み込んだときは1チャンネルの画像、その画像をいったん保存し、imread()メソッドで読み込むとデフォルトでカラー画像として読み込まれます。

したがって、ある時はaddWeighted()で上手く重なり、あるときは上手くいかない。

この原因を明らかにするのにはまってしまいました。気を付けましょう。

2020年11月20日金曜日

JSRT vol76No11 「AI による放射線技術の発展」特集号誌上講座

 日本放射線技術学会雑誌 Vol 76 No11 Nov 2020 「AI による放射線技術の発展」特集号誌上講座が発刊されました.

この特集号に「Pydicomを使ってDICOM画像を操る」と題してPydicomの解説とサンプルプログラムを投稿しました.

サンプルプログや補足などを以下に記述します.

1.Pydicomとは

   Pydicomを簡単に紹介しました.


2.Pydicomプログラミングの準備

2.1.前提条件

  • 筆者はAnacondaでPython環境をVersion3.7の環境を構築しました.
  • Anacondaにはnumpy, matplotlib, pyQt5は含まれているので改めてインストールの必要はありません.
もしインストールされていないライブラリがあれば以下からインストールを行ってください.


2.2. DICOM画像データセット

JSRTの標準デジタル画像データベース(DICOM版)の胸部CR画像をダウンロードして解凍します.

2.3.Pydicomのインストール

Pydicomのドキュメント(pydicom documentation,https://pydicom.github.io/pydicom/stable/)も是非参照してください.有用な情報がたくさん得られます.


3.Pydicomを使ってDICOM画像を操る

記事内で紹介したサンプルプログラムをダウンロードして解凍してください.

内容は以下の通りです.

3.1.DICOM画像を表示する

3.2.DICOM画像をPNGに変換する

3.3.DICOM画像の匿名化

3.4.DICOMタグ情報取得の関数化

3.5.セグメンテーションツールを作成する


AI研究のために自施設のDICOM画像を有効に利用できることを願っています.


質問や要望などありましたら uesugi@do-johodai.ac.jp までメールをください.






2020年3月23日月曜日

Pyゼミ0.05 備忘録 Ubuntu18.04にTensorFlowとChainerをインストールする

昨年2019年12月に突然PFN社がChainerの開発の中止を発表.
日本発のAIフレームワークと整然としたコードが好きだったので,長く使おうと思っていたのに開発中止のニュース.
残念です.

世の中のメジャーはGoogleのTensorFlowということで,研究室のUbuntu16.04を18.04にアップグレードと合わせてTensorFlowをインストールしました.
まだ,Chainerの資産があるのでChainerもインストールしておきます.
その他,画像関連のAI開発に必要なライブラリもインストール.
これらの作業の備忘録ですので,見た目は良くないので,勘弁.

Key word:Ubuntu 18.04,TensorFlow,Chainer,GPU


インストールPCの仕様

インストールを行ったPCの仕様は以下の通りです.

  • CPU     Core i7 or i5
  • メモリ  16GB or 8GB
  • GPU       GeForce 1080 or 1060
  • Storage  240GB SSD ~ 1Tb HDD 


行った作業項目

  1. Ubuntu 18.04のインストール(詳細割愛)
  2. NVIDIAドライバーとCUDAのインストール
  3. CUDAのパスを.bashrcに設定する
  4. cuDNNのインストール
  5. Anacondaのインストール
  6. TensorFlowとKerasのインストール
  7. cupyのインストール
  8. Chainerのインストール
  9. OpenCVのインストール(画像処理関連ライブラリ)
  10. DCMTKのインストール(画像圧縮,解凍のツールキット)
  11. ImageJのインストール(DICOM画像のフリービューワ)
  12. Dropboxのインストール(おまけ)


具体的作業手順

1)Ubuntu 18.04 インストール

  • インストールはSecure BootをDisableにしていること.
  • インストール後,アップデートを実行・完了すること.

2)NVIDIA DriverとCUDAのインストール

参考URL

 CUDA Toolkit 10.2 Download
 https://developer.nvidia.com/cuda-downloads

ダウンロード条件

 Linux
 x86_64
 Ubuntu
 18.04
 dev[network]

以下の作業をターミナルから入力し実行する.

$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
$ sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
$ sudo add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"
$ sudo apt-get update
$ sudo apt-get -y install cuda

再起動する

$ sudo reboot

確認

次のコマンドを入力してドライバーがインストールされたことを確認する
$ nvidia-smi
(以下の情報が表示されればOK,DriverとCUDAのバージョンが表示されている)
Fri Mar  6 18:15:09 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.33.01    Driver Version: 440.33.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  On   | 00000000:01:00.0  On |                  N/A |
| 41%   39C    P2    23W / 120W |    233MiB /  6075MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0       984      G   /usr/lib/xorg/Xorg                            18MiB |
|    0      1014      G   /usr/bin/gnome-shell                          48MiB |
|    0      1312      G   /usr/lib/xorg/Xorg                            95MiB |
|    0      1445      G   /usr/bin/gnome-shell                          66MiB |
+-----------------------------------------------------------------------------+

3)CUDAのパスを.bashrcに設定

エディタgeditを使って.bashrcファイルを編集する. 
$ gedit .bashrc

以下の3行を.basrcファイルの最後に追加し,保存する.
これでCUDAのパスが通るようになる.
#CUDA
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"

確認

$ source .bashrc
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Wed_Oct_23_19:24:38_PDT_2019
Cuda compilation tools, release 10.2, V10.2.89

4)cuDNNのインストール

https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/
からダウンロード:libcudnn7_7.6.5.32-1+cuda10.2_amd64.deb
$ sudo dpkg -i libcudnn7_7.6.5.32-1+cuda10.2_amd64.deb

参考URL

【Ubuntu18.04】NVIDIAドライバ・CUDA・cuDNNのインストール方法
https://atsuyakoike.hatenablog.com/entry/2019/08/08/214530


5)Anacondaのインストール

https://www.anaconda.com/distribution/
ダウンロード:Anaconda3-2019.10-Linux-x86_64.sh
$ bash Anaconda3-2019.10-Linux-x86_64.sh

・・・・・
installation finished.
Do you wish the installer to initialize Anaconda3
by running conda init? [yes|no]
[no] >>>yes

確認

$ source .bashrc
$ conda -V
conda 4.7.12


6)TnesorFlow と Kerasのインストール

TensorFlowのインストール

GPU対応のTensorFlowをインストールする

$ conda install tensorflow-gpu

確認

(TensorFlowをimportして,デバイスにGPUの形式が表示されていることを確認する)
$ python
Python 3.7.4 (default, Aug 13 2019, 20:35:49) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow    
>>> from tensorflow.python.client import device_lib
>>> device_lib.list_local_devices()
2020-03-06 16:09:01.783756: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
(省略)
2020-03-06 16:09:01.870307: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1618] Found device 0 with properties: 
name: GeForce GTX 1060 6GB major: 6 minor: 1 memoryClockRate(GHz): 1.759
pciBusID: 0000:01:00.0
(省略)
2020-03-06 16:09:01.936563: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1304] Created TensorFlow device (/device:GPU:0 with 5412 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1060 6GB, pci bus id: 0000:01:00.0, compute capability: 6.1)
2020-03-06 16:09:01.937931: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x55efb35f1a50 executing computations on platform CUDA. Devices:
2020-03-06 16:09:01.937946: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): GeForce GTX 1060 6GB, Compute Capability 6.1
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
(省略)
incarnation: 12303617427411943325
physical_device_desc: "device: 0, name: GeForce GTX 1060 6GB, pci bus id: 0000:01:00.0, compute capability: 6.1"
, name: "/device:XLA_GPU:0"
device_type: "XLA_GPU"
memory_limit: 17179869184
locality {
}
incarnation: 2429606674858306080
physical_device_desc: "device: XLA_GPU device"
]

Kerasのインストール

$ conda install keras

参考URL

GPU付きのTensorflowをUbuntu18.04に入れる
https://qiita.com/python_walker/items/d599aeeea673bf89b7cb


7)cupyのインストール

$ pip search cupy
・・・
cupy-cuda102 (7.2.0)      - CuPy: NumPy-like API accelerated with CUDA
・・・

$ pip install cupy-cuda102

確認 

pythonを起動して
>>> import cupy as cp
>>> cp.__version__
'7.2.0'

参考URL

最新の cuda + cudnn + cupy を Ubuntu 18.04 へインストールする@2019年春版
https://qiita.com/aizakku_nidaa/items/3c97dbcc30e1995488a5

8)chainerのインストール

$ pip install chainer

確認 

pythonを起動して
>>> import chainer
>>> chainer.__version__
'7.2.0'


9)OpenCVのインストール

$ pip install opencv-python

確認 

pythonを起動して
>>> import cv2
>>> cv2.__version__
'4.2.0'

10)Pydicomインストール

$ pip install  pydicom

確認 

pythonを起動して
>>> import pydicom
>>> pydicom.__version__
'1.4.2'

11)DCMTKのインストール

$ sudo apt install dcmtk

確認

$ dcmdjpeg --version
(以下の内容が表示されればOK)
$dcmtk: dcmdjpeg v3.6.2 2017-07-14 $

dcmdjpeg: Decode JPEG-compressed DICOM file

Host type: Debian
Character encoding: UTF-8

External libraries used:
- ZLIB, Version 1.2.11
- IJG, Version 6b  27-Mar-1998 (modified)


12)ImageJのインストール

参考URL

https://imagej.nih.gov/ij/
ダウンロード:ij152-linux64-java8.zip
Homeで展開、起動してアイコンをお気に入りに登録する

おまけ)Dropboxのインストール

$ cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -

起動

$ ~/.dropbox-dist/dropboxd


以上です.

2020年2月16日日曜日

Pyゼミ2.05 PyQt5によるラジオボタンとチェックボックス

ラジオボタンとチェックボックスの使い方を学ぼう.


Keyword:PyQt5,ラジオボタン,チェックボックス


画像のセグメンテーションにラベルを付けるようなとき,ラジオボタン(どれか一つ選択)やチェックボックス(複数選択)を使いたいときがあります.

インターネットを調べるとラジオボタンやチェックボックスについての記事がいろいろあるけど,実際使ってみようとするといろいろと問題が発生します.
  • チェック付けた情報をどうやって得るの?
  • チェックボックスを増やしたり減らしたり簡単にしたいよ.

これらを短いプログラムで解決していこうと思います.
具体的には次のような仕様になります.
  • 3つの部位をラジオボタンで選択する.
  • 5つの状態をチェックボックスで選択する.
  • OKボタンをクリックすると,チェックのついた情報がコンソールに表示する.
  • ラジオボタンやチェックボックスの項目はリストで持ち,増やしたり減らしたりできる.

GUIのイメージは次のようになります.




プログラム概要


はじめに'__main__'を見てみる

リストpartsに3つの部位が格納され,stateにはLevel1からLevel5までの5つの状態が格納されています.

    parts = [ 'Brain' , 'Lung' , 'Abdomen' ]
    state = [ 'Level1' , 'Level2' , 'Level3' , 'Level4' , 'Level5']

リスト内の値を自由に追加や編集することでいろいろ応用可能です.

この2つのリストを引数にCheckBox_RadioButtonクラスを呼びだします.


次に,イニシャライザ__init__を見てみる

partsとstateの要素数をそれぞれself.nPtとself.nStに代入しています.
そして,ラジオボタンを生成するself.radbtnをボタンの個数分のリストを作成しています(とりあえず空白" "を値としてリストを作成).
このリストにあとでラジオボタンを作成します.

    self.radbtn = list(" " * self.nPt)

同様にチェックボックスのボタンを生成するリストself.chkboxも作成しています.

部位と状態のリストをクラス内で使用するためself.partsとself.stateに代入しています.


initUIを見てみよう


最初に部位を選択するラジオボタンを作る.

”部位”を表示するラベルlblPrtを作成しします.
ラジオボタンは複数のラジオボタンから一つ選択しますが,複数ラジオボタンをグループにまとめるためradbtngrpを作成します.

    self.radbtngrp = QButtonGroup()

ラジオボタンや”部位”ラベルを配置するBoxLayoutを作成します.
縦に並べるので,QVBoxLayoutを使い,それにラベルlblPrtを配置します.

        vboxPrt = QVBoxLayout()
        vboxPrt.addWidget(lblPrt, alignment=Qt.AlignTop | Qt.AlignHCenter)

次に部位の数分(self.nPt)繰り返してi番目のラジオボタンをリストself.radbtn[i]に作成します.

    self.radbtn[i] = QRadioButton( self.parts[i])

このラジオボタンに対して,チェック可能かどうかsetCheckableをTrueに,フォーカスするかどうかsetFocusPolicyについてフォーカスしないに,そして,ラジオボタンをチェックしたときの動作をclicked.connectを使ってself.clickedRadbtn関数を呼ぶようにします.
ラジオボタンのグループradbtngrpにaddButtonを使って,i番目のラジオボタンself.radbtn[i]とIDのiの値を追加します.
このIDはどのボタンがチェックされているか調べるのに使われます.
そして最後にvboxPrtレイアウトにaddWidgetを使って配置している.

            self.radbtn[i] = QRadioButton( self.parts[i])
            self.radbtn[i].setCheckable(True)
            self.radbtn[i].setFocusPolicy(Qt.NoFocus)
            self.radbtn[i].clicked.connect(self.clickedRadbtn)                           
            self.radbtngrp.addButton(self.radbtn[i], i)
            vboxPrt.addWidget(self.radbtn[i], alignment=Qt.AlignTop)  


次に,状態を選択するチェックボックスを作る

最初に”状態”のラベルlblSttを作成し,チェックボックスを配置するレイアウトvboxSttに配置する.

状態の数分(self.nSt)繰り返して,i番目のチェックボックスをリストself.chkbox[i]に作成し,このチェックボックスがチェックされたときの動作をclicked.connectを使ってself.clickedCbxbtn関数を呼ぶようにし,最後にvboxSttレイアウトにaddWidgetを使って配置します.

            self.chkbox[i] = QCheckBox(self.state[i],self)
            self.chkbox[i].stateChanged.connect(self.clickedCbxbtn)
            vboxStt.addWidget(self.chkbox[i], alignment=Qt.AlignTop)

このようにfor文を使うことで簡単にボタンを追加することができます.


OKボタンを作る.

ボタンをチェックした後,情報を取得するアクションとしてOKボタンokbtnをQPushButtonを使って作ります.
このokbtnをクリックしたときの動作をclicked.connectを使って,self.clickedOkbtn関数を呼び出すようにします.
OKボタンokbtnを配置するだけですが,レイアウトokboxを作成して.これにOKボタンを配置します.


レイアウトを作成する.

最後にラジオボタンのレイアウトvboxPart,チェックボックスのレイアウトvboxSttを水平にレイアウトするためhboxをQHBoLayoutで作成しこれに2つのレイアウトを配置ます.

        hbox = QHBoxLayout()
        hbox.addLayout(vboxPrt)
        hbox.addLayout(vboxStt) 

最後に,上のhboxとokboxを縦に配置するためにQVBoxLayoutを使ってvboxを作成し,これにhboxとokboxをレイアウトします.

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addLayout(okbox)


ボタンをクリックしたときの動作する関数を作る


クリックしたチェックボックスを調べる関数clickedCbxbtn

この関数では,どのチェックボックスがチェックされたのかコンソールに表示します.
チェックボックスself.chkbox[i]にチェックあるかどうかcheckState()を使って調べて表示します.

        for i in range(self.nSt):
            print(self.state[i], self.chkbox[i].checkState())


クリックしたラジオボタンを調べる関数clickedRadbtn

この関数はチェックされたラジオボタンをコンソールに表示します.
ラジオボタンのグループradbtngrpのどれがクリックされたのか,checkedId()を使ってIDを取得します.
このIDを用いてリストpartsのどれがチェックされているか知ることができます.

        checkid = self.radbtngrp.checkedId()         
        print( "PART:", self.parts[checkid] )


OKボタンがクリックされたらボタンの情報を表示するclickedOkbtn関数

ボタンのクリックされた情報を集約し,変数rsltStrにまとめます.
はじめにラジオボタンのIDを取得し,部位名称をrsltStrに代入します.

        checkid = self.radbtngrp.checkedId()   
        rsltStr = self.parts[checkid]

次に,チェックボックスchkbox[i]をひとつずつcheckState()を使って調べ,もしチェックされていれば値2が返るので,そのインデックス+1を変数rsltStrに追加します.

        for i in range(self.nSt):
            if self.chkbox[i].checkState() > 0:
                rsltStr += ":" + str(i+1)   

この変数rsltStrを表示すると,ラジオボタンとチェックボックスの状態を知ることができます.

        print("RESULT:", rsltStr)

例えば図のようにチェックしたとすると,結果は次のようになります.

コンソールに表示される結果は次のようになります.

---------- Clicked RadioButton
PART: Lung
---------- Clicked Changebox
Level1 0
Level2 0
Level3 2
Level4 0
Level5 0
========== Clicked OK ==========
RESULT: Lung:3

プログラムを入力して実行してみよう


# -*- coding: utf-8 -*-
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from PyQt5 import QtCore, QtWidgets

class CheckBox_RadioButton(QWidget):
    def __init__(self, Parts, State):
        super().__init__()

        self.nPt    = len(Parts)
        self.nSt    = len(State)       
        self.radbtn = list(" " * self.nPt)
        self.chkbox = list(" " * self.nSt)
        self.parts  = Parts  
        self.state  = State
        self.initUI()

    def initUI(self):
        """ Radio Button """
        lblPrt         = QLabel("部位")
        self.radbtngrp = QButtonGroup()
        vboxPrt        = QVBoxLayout()
        vboxPrt.addWidget(lblPrt, alignment=Qt.AlignTop | Qt.AlignHCenter)
        for i in range(self.nPt):
            self.radbtn[i] = QRadioButton( self.parts[i])
            self.radbtn[i].setCheckable(True)
            self.radbtn[i].setFocusPolicy(Qt.NoFocus)
            self.radbtn[i].clicked.connect(self.clickedRadbtn)                          
            self.radbtngrp.addButton(self.radbtn[i], i)
            vboxPrt.addWidget(self.radbtn[i], alignment=Qt.AlignTop)   
       
        """ CheckBox """
        lblStt  = QLabel("状態")
        vboxStt = QVBoxLayout()
        vboxStt.addWidget(lblStt, alignment=Qt.AlignTop | Qt.AlignHCenter)
        for i in range(self.nSt):
            self.chkbox[i] = QCheckBox(self.state[i],self)
            self.chkbox[i].stateChanged.connect(self.clickedCbxbtn)
            vboxStt.addWidget(self.chkbox[i], alignment=Qt.AlignTop)

        """ OK Button """
        okbtn = QPushButton("OK")
        okbtn.clicked.connect(self.clickedOkbtn)
        okbox = QHBoxLayout()
        okbox.addWidget(okbtn)
       
        """ Layout """
        hbox = QHBoxLayout()
        hbox.addLayout(vboxPrt)
        hbox.addLayout(vboxStt)       
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addLayout(okbox)
       
        self.setLayout(vbox)   

        self.setGeometry(100, 75, 250, 250)
        self.setWindowTitle("RadioButton&CheckBox")   
        self.show()
       
    def clickedCbxbtn(self):
        print("-"*10, "Clicked Changebox")
        for i in range(self.nSt):
            print(self.state[i], self.chkbox[i].checkState())
           
    def clickedRadbtn(self):
        print("-"*10, "Clicked RadioButton")
        checkid = self.radbtngrp.checkedId()        
        print( "PART:", self.parts[checkid] )
           
    def clickedOkbtn(self):
        print("="*10,"Clicked OK", "="*10)
        checkid = self.radbtngrp.checkedId()  
        rsltStr = self.parts[checkid]
        for i in range(self.nSt):
            if self.chkbox[i].checkState() > 0:
                rsltStr += ":" + str(i+1)     
        print("RESULT:", rsltStr)
       
if __name__ == '__main__':
    parts = ['Brain','Lung','Abdomen']
    state = ['Level1','Level2','Level3','Level4','Level5']
   
    app = 0     #For Spyder
    app = QApplication(sys.argv)

    ex = CheckBox_RadioButton(parts, state)
    sys.exit(app.exec_())

2019年9月27日金曜日

Pyゼミ1.06 DICOM CT画像をLUTで疑似カラーを付けてみる

CTのグレー画像をLUTを使ってカラー画像にしてみる。


keyword: DICOM, ImageJ, LUT(Lookup table)


CTやMR画像などはグレー画像で色がありません。
これに色を付けるには1つの画素値を赤(R),緑(G)と青(B)の3つの色に分ける必要があります。
グレーの画素値(0から255)をRGBに分解する対応表をLookup table(LUT)と呼びます。

ImageJのLUTでCT画像に色を付ける


画像処理ツールのImageJにはたくさんのLUTが揃っています。

ImageJのImage/Lookup TablesにたくさんのLUTを見ることができます。


これを使ってImageJでグレー画像に疑似カラーの色を付けることができます。
オリジナルのDICOM画像を表示します。
ImageJによるDICOM画像表示

 この画像に「16 Color」のLUTを使ってカラー化してみます。
LUT処理後のDICOM画像
このように,脳実質が緑,脳室が青,頭蓋骨が白,周囲の脂肪が赤く表示されます。グレーの画素値の違いを色を付けることで見やすくなります。

ImageJのLUTはImageJがインストールされたディレクトリImageの下のlutsのディレクトリの中に .lut ファイルとして存在します。


ImageJのLUTファイルを読み込む


プログラムreadImageJLut.pyは初めにLUTを入れるリストのためにnumpyとLUTを表示するためにmatplotlibをインポートします。

LUTファイル名を変数lutfnmに代入します。

LUTがファイルをOpenしてdtにLUTのデータを”rb”で,バイナリデータとして読み込みます。
 f = open(lutfnm, "rb")
 dt = f.read()
 f.close()

dtにはRGBの値が1次元のバイナリデータとして格納されているため整数型のnumpyのリストに変換します。
for文を使ってdtの要素を一つずつ取り出しリストrgbに入れます。
 rgb     = np.array( [ i for i in dt ] )

リストrgbにはRの成分256個,Gの成分56個,Bの成分256個が1次元に格納されているので,reshapeメソッドを使って,3x256の2次元リストに変換しています。
これをR,G,Bの各成分のリストr,g,bに代入します。
 r, g, b = np.reshape( rgb, (3,256) )

これで各画素値に対応するRGB成分がリストr,g,bに格納されました。
グレーの画素値がvのとき,各RGB成分は r[v], g[v], b[v]として取り出すことができます。

readImageJLut.py

import numpy as np
from matplotlib import pyplot as plt

lutfnm = "D:\Dropbox\Temporary\ImageJ\ij152-win-java8\ImageJ\luts\\16_Colors.lut"

f = open(lutfnm, "rb")
dt = f.read()
f.close()

print(">1>要素数:", len(dt), ",型:",type(dt))

rgb     = np.array([i for i in dt]) # [r0・・・r255 g0・・・g255 b0・・・b255]
r, g, b = np.reshape(rgb,(3,256))   #  赤,緑と青の成分をリストr,gとbに分解
print(">2>",len(r),len(g),len(b))

# 画素値(Gray)とRGB成分の表示
print("LUT\nGray\tRed\tGreen\tBlue")
for i in range(256):
    print(i,"\t", r[i],"\t", g[i],"\t", b[i])

# LUT値のグラフ表示
x = np.linspace(0,255,256)  # 0〜255を256分割する
plt.plot(x, r, color='red')
plt.plot(x, g, color='green')
plt.plot(x, b, color='blue')
plt.show()



 プログラムを実行してみよう


プログラムを実行するとはじめに次の2行が表示されます。

>1>要素数: 768 ,型: <class 'bytes'>
>2> 256 256 256


要素数は768と表示されています。これは256xRGBになります。
そしてImageJのLUTはバイナリデータでファイルに格納されているためバイト型になっています。

次にバイト型が整数型のリストに変換され,LUTが表示されます。

LUT
Gray    Red     Green   Blue
0        0       0       0
1        0       0       0
2        0       0       0
3        0       0       0
4        0       0       0
5        0       0       0
6        0       0       0
7        0       0       0
8        0       0       0
9        0       0       0
10       0       0       0
11       0       0       0
12       0       0       0
13       0       0       0
14       0       0       0
15       0       0       0
16       1       1       171
17       1       1       171
18       1       1       171
19       1       1       171
 ・・・・・・・・・
236      222     180     222
237      222     180     222
238      222     180     222
239      222     180     222
240      255     255     255
241      255     255     255
242      255     255     255
243      255     255     255
244      255     255     255
245      255     255     255
246      255     255     255
247      255     255     255
248      255     255     255
249      255     255     255
250      255     255     255
251      255     255     255
252      255     255     255
253      255     255     255
254      255     255     255
255      255     255     255


これは左の列のGrayの値の画素値がRGB成分に分解されるときの値を示しています。
この表がLUTの実体です。

最後にLUTの各値をプロットしたグラフが現れます。
16_Color.lutのカラー成分のグラフ
グラフは横軸がGrayの画素値,縦軸がRGBそれぞれの成分の値になります。
Grayが15以下ではRGBすべて0なので黒で表示され,240以上ではRGBすべて255なので白で表示されます。
Grayが16以上239以下ではRGBそれぞれの割合で混合され様々な色を出力することができます。


CT画像をLUTを使ってカラー画像にする


プログラムimageLUT.pyはDICOM画像を読み込むのためのpydicomモジュールと画像保存のためのcv2モジュールをインポートします。

プログラムの前半はLUTファイルを読み込みrgb各成分をリストr,g,bに読み込みます。
今回はLUTに”BRGBCMYW.lut”を使いました。

DICOM画像を読み込み変数dに代入します。
ウィンドウニング情報を変数wwとwcに,画像の高さと幅をrowとcolに,画像情報をimgに代入します。

DICOM画像のウィンドニング処理した後に,カラースケールを画像中に表示するために255~0の帯を画像に入れます。
 for y in range(256):            #カラースケース
     for x in range(50):         #スケールの幅
         img[350-y, x] = y       #画像中にスケールを入れる。
1行目のfor y in range(256):は,range(256)により変数yに0から255の値が入ります。
yは画素値でもあり,カラースケールの帯の縦方向の表示位置でもあります。
次のfor x in range(50):は,スケールの帯の幅を50にします。
最後に img[350-y, x] = y は,画像img中の350-y,xの位置に画素値yを代入します。
カラースケールの入った画像をグレー画像のまま”original.png”のファイル名で保存します。
ここで350は画像の上縁から350画素の位置からカラースケールが始まることを示します。

次にLUTを使って画像imgをRGBの各成分に分けるために,画素値がすべて0のrimg,gimg,bimgを作成します。
 rimg = np.zeros((row, col))

次に二重のfor文を使って,x,yの画素の値img[y,x]をリストr,g,bを使って各成分の値に変換して画像rimg,gimg,bimgに代入します。
 rimg[y, x] = r[int(img[y, x])]

Opencvのmergeメソッド使ってRGB成分の画像をマージしてカラー画像cimgを作成します。
 cimg = cv2.merge((rimg, gimg, bimg)) 

pyplotを使ってコンソールに表示します。
pyplotでコンソールに表示された疑似カラー画像
最後にOpneCV を使ってLUT処理後の画像を"tmp.png"として保存します。

OpneCVの処理系はカラー画像をBGRとの順で管理しているため他のPILなどと扱いが異なるため注意が必要です。
BGRのままで画像を保存する次のようになります。

BGR順の画像で正しく色が表示されていません。
全く異なる画像になってしまいます。

OpneCVで画像を保存するとき,その直前でRGBをBGRに変換して保存します。
BGR→RBG変換にはいくつかの方法があります。
ひとつはmergeするときに順番をBGRとしてカラー画像を作成する方法です。
 cimg = cv2.merge((bimg, gimg, rimg))
先のmergeとはrimgとbimgが反対になっています。

もう一つの方法はリストの技を使う方法です。
 cimg = cimg[:, :, ::-1]
既に存在するRGBG画像をBGR画像に変換するのに便利です。



imageLUT.py

import numpy as np
from matplotlib import pyplot as plt
import pydicom
import cv2

lutfnm = "ImageJインストールディレクトリ\ImageJ\luts\BRGBCMYW.lut"
#lutfnm = "ImageJインストールディレクトリ\ImageJ\luts\\16_Colors.lut"
#lutfnm = "ImageJインストールディレクトリ\ImageJ\luts\Red_Hot.lut"

f = open(lutfnm, "rb")
dt = f.read()
f.close()

print(">1>", len(dt), type(dt))

rgb     = np.array([i for i in dt]) # [r0・・・r255 g0・・・g255 b0・・・b255]
r, g, b = np.reshape(rgb,(3,256))   #  [[r0・・・r255] [g0・・・g255] [b0・・・b255]]

x = np.linspace(0,255,256)  # 0〜255を256分割する
plt.plot(x, r, color='red')
plt.plot(x, g, color='green')
plt.plot(x, b, color='blue')
plt.show()

# DICOM画像を読み込む
d = pydicom.dcmread('../dcmdir1/Brain01')

wc = d.WindowCenter     #ウィンドウセンターの取得
ww = d.WindowWidth      #ウィンドウ幅の取得
row= d.Rows             #画像の行数の取得
col= d.Columns          #画像の列数を取得
img = d.pixel_array     #画像を取得

#DICOM画像のウィンドニング
max = wc + ww / 2         #表示最大画素値
min = wc - ww / 2         #表示最小画素値
img = 255*(img-min)/(max-min)
img[img > 255] =255
img[img < 0] = 0

# カラースケールを画像に入れる
for y in range(256):            #カラースケース
    for x in range(50):         #スケールの幅
        img[350-y, x] = y       #画像中にスケールを入れる。

cv2.imwrite("original.png", img)

#LUTを使ってR,G,Bのチャンネルを作成する。
rimg = np.zeros((row, col))     #Rチャンネルの初期化
gimg = np.zeros((row, col))     #Gチャンネルの初期化
bimg = np.zeros((row, col))     #Bチャンネルの初期化
for y in range(row):
    for x in range(col):
        #LUTで画像を各チャンネルに変換
        rimg[y, x] = r[int(img[y, x])]
        gimg[y, x] = g[int(img[y, x])]
        bimg[y, x] = b[int(img[y, x])]
      
cimg = cv2.merge((rimg, gimg, bimg)) # RGB
plt.imshow(cimg)
plt.show()

#OpenCV は画像のチャンネル順を BGR として扱うためBGRの順ででマージする。
#cimg = cv2.merge((bimg, gimg, rimg)) # BGR
cimg = cimg[:, :, ::-1]               # BGR->RGB変換
cv2.imwrite("temp.png", cimg)



プログラムを実行してみる


LUTには”BRGBCMYW.lut”を用いています。
実行するとLUTのグラフとLUT処理した画像がコンソールに現れます。
カレントディレクトリにカラースケールを入れたグレー画像original.pngとLUT処理された画像temp.pngが保存されます。
LUT処理前のグレー画像
左にカラースケール(まだグレーですが)が入っています。

LUT(BRGBCMYW.lut)処理後の画像
左のカラースケールに色がついている

ImageJはたくさんのLUTを提供しています。是非いろいろ試してみてください。
3つほどカラースケールを下に示しました。
目的に応じて使い分けるとよいでしょう。



おわりに


今回はLUTの処理について,ImageJのLUTファイルを読み込むところから説明をしました。
様々な処理結果を見やすくすにはLUTを使った疑似カラー表示が適している場合が多いと思います。
LUTによる表示は実験結果の効果的な表現に便利です。



2019年9月13日金曜日

医用画像使ったPythonゼミナールを始めまーす


修正履歴:各Pyゼミのリンクを作成しました。また,一部採番が重複していたので修正しました。2019.09.13

年も明けて2019年

ブログを立ち上げてかなり放置していたので,そろそろなんかやってみようかとPCに向かっているところです。
放置している間にBloggerもだいぶ変わった。
医療情報に関連するテーマで少し持続するテーマ,”Pythonで医用画像AI”を考えてみました。

人工知能の流行もやや一段落

人工知能の流行も一時よりはだいぶ熱が冷めた感じですが,医療においてはこれからでしょう。
研究室では,これまでJavaを使ってAIを作ってきましたが,あるきっかけらPythonに移行することにしました。
それれは医療画像規格であるDICOM(Digital Imaging and COmmunication in Medicine)が非常に簡単にPythonで扱えるからでした。

本学,北海道情報大学医療情報学部ではJavaプログラミングが1年生(診療情報管理専攻)で必修科目です。
プログラミングの実習中の学生との雑談でpython勉強中です,という学生もいたりして,彼らにも画像処理結果が見れるので良いテーマでしょう。

PythonでAIやってみる?

本研究室の3,4年生のゼミナールでこれまで勉強してきた内容や作成物を整理して,1年生でもわかるようにブログの中で公開してみようかと考えたわけです。

もちろんここらでちょっと自分もAIに触れてみようと思っている人や学生などを対象に連載を組んでみたいと思っています。読んでもらいたいターゲットとしては

  • python勉強したいけど興味ある分野が見つからない人々
  • とりあえず人工知能に触れてみた大学生,高校生,ひょっとしたら小中高生
  • 修士のテーマにしたいけどどうする,という大学院生
  • 画像がいっぱいあって解析してみたい診療放射線技師や医師など医療スタッフ
  • 会社でAI推進の指示があったが何から手を付けて良いかわからない社会人
  • ネットで色々調べたけど具体的にAIとDICOMをどうくっつけるか迷える人々

環境構築編,DICOM編,GUI編とAI編をはじめます

具体的には以下の内容で進めていきたいと考えています。どこから始めても良いように並行して公開していきます。

0 環境構築編

本ゼミナールではUbuntu上で開発することを前提に進めまていますが,Windows上でのAI開発環境構築やノートPC上でのDual boot環境構築をまとめました。

Pyゼミ0.01 Pythonで医用画像のAIを試すための環境構築 
              
Pyゼミ0.02 Windows10AIしたい
              
Pyゼミ0.03 MSI ノートPCPS42 8RC-009JP)にAI環境を構築する
             
Pyゼミ0.04 MSI P65Dual bootにしてみた

Pyゼミ0.05 備忘録 Ubuntu18.04にTensorFlowとChainerをインストールする 

Pyゼミ0.06 備忘録 Ubuntu20.04にTensorFlowとPyTorchをインストールする New 20221019

Ⅰ DICOM編

医用画像は標準化が進み,DICOM(Digital Imaging and COmmunication in Medicine)が一般的に用いられています。Pydicomを使った簡単な画像の表示,ウィンドニングと呼ばれる最適画像濃度変換処理とJPEG,PNG画像変換や画像ポジションによるソート,画像拡張について紹介します。

Pyゼミ1.01 DICOM画像表示
              
Pyゼミ1.02 DICOMからJPEGなどへの変換
              
Pyゼミ1.03 DICOMのタグ情報を読む
              
Pyゼミ1.04 DICOMのタグ情報(ImagePosition)で画像ファイルをソートする
              
Pyゼミ1.05 DICOM JPEG圧縮画像を解凍する

Pyゼミ1.06 DICOM CT画像をLUTで疑似カラーを付けてみる


Pyゼミ1.07 CT画像にDICOM Color LUTを使ってヒートマップ画像などを重ねてFusion画像を作ってみる

Pyゼミ1.0 番外編 DICOM RDSRを読む 20220502

Pyゼミ1.08 PET画像を読む  20220506 


Ⅱ GUI(Graphical User Interface)編

PyQt5を使ったGUIプログラムを紹介します。
DICOM画像表示,複数DICOM画像のページングとマウスにより任意画像の抽出,DICOM画像上から任意のROIの抽出など画像加工プログラムを紹介します。

Pyゼミ2.01 PyQt5によるDICOM画像表示.画像ファイル渡し
              
Pyゼミ2.02 PyQt5によるDICOM画像表示とページング
              
Pyゼミ2.03 PyQt5によるDICOM画像のセグメンテーション
              
Pyゼミ2.04 PyQt5によるDICOM画像の拡大表示と保存

Pyゼミ2.05 PyQt5によるラジオボタンとチェックボックス new2020.02.16

             

Ⅲ 人工知能編

人工知能のフレームワークであるChainerを使います。
手書き数字認識MNISTのデータから医用画像データへの拡張方法,pythonを使ったChainerの訓練プログラムをGPU対応にする方法などを紹介します。

Pyゼミ3.01 手書き認識のニューラルネットワーク
              
Pyゼミ3.02 手書き画像からDICOM画像へ
              
Pyゼミ3.03 DICOM画像を訓練用とテスト用に分けてみる
              
Pyゼミ3.04 手書き文字認識のニューラルネットワークをDICOMに拡張する
              
Pyゼミ3.05 MNISTのネットワークをAlexnetに対応させる
              
Pyゼミ3.06 ChainerTrainer Extensionを使ってみる
              
Pyゼミ3.07 ChainerGPUを使って学習してみる



プログラムの方針

プログラムのサンプルを探すのであればGitHubに大量のソースコードが保存されています。しかし,初心者がチャレンジしてするには敷居が高いように思います。
そこでPyゼミでは次の点に留意してプログラムを作成しています。

  • 100行程度の長さで,アルゴリズムを容易に理解できる
  • ひとつのプログラム内でアルゴリズムが完結している
  • 実行した結果が複雑ではなく容易に理解が得られる


おわりに

本研究室のゼミナールだけでなく,外部の他の勉強会やセミナーにも参加してみて,周囲の人たちがいろいろな問題をもっていることが分かってきました。
おおよそ図書などで人工知能が使えるようになっても,最初にデータをどのように加工してAIに与えるべきなのか,つまりMNISTのデータで上手くいくのは分かったけどその次どうしたらいいの...という問題にすこしでも参考になればと考えています。

ちょっとお願い

なお本ソースコードの使用にあたって,何らかの具都合や不利益が生じたとしても本研究室で責任を負いかねます.どうぞご了承ください。
本ゼミナールで配布するDICOM画像は私のCT全身像です。実験以外の利用はしないようお願いいたします。
また,ご意見などありましたらメッセージをいただけますでしょうか。