Raspberry piの電子工作やPythonとかjavascriptとかかじってます

TensorFlowで高専生の学科判別機作ってみた

動機

高専生活5年間のなかで「お前J科ぽい顔してるな」と何度言われたかわからない。 自分でも説明はできないけど確かにその学科っぽい顔ってあるよなと感じたので 手元には卒業アルバムとパソコンで学科判別機を作っていく。

使ったもの

PC: MacBook Air (2017) - 0S: HighSierra 10.13.6

  • メモリ: 8GB 卒業アルバム、その他顔の映った画像データ

手順

1. 画像収集とデータ整理

学習させるための画像を集めます。物は試しで、とりあえず1学年40人程度の写真を使っています。手っ取り早く手に入れるため卒アルの集合写真を使います。

データが少ないときは歪みや反転を使ってデータの水増しをすることが多いようですが、めんどくさかったので卒アルをいくつかの角度から写真をとって水増ししました。

opencvを使って顔認識で認識できた顔写真のみをデータとします。 1人当たり2~3回写真に映るくらいの写真を撮って、顔認識させたところ、学科ごとに顔写真80枚程度とネクタイなどを誤認識した画像40枚程度が集まりました。 これらの画像を学科ごとの顔写真フォルダ5つと誤認識した画像を集めたフォルダ1つの6個のフォルダに、整理していきます。

一つの画像から複数の顔データを取得し、64px*64pxにリサイズして出力するのに使ったプログラムがこちらになります。

# -*- coding: utf-8 -*-
import cv2

#HAAR分類器の顔検出用の特徴量
cascade_path = "/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml"
image_path = "narisawa.jpg"

#ファイル読み込み
image = cv2.imread(image_path)
#グレースケール変換
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#カスケード分類器の特徴量を取得する
cascade = cv2.CascadeClassifier(cascade_path)

#物体認識(顔認識)の実行
#image – CV_8U 型の行列.ここに格納されている画像中から物体が検出されます
#objects – 矩形を要素とするベクトル.それぞれの矩形は,検出した物体を含みます
#scaleFactor – 各画像スケールにおける縮小量を表します
#minNeighbors – 物体候補となる矩形は,最低でもこの数だけの近傍矩形を含む必要があります
#flags – このパラメータは,新しいカスケードでは利用されません.古いカスケードに対しては,cvHaarDetectObjects 関数の場合と同じ意味を持ちます
#minSize – 物体が取り得る最小サイズ.これよりも小さい物体は無視されます
facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
#facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=3, minSize=(10, 10), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)

print "face rectangle"
print facerect
i=0
if len(facerect) > 0:
    #検出した顔をリザイズして保存していく
    for rect in facerect:
        image2 = image[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
        if image.shape[0]<64:#小さすぎる顔データは捨てる
            continue
        image2 = cv2.resize(image2,(64,64))
        cv2.imwrite(image_path+str(i)+".jpg", image2)
        i+=1

あまり元画像の数が多くなかったので、 このプログラムと顔のデータを取得したい画像を同じフォルダに入れてimage_pathを変更しながら実行して行きます 画像の名前はダブらなければ後の作業に関係なかったです

1学科ごとに画像をフォルダにまとめ、このフォルダから手作業で顔と顔以外に分類したら顔以外の画像はは5学科共通の誤認識フォルダのなかに移していけばおしまいです。

学習データとして使うために分類したフォルダをさらに一つのフォルダに入れておきましょう。次のようなディレクトリー構造になってました。

face --- mFace --- face1.jpg
      |         |-  〜〜〜〜〜
      |         -- 顔写真
      |- eFace --- 顔写真80枚くらい
      |- dFace --- 顔写真80枚くらい
      |- jFace --- 顔写真80枚くらい    
      |- cFace --- 顔写真80枚くらい
      -- other --- 誤認識した画像たくさん

最後に自分の顔写真でどの学科か判断させるために所属学科から自分の顔写真は取り除いておきます。

2. TensorFlowのインストール、再学習

今回やりたいことはTensorflowのImage Retrainingというチュートリアルを参考にしていけばいい。

インストールするものについては、基本がわかっていなかったのと古い情報に惑わされたりしましたが、 どうやらTensorFlowのインストールとTensorFlow Hub のインストールをしなければいけないようだ。

インストールにもチュートリアルが用意されているので、TensorFlowTnesorFlow Hubチュートリアルに従ってインストールしていく。

この後はImage Retrainingチュートリアル

curl -LO https://github.com/tensorflow/hub/raw/r0.1/examples/image_retraining/retrain.py

までやっておきましょう。

次の再学習のコマンドではお花の判別機を作ってしまうので、先ほどの学習データをまとめたフォルダを retrain.pyと同じディレクトリにコピーし、image_dirに学習データの大元のディレクトリ名にして実行

python retrain.py \
  --bottleneck_dir=bottlenecks \
  --how_many_training_steps=100 \
  --model_dir=inception \
  --summaries_dir=training_summaries/basic \
  --output_graph=retrained_graph.pb \
  --output_labels=retrained_labels.txt \
  --image_dir=学習させたいフォルダ名(今回はface)

として実行(10分くらい待ちましょう) これで再学習は終わりです

3. 実行

実行の手順もの上のチュートリアルの通りに行えばできる graphとlabelはチュートリアルと名前を変えてしまったので注意してください

curl -LO https://github.com/tensorflow/tensorflow/raw/master/tensorflow/examples/label_image/label_image.py
python label_image.py \
--graph=retrained_graph.pb --labels=retrained_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=調べたい顔写真

4. 結果

一応自分の顔がどの学科に見えるかについて調べてみました。本来はもっとくっきりしたデータで判別してますが、顔にはぼかしを入れています。

f:id:naritaku:20180919040150p:plain
結果

画像の名前を第一候補となった学科とその確率にしてあります。 人間相手でも8割はJ科と間違えられるので大健闘です。

5. 今後の展望

人間と同じような感じで答えてくれた?ので満足です。

顔だけでもこの結果だったので体格、行動、その他諸々を踏まえると人間が間違えるのも致し方ないのかもしれません。 こんなことして遊んでるからJ科に間違えられるのでしょう。

せっかく動くようにしたので文化祭とかで使えたら面白いかなと考えています。 どこかで日の目を目せて上げたいです。あとは精度を上げるために画像データも募集してます。