【超初心者向け】Python×機械学習で画像認識の実装をしてみよう(医療画像)
本記事では、画像認識についてPythonの実装をしながら分かりやすく解説していきます。
画像認識の領域は、ディープラーニングの発展とともに、今でも様々な研究が盛んです。
医療分野でも、画像認識タスクは数多くの研究が行われています。
そんな画像認識について医療画像を使って、Pythonでの実装を一緒にやっていきましょう。
画像認識の基礎を理解しよう
まずは、画像認識の基礎について理解していきましょう。
画像認識でよく使われるライブラリに「OpenCV」というものがあります。
正式名称は「Open Source Computer Vision Library」と言い、画像認識で最もよく使われるライブラリです。
データセットの準備
まずは、データセットの準備をしていきましょう!
今回使用するデータセットは、下記サイトから取ってきたものになります。
http://imgcom.jsrt.or.jp/minijsrtdb/
日本放射線技術学会 胸部X線画像の性別の2クラス分類データセット Gender01
こちらのデータセットは、胸部正面像が性別ごとに分けられており、どの性別かを予測する事に使用します。
▼ データセットはこちらの下記リンクからダウンロードしてください。
Google colaboratoryを前提に実装していきますが、ローカルのJupyter等の環境でも問題ありません。
ダウンロードが出来たらGoogleDriveにzipファイルのままアップロードしておいてください。
OpenCVで画像を読み込んでみよう
実際に「OpenCV」を使って簡単に画像を表示させたり加工したりしていきましょう!
まずは自分のGoogleDriveにアップロードしたデータを使用するために、GoogleDriveと連携させる(Googleドライブのマウント)事を行います。
下記コードを実行する事で、Googleドライブのマウントは完了です。
# Googleドライブのマウント
from google.colab import drive
drive.mount('/content/drive')
もしも、マウント時にログが表示されて困ったときは、こちらの記事を参考にしてみて下さい。
続いて、先程アップロードしたzipファイルの解凍を行います。
解凍してからアップロードしてもいいですが、データ量が多い場合には時間がかかるので、zipファイルでアップロードして、コードで解凍する方がおすすめです。
from zipfile import ZipFile
# Zipファイルの解凍
file_name = '/content/drive/My Drive/Gender01.zip'
with ZipFile(file_name, 'r') as zip:
zip.extractall()
次に、必要なライブラリをインポートしておきます。
#ライブラリのインポート
import matplotlib.pyplot as plt
import glob
import cv2
globは特定のファイルパスを抽出してくるのによく使います。
files = glob.glob("/content/Gender01/train/male/*.png")
このようにglobを使ってあげることで特定のディレクトリ配下にあるpngファイルのパスを全て抽出してくることができます。
*.pngの拡張子を変えることで、自分のdatasetに合わせて抽出することが出来ます。
files = sorted(files)
print(files)
抽出したファイルパスを表示してみると、ちゃんとパスがリスト形式で格納されていることが分かります。
続いては、ファイルのパスから画像を読み込む作業を行いたいと思います。
ここで、最初に説明したOpenCVの登場です。
image = cv2.imread(files[0])
ファイルパスの中で最初のパス(0番目)の画像情報をOpenCVを使って抽出します。
そうすると以下のように配列形式で画像の情報が得られます。
画像を表示させてみよう
実際に先程読み込んだ画像を表示させてみましょう。
plt.imshow(image)
以下のように表示されたと思います。
ここで、画像情報がどんな形になっているか見てみましょう!
image.shape
これは256×256のピクセルの面がRGB(赤緑青)の3次元で重なっていることを表します。
画像を加工してみよう
ここでは、先程表示した画像をOpenCVを使って加工してみましょう。
通常、画像はRGBの順番で重ね合わされるのですが、OpenCVで読み込んだ場合はBGRの順番で格納されています。
そのため、実際の画像と色合いが変わってしまうのです。(大幅には変わらないが…順番がRGBではない!)
そこで、Matplotlibで画像を表示する前にBGRからRGBの順番に変換してあげる必要があります。
image = cv2.imread(files[0])
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image_gray)
このように変換してあげると・・・
今回は医療画像なので見た目には分かりませんが、カラー画像では大幅に変わるので覚えておいてください!
続いて画像のトリミングをしてみたいと思います。
以下のように画像の要素を一部抽出してあげるだけで画像の一部分だけをトリミングして表示することができます。
mage_gray2 = image_gray[50 : 200, 40: 160]
plt.imshow(mage_gray2)
より詳しく画像処理について学びたい方はこちらの記事を参考にしてみてください。
Pythonで画像認識を実装してみよう
ここからは、先ほどと同じところから出ているdatasetの胸部X線画像の方向分類をやってみたいと思います。
▼ コード一覧はこちら
# ライブラリのインポート
import numpy as np
import tensorflow.keras as keras
from keras.utils import np_utils
from keras.models import Sequential, Model, model_from_json
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.callbacks import ModelCheckpoint
import matplotlib.pyplot as plt
from PIL import Image
import glob
import json
from zipfile import ZipFile
%matplotlib inline
# データセットを変数に格納
# フォルダ名(分類クラス)のリスト
folder = ["down", "right", "left", "up"]
image_size = 32 #入力画像のサイズを32×32とする
#学習用データ、学習用ラベル、検証用データ、検証用ラベルをそれぞれ格納するための空の配列を作成
X_train = []
y_train = []
X_val = []
y_val = []
# 学習用(train)データに対して行う処理
for index, name in enumerate(folder):
dir = "/content/Directions/train/" + name #対象のフォルダ名
files = glob.glob(dir + "/*.png") #pngファイルのリストを取得
for i, file in enumerate(files):
image = Image.open(file) # 画像ファイルの読み込み
image = image.convert("RGB") # RGBモードに変換
image = image.resize((image_size, image_size)) # リサイズ
data = np.asarray(image) # 画像を配列に変換
X_train.append(data) # 配列をX_trainに追加
y_train.append(index) # ラベルをy_trainに追加
# 検証用(validation)データに対しても同じ作業を行う
for index, name in enumerate(folder):
dir = "/content/Directions/validation/" + name
files = glob.glob(dir + "/*.png")
for i, file in enumerate(files):
image = Image.open(file)
image = image.convert("RGB")
image = image.resize((image_size, image_size))
data = np.asarray(image)
X_val.append(data)
y_val.append(index)
# numpy配列に変換
X_train = np.array(X_train)
y_train = np.array(y_train)
X_val = np.array(X_val)
y_val = np.array(y_val)
# 正規化
X_train = X_train.astype('float32')
X_train = X_train / 255.0
X_val = X_val.astype('float32')
X_val = X_val / 255.0
# 正解ラベルの形式を変換
y_train = np_utils.to_categorical(y_train, 4)
y_val = np_utils.to_categorical(y_val, 4)
# モデルの定義
def model(X, y):
model = Sequential()
model.add(Flatten())
model.add(Dense(64, activation='relu', input_shape=(256,)))
model.add(Dropout(0.2))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(4, activation='softmax'))
opt = keras.optimizers.SGD(lr=0.001, decay=1e-6)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
return model
# 学習過程を可視化
def plot_history(history):
plt.plot(history.history['accuracy'],"o-",label="accuracy")
plt.plot(history.history['val_accuracy'],"o-",label="val_acc")
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(loc="lower right")
plt.show()
plt.plot(history.history['loss'],"o-",label="loss",)
plt.plot(history.history['val_loss'],"o-",label="val_loss")
plt.title('model loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(loc='lower right')
plt.show()
# 最良のモデルを保存するための関数
modelCheckpoint = ModelCheckpoint(filepath = 'direction_4.hdf5',
monitor='val_loss', # 監視する値
verbose=1, # 結果表示の有無
save_best_only=True,
save_weights_only=True,
mode='min',
)
# 学習の実行
model = model(X_train, y_train)
history = model.fit(X_train, y_train,
epochs=50,
batch_size=32,
validation_data=(X_val, y_val),
callbacks=[modelCheckpoint])
json_string = model.to_json()
open('direction_4.json', 'w').write(json_string)
plot_history(history)
# テストの準備
# モデルを読み込む
with open('/content/direction_4.json', 'r') as model_json_file:
model_json = json.load(model_json_file)
model = model_from_json(json.dumps(model_json))
model.load_weights('/content/direction_4.hdf5')
X_test = []
y_test = []
for index, name in enumerate(folder):
dir = "/content/Directions/test/" + name
files = glob.glob(dir + "/*.png")
for i, file in enumerate(files):
image = Image.open(file)
image = image.convert("RGB")
image = image.resize((image_size, image_size))
data = np.asarray(image)
X_test.append(data)
y_test.append(index)
X_test = np.array(X_test)
y_test = np.array(y_test)
X_test = X_test.astype('float32')
X_test = X_test / 255.0
y_test = np_utils.to_categorical(y_test, 4)
詳しいコードの解説やデータについてはこちらの記事で解説しています。
まとめ
今回の記事では、画像認識をPythonで実装しながら簡単に解説しました。
今回紹介したのは、まだまだ極一部です。
ぜひご自身で色々調べてみて画像認識の実装をやってみてくださいね!
コメント