python 魚が映っている時と映っていない時の画像で機械学習にかけて学習モデルの作成

import cv2
import os, glob, pickle
from sklearn.model_selection import train_test_split
from sklearn import datasets, metrics
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 画像の学習サイズやパスを指定
image_size = (64, 32)
path = os.path.dirname(os.path.abspath(__file__))
path_fish = path + '/fish'
path_nofish = path + '/nofish'
x = # 画像データ
y = # ラベルデータ

# 画像データを読み込んで配列に追加 --- (*1)
def read_dir(path, label):
 files = glob.glob(path + "/*.jpg")
  for f in files:
   img = cv2.imread(f)
   img = cv2.resize(img, image_size)
   img_data = img.reshape(-1, ) # 一次元に展開
   x.append(img_data)
   y.append(label)

# 画像データを読み込む
read_dir(path_nofish, 0)
read_dir(path_fish, 1)

# データを学習用とテスト用に分割する --- (*2)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

# データを学習 --- (*3)
clf = RandomForestClassifier()
clf.fit(x_train, y_train)

# 精度の確認 --- (*4)
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

# データを保存 --- (*5)
with open("fish.pkl", "wb") as fp:
pickle.dump(clf, fp)

 

前提としてある動画から魚が映っている画像と映っていない画像を150枚ずつにわけてfishフォルダ、nofishフォルダを作成してある。

 

モジュールインポート

import cv2
import os, glob, pickle
from sklearn.model_selection import train_test_split
from sklearn import datasets, metrics
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

 

globモジュールでは、引数に指定されたパターンにマッチするファイルパス名を取得することが出来る。特定のディレクトリに存在するファイルに処理を加えたい場合などに、使用する。

pickleモジュールでは学習済みデータを保存するためにインポートする。

 

train_test_splitはデータを学習用、テスト用に分けるためにインポート。

学習モデルを構築するためのアルゴリズムとしてRandomForestClassifierをインポート。高い精度を出すアルゴリズムの一つ。

 

accuracy_scoreは予測結果とテスト結果を比較し精度を確認することができる。

 

画像の学習サイズやパスを指定

image_size = (64, 32)
path = os.path.dirname(os.path.abspath(__file__))
path_fish = path + '/fish'
path_nofish = path + '/nofish'
x = # 画像データ
y = # ラベルデータ

機械学習では学習するデータは同じサイズである必要があるため全て64✖️32のサイズに指定する。64✖️32なのは横長の画像が多かったから。

 

os.path.dirnameは, 引数で渡したパス名からディレクトリ名の部分だけ抜き出す関数。

>>> os.path.dirname("/User/Program/test.py")
'/User/Program'

>>> os.path.dirname("/User/Program")
'/User'

os.path.abspathは引数で与えたパス名の絶対パスを取得する関数

>>> os.path.abspath("test.py")
'/User/Program/test.py'
>>> os.path.abspath("/User/Program/test.py")
'/User/Program/test.py'

path = os.path.dirname(os.path.abspath(__file__))この記述では実行中のスクリプトディレクトリの絶対パスを取得することができる。

print('abspath:     ', os.path.abspath(__file__))
print('abs dirname: ', os.path.dirname(os.path.abspath(__file__)))

実行結果

# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

 

画像データを読み込んで配列に追加

def read_dir(path, label):
 files = glob.glob(path + "/*.jpg")
  for f in files:
   img = cv2.imread(f)
   img = cv2.resize(img, image_size)
   img_data = img.reshape(-1, ) # 一次元に展開
   x.append(img_data)
   y.append(label)

# 画像データを読み込む
read_dir(path_nofish, 0)
read_dir(path_fish, 1)

path_nofishにはnofish(魚が映っていないファイル)のパスが格納されている。

path_fishは魚が映っているファイルのパス。

 

glob.glob()でnofish、fishディレクトリの.jpgと一致するファイルパスを全て取得している。

cv2.imread()で画像の読み込み。

reshape()で画像データを一次元の配列に変換、(-1,)第一引数に-1を指定することで1行の配列にすることができる。

 

append()でx,yにそれぞれの配列を追加。

xに画像データ、yに画像データに対応したラベル番号。

 

テスト用、学習用にデータを分ける

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

 

データの学習

clf = RandomForestClassifier()
clf.fit(x_train, y_train)

変数にオブジェクト格納。

fit()で学習。

 

精度の確認

y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

 

predict()で予測。

accuracy_score()で予測結果とテストデータを比較。

 

データの保存

with open("fish.pkl", "wb") as fp:
pickle.dump(clf, fp)

 

with openに"wb"を指定して書き込み用でファイルを開く。

pickle.dump()で学習済みデータを保存。第一引数に保存したいオブジェクト、第二引数に保存先のファイル。