自分のための備忘録的なブログです。

Ubuntu14.04LTS を使って、ディープラーニングの勉強をしています。
記載されているコードは、他の OS には互換性がない可能性があります。


DNN:
マシン性能別 学習速度の比較, TFチュートリアルをmodifyする
python3:
オブジェクト指向プログラミングとは, システムコマンド(os), ファイル・フォルダ名取得, 画像の前処理,
R lang:
R基本コマンド, Rデータ形式, RStudio文字化け(os), RStudio背景黒,
Ubuntu14 の初期設定:
Ubuntu14初期設定, 初期設定-2, cudaなども, 初期設定-3

Python + NiBabel で nii ファイルを扱う

NiBabel は、神経画像のフォーマットである Analyze, NifTi などを扱うことができる Python ライブラリ。

Neuroimaging in Python — NiBabel 2.2.1 documentation

このページに書いてあるのは上記リンク先の超訳(抄訳+個人の感想)なので、詳しくはリンク先を読んでいただきたし。

  NifTi とはなんぞや -> こちら参照。nifti ファイルを python で。

 

NiBabel は Analyze, GifTi, NifTi, NINC1, MINC2, MGH, PAR/REC など多彩なファイル形式を扱うことができるということ。このライブラリ自体は PyNifTi の後継とのことなので、もとが「NifTi を Python で扱いたい」というところから来ているものと思われる(個人の妄想です)。

 

NiBabel は各種データの I/O (in-out)に使用し、解析には numpy, scikit-learn, tensorflow など別のライブラリを用いる。Jupyter Notebook で R に投げたりもできるだろう(やったことないけど)。

 

 

事前準備

 インストール

$ pip install nibabel

 

インポート

>>> import numpy as np

>>> import nibabel as nib

 

(画像を読み込むと numpy array 形式となるので、numpy もインポートしておく)

Python 3.6 でエラーが出たので、現状 3.5 以前で使うのがベター。当然 pyenv や conda仮想環境を使うべき)

 

データ形式と "RAS+"

2つのデータ形式

NifTi には NifTi-1 と NifTi-2 の 2つのデータ形式がある(が拡張子は一緒!!ややこしい!!)。

 

詳しくないかざっくりと解説

nifti ファイルを python で。 - 医用画像で Deep Learning

RAS+ と 4つの次元 

NifTi 形式には 4つの次元がある: xyzt

 空間方向の 3軸(xyz)と、時間方向(t)の 1軸

空間座標は基本的に RAS+ だが、それ以外の形式で保存されていることもあり注意が必要。RAS+とは、第1軸(x軸)は 左から右(right)へ、第2軸(y軸)は後ろから前(anterior)へ、第3軸は下から上(superior)へ、という形でデータが並んでいるということ。

 RAS+ が被験者の上側から眺めたような配置。医者が CT や MRI を見るときの配置は、LAS に相当。

 

コードを触ってみる

参考:

NiBabel 2.2.1 General tutorials

NiBabel 2.2.1 getting started

 

画像の読み込み

img_file = nib.load('ファイル名')

img = img_file.get_data()

 nib.load() で読み込んでも、画像データは自体はキャッシュ/メモリーに取り込まれない。メモリー節約のために、「画像がここにありますよ」という位置情報だけを読み込んでいると思われ。

 get_data() メソッドで画像データを読み込む(原文では cache に保存する、と書かれているが、実際は RAM なのかな)。この読み込んだ画像データを、nibabel では  proxy と言うらしい: Neuroimaging in Python — NiBabel 2.2.1 documentation

proxy: 代理、代理人、代用品

 ここで >>> type(img) に対して <... 'numpy.ndarray'> と返るらしく、np.array 形式で読み込まれる。

 

画像のオリエンテーションを確認する

nib.aff2axcodes(img.affine)

 ここで ('R', 'A', 'S') と返るならば RAS+ 形式。

 

画像を読み込んだかどうかを確認する

img.in_memory

 画像データが読み込まれている(chache に読み込まれている, proxy)なら True が返る。

 

画像データを消去する

img.uncache()

 

ヘッダーの取得と表示

hdr = img.header

print(hdr)

hdr.get_xyzt_units()

 ヘッダーの get_xyzt_units() メソッドで、単位を取得できる。返り値はタプルで、('mm', 'sec') など。

 

データ形式の確認

img.get_data_dtype() == np.dtype(np.int16)

 返り値は True または False。確認方法めんどくさいな・・・

 チュートリアル(getting started)の nii ファイルは np.int16 で保存されていた。int16 だと -32,768 から 32,767 の範囲とのこと、CT も MRI もこの形式で大丈夫(カバーできる)だろう。

 これよりデータ量を減らそうとすると、uint8 でも 0-255 までしか保存できない。uint8 で保存すると画質が劣化するはず、jpg とか png とか、基本 uint8 のはずですが。

 

数値の取得

x_len, y_len, z_len = img.shape

x = x_len//2

y = y_len//2

z = z_len//2

value = img[x, y, z]

print(value)

 画像データを読み込んだ後は、python 標準ライブラリでスライスして、数値データを表示したり、計算したり、代入したり、好きに扱うことができる。

 ここまで来ればあとはご自由に、と言った感じ。

 

画像の表示

import matplotlib.pyplot as plt

 

slice0 = img[x, :, :]

slice1 = img[:, y, :]

slice2 = img[:, :, z]

 

def show_slices(slices):

    fig, axes = plt.subplots(1, len(slices))

    for i, slice in enumerate(slices):

        axes[i].imshow(slice.T, cmap="gray", origin="lower")

 

show_slices([slice0, slice1, slice2])

 画像は四次元データなのだけど、もし時間方向にデータがひとつしかない場合、numpy の機能で三次元になっているはず。上記は、その三次元で読み込まれた場合のスクリプト

 もし四次元で読み込まれた場合には

>>> img = img[:, :, :, 0]

 の様に、三次元データにスライスしてから上記コードを実行すればいい、はず。

 

アフィン変換

tutorial には、アフィン変換について延々と書いてある。

Neuroimaging in Python — NiBabel 2.2.1 docum entation

画像を拡大・回転・平行移動(アフィン変換)することでボクセルの位置を変更することが可能、異なる画像の座標を変更して、位置合わせができるということ。

この部分、数学的に大変なので扱わず・・・

 

それぞれの NifTi ファイルには撮影スライスの位置や傾き、拡大率を表す「アフィン」"affine" の値が設定されている様子。

>>> img.affine

で確認でき、画像データと affine とで計算することで位置情報を修正できるらしい。が、工学部卒ならともかく、私の理解は超える。。。

 

画像データの変更

print(img[0, 0, 0, 0])

img[0, 0, 0, 0] = -99

print(img[0, 0, 0, 0]

 

画像の保存

nib.save(img, 'new_file.nii')

# もしくは メソッドとして

img.to_filename('new_file.nii')

 

 以上!