コンテンツにスキップするには Enter キーを押してください

chainer メモ(その4)機械学習で顔認識!実際に画像をつっこむ(OpenCV3使用)

 

はじめに

前回のブログで乃木坂メンバーの顔を学習するところまでやったので、
実際に適当な画像を突っ込んで、顔認識からの誰が写っているかを試してみましょう。




 

コード

コードの全文はgithub
下のコードは実際に画像を指定してpredictする。


from image2TrainAndTest import image2TrainAndTest
from image2TrainAndTest import getValueDataFromPath
from image2TrainAndTest import getValueDataFromImg
from faceDetection import faceDetectionFromPath
import alexLike

def main():
    parse = argparse.ArgumentParser(description='face detection')
    parse.add_argument('--batchsize', '-b', type=int, default=100)
    parse.add_argument('--gpu', '-g', type=int, default=-1)
    parse.add_argument('--model','-m', default='')
    parse.add_argument('--size', '-s', type=int, default=128)
    parse.add_argument('--channel', '-c', default=3)
    parse.add_argument('--testpath', '-p', default="./images/test/output/inputImage_0.png")
    args = parse.parse_args()

    if args.model == '': #学習したモデルを使って予測するので必要
        sys.stderr.write("Tom's Error occurred! ")
        sys.stderr.write("You have to designate the path to model")
        return

  # この2行は、出力層の数をモデルの名前から取ってきているだけです。
  # 完全自己流なので適当に。筆者はmy_output_5.modelという感じで、出力層の数をここで分かるようにしてます。
    outNumStr = args.model.split(".")[0].split("_")
    outnum = int(outNumStr[ len(outNumStr)-1 ])
  
    # モデルを読み込む
    model = L.Classifier(alexLike.AlexLike(outnum))
    chainer.serializers.load_npz(args.model, model)

    # faceDetectionFromPathでは指定した画像に写っている顔を指定したサイズにしてリストで返してくれる
    faceImgs = faceDetectionFromPath(args.testpath, args.size)
    for faceImg in faceImgs: # 写っていた顔ごとに判別する
	# getValueDataFromImgではpillowの画像を渡すとCNN用のデータにして返してくれる。
        valData = getValueDataFromImg(faceImg)
        pred = alexLike.predict(model, valData)
        print(pred)

if __name__ == '__main__':
    main()

 

以下は、モデルファイルに書いたpredictの部分

...
def predict(model, valData):
    x = Variable(valData)
    y = F.softmax(model.predictor(x.data[0]))
    return y.data[0]

ここでは、一人の顔だけを入れて判定するようにしています。
以下のようにすることでまとめて予測することもできます。
この場合は、getValueDataFromImgで得られた、画像を一旦valDatasにまとめておいて、予測するという流れになると思います。
以下のこのコードは実際にgithubには載っていません。

def predict(model, valDatas):
    x = np.asarray(valDatas)
    y = F.softmax(model.predictor(x))
    return y.data

 

Opencv3を使ったfaceDetectionFromPathのコード

def faceDetectionFromPath(path, size):
    cvImg = cv2.imread(path)
    #顔の位置を判定するためのファイルを指定
    cascade_path = "./lib/haarcascade_frontalface_alt.xml"
    cascade = cv2.CascadeClassifier(cascade_path)
    facerect = cascade.detectMultiScale(cvImg, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
    faceData = []
    for rect in facerect:
        faceImg = cvImg[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
        resized = cv2.resize(faceImg,None, fx=float(size/faceImg.shape[0]),fy=float( size/faceImg.shape[1]))
        # opencvからpillowに移すときはこうするらしい
        CV_im_RGB = resized[:, :, ::-1].copy() 
        pilImg=Image.fromarray(CV_im_RGB)
        faceData.append(pilImg)
        
    return faceData

 

次にgetValueDataFromImgのコード

def getValueDataFromImg(img):
    img.show()
    r,g,b = img.split()
    rImgData = np.asarray(np.float32(r)/255.0)
    gImgData = np.asarray(np.float32(g)/255.0)
    bImgData = np.asarray(np.float32(b)/255.0)
    imgData = np.asarray([[[rImgData, gImgData, bImgData]]])
    return imgData

これは前回書いたブログに詳しく書いてある。

 

実際に動かす

今回はこの画像を判別しましょう。
なぁちゃんねこです。
nala

これを指定してあげる。今回はデスクトップにおいたので~/Desktop/nala.pngとしてます。

> $ python facePrediction.py -m my_output_5.model -p ~/Desktop/nala.png     [±master ●●]
[  1.61287112e-15   7.70309465e-15   9.25570731e-12   1.00000000e+00
   1.31814785e-12]

数値がいろいろ出てきましたが、前から[他人 まなったん まいやん なぁちゃん いくちゃん]の確率なので、正しくなぁちゃんだと判別できています。
※ ◯e+△というのは◯x(10の△乗)という意味。
9.25e-12というのは 9.25 x (1/10)^12 = 0.00000000000925 になります。

 

ただしまだ学習が甘く…

完璧にはまだまだなっていません。
男の人や、海外の人などにすればちゃんと最初の他人のところの確率が上がるのですが、同じ乃木坂のメンバーを入れるとまだ誤認識してしまいます。

例えば、この画像
three
画像の左から、白石麻衣、橋本奈々未、桜井玲香ですが実行すると

> $ python facePrediction.py -m my_output_5.model -p ~/Desktop/three.png    [±master ●●]
[  5.09224244e-16   2.70446762e-25   9.99930263e-01   6.97188225e-05
   1.54185052e-28]
[  2.12674824e-20   1.00000000e+00   2.41085564e-23   4.09269507e-09
   4.33422050e-14]
[  2.52632541e-04   5.95084249e-09   1.38581757e-12   4.83696738e-07
   9.99746859e-01]
[ 1.  0.  0.  0.  0.]
[  1.00000000e+00   0.00000000e+00   1.45096048e-40   3.56861976e-37
   1.60146540e-33]

上から、白石麻衣、橋本奈々未、桜井玲香、服(顔の誤認識)、服(顔の誤認識)の顔に対しての結果です。
それぞれの顔に対して左から、[その他 秋元真夏 白石麻衣 西野七瀬 生田絵梨花]である確率になります。

白石麻衣は正しく認識されています。
ただ、橋本奈々未は秋元真夏、桜井玲香は生田絵梨花と判定されてしまいました。
この2人はまだ学習させていないので、他人と判定してほしかったのですが、、、
下2つの服の誤認識されたものは、しっかりとその他として判定されています。

他人として学習させた中に同じような年代の日本人女性をあまり入れてなかったので、間違えたのだと思います。
対処法としては、AKBなどの48グループのメンバーを他人として登録して、他の乃木坂メンバーもちゃんとその人として学習させることだと思います。(め、めんどくさい…)
あとはシンプルにモデルが良くない。
学習の方のブログでも書きましたが、モデル自体はalexnetほぼほぼそのままなので顔認識のためのモデルではありません。
いろいろな論文読んで試してみようかなとは思っています。実行に移せればよいのですが…

とりあえず、頑張ってみようかな…

あ、そもそもこれを作った理由としてはブログなどにアップされた画像で推しが居たら自動的に保存できたらなーという感じなので、そこまでできたらいいなーとは思っています。(やる気が続いたら)




2 Comments

  1. はむ
    はむ 2018年1月25日

    画像の左から、白石麻衣、桜井玲香、橋本奈々未ですが実行すると
    と書いてますが、桜井玲香、橋本奈々未は逆じゃないですか?

    • toxweblog
      toxweblog 2018年1月25日

      本当ですね。間違えていました。
      ご指摘ありがとうございます。
      修正致しました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です