芸能人の顔を機械学習で分類してみた（その５）

###引数で与えた画像の分類
[芸能人の顔を機械学習で分類してみた（その３）](https://qiita.com/yuni/items/7cfd540104f54263f6b5)で、うまくいかなかった画像分類にもういちどトライ。

何をやったかというと、下記データを使って学習させ、正解率98%の精度にできたモデルを使って、引数に画像を与えて結果を0/1に返すってやつをやっていました。

<使ったデータ>
trainデータ：石原さとみ(100枚), 西島秀俊(100枚)
testデータ ：石原さとみ(30枚), 西島秀俊(30枚)

<ラベル>
0：西島秀俊
1：石原さとみ

今回は、画像を与えると、顔部分だけを切り出して、その計算結果を返すように修正しました。

```FaceType1.py
#!/usr/bin/env python
#! -*- coding: utf-8 -*-

import sys
import numpy as np
import tensorflow as tf
import cv2
import os


NUM_CLASSES = 2
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3
#カスケード分類器ロード
cascade_path = "/Users/yuni/anaconda/lib/python3.6/site-packages/cv2/data/haarcascade_frontalface_alt.xml"


def inference(images_placeholder, keep_prob):
    """ モデルを作成する関数

    引数: 
      images_placeholder: inputs()で作成した画像のplaceholder
      keep_prob: dropout率のplace_holder

    返り値:
      cross_entropy: モデルの計算結果
    """
    def weight_variable(shape):
      initial = tf.truncated_normal(shape, stddev=0.1)
      return tf.Variable(initial)

    def bias_variable(shape):
      initial = tf.constant(0.1, shape=shape)
      return tf.Variable(initial)

    def conv2d(x, W):
      return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def max_pool_2x2(x):
      return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                            strides=[1, 2, 2, 1], padding='SAME')
    
    x_image = tf.reshape(images_placeholder, [-1, 28, 28, 3])

    with tf.name_scope('conv1') as scope:
        W_conv1 = weight_variable([5, 5, 3, 32])
        b_conv1 = bias_variable([32])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    with tf.name_scope('pool1') as scope:
        h_pool1 = max_pool_2x2(h_conv1)
    
    with tf.name_scope('conv2') as scope:
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

    with tf.name_scope('pool2') as scope:
        h_pool2 = max_pool_2x2(h_conv2)

    with tf.name_scope('fc1') as scope:
        W_fc1 = weight_variable([7*7*64, 1024])
        b_fc1 = bias_variable([1024])
        h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    with tf.name_scope('fc2') as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    with tf.name_scope('softmax') as scope:
        y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

    return y_conv

# 顔検出器
# detector = dlib.simple_object_detector("detector.svm")

images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
keep_prob = tf.placeholder("float")

logits = inference(images_placeholder, keep_prob)
sess = tf.InteractiveSession()

saver = tf.train.Saver()
sess.run(tf.global_variables_initializer())
saver.restore(sess, "model.ckpt")

if __name__ == '__main__':
    test_image = []
    for i in range(1, len(sys.argv)):
        img = cv2.imread(sys.argv[i])
        #グレースケール変換
        image_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

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


        #物体認識（顔認識）の実行
        facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))

        if len(facerect) == 1:
            print ("顔認識に成功しました。")
            print (facerect)

            #検出した顔の処理
            for rect in facerect:
                #顔だけ切り出して保存
                x = rect[0]
                y = rect[1]
                width = rect[2]
                height = rect[3]
                dst = img[y:y+height, x:x+width]
                new_image_path = "./result/" + sys.argv[1]
                cv2.imwrite(new_image_path, dst)

        elif len(facerect) > 1:
            # 複数顔が検出された場合はスキップ
            print ("顔が複数認識されました")
            print (facerect)

            if len(facerect) > 0:
                color = (255, 255, 255) #白
                for rect in facerect:
                    #検出した顔を囲む矩形の作成
                    cv2.rectangle(image, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=2)
            quit()

        else:
            # 顔検出に失敗した場合もスキップ
            print ("顔が認識できません。")
            quit()
        
        #形式を変換
        dst = cv2.resize(dst, (28, 28))
        test_image.append(dst.flatten().astype(np.float32)/255.0)
    test_image = np.asarray(test_image)

    for i in range(len(test_image)):
        result = []
        result = logits.eval(feed_dict={images_placeholder: [test_image[i]],keep_prob: 1.0 })
        print ("result")
        print (result)
        print ("小数第3桁で四捨五入")
        print (np.round(result,3))
```

###結果

```
$ python3 FaceType1.py fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg
[ INFO:0] Initialize OpenCL runtime...
顔認識に成功しました。
[[107  74 164 164]]
result
[[9.9965370e-01 3.4631684e-04]]
小数第3桁で四捨五入
[[1. 0.]]
```
使った画像
![fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/a532f3e7-df7f-33a7-730d-dc2e3a18487e.jpeg)
fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg

切り出された顔
![fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/64458c07-8b5e-f60f-d837-a486c05b3588.jpeg)

99.965%西島さんに分類されました。


それでは前回失敗してた画像を使ってみます。

```
$ python3 FaceType1.py f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg
[ INFO:0] Initialize OpenCL runtime...
顔認識に成功しました。
[[175 138 195 195]]
result
[[9.999999e-01 6.105071e-08]]
小数第3桁で四捨五入
[[1. 0.]]
```
使った画像
![f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/922f1137-eb52-2805-e5b2-bd6df36ef915.jpeg)
f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg
切り出されたおかお
![f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/094dcdc9-d630-760d-25b7-f56316dacd13.jpeg)

99.999%西島さんという結果が出ました〜。よかった。
というのも、計算させるときに切り出した顔のデータ出なく、引数に与えたデータそのまま使ってました(苦笑いしかない...)

石原さとみの画像でもテストします。

使った画像
![fe08c1be52084dfc0781eae08d00678cc7230deefb80b575a89e6f344d735797.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/85abda24-91f7-e7a2-7a25-0a404afae6be.jpeg)
fe08c1be52084dfc0781eae08d00678cc7230deefb80b575a89e6f344d735797.jpg

```
$ python3 FaceType1.py fe08c1be52084dfc0781eae08d00678cc7230deefb80b575a89e6f344d735797.jpg
[ INFO:0] Initialize OpenCL runtime...
顔認識に成功しました。
[[160 208 455 455]]
result
[[3.1513974e-08 1.0000000e+00]]
小数第3桁で四捨五入
[[0. 1.]]
```
100%石原さとみでした。

もう一枚くらいやってみる。
![ffb73a7d766e5da2d488eafad0761d88a8b4313937924993ec7e1ddc10e0d7dc.jpg](https://qiita-image-store.s3.amazonaws.com/0/223989/b8e5bb6b-87f0-0655-a8dc-959694c63b07.jpeg)
ffb73a7d766e5da2d488eafad0761d88a8b4313937924993ec7e1ddc10e0d7dc.jpg

```
$ python3 FaceType1.py ffb73a7d766e5da2d488eafad0761d88a8b4313937924993ec7e1ddc10e0d7dc.jpg
[ INFO:0] Initialize OpenCL runtime...
顔認識に成功しました。
[[ 67 115 221 221]]
result
[[1.4139876e-09 1.0000000e+00]]
小数第3桁で四捨五入
[[0. 1.]]
```
こちらも100%石原さとみでした。


###ちなみに

もういちど自分の顔使ってみました。
![IMG_6154.JPG](https://qiita-image-store.s3.amazonaws.com/0/223989/3b288dd6-6350-644e-a02f-6807a9fc493c.jpeg)
IMG_6154.JPG

```
$ python3 FaceType1.py IMG_6154.JPG
[ INFO:0] Initialize OpenCL runtime...
顔認識に成功しました。
[[ 42  67 144 144]]
result
[[2.2511498e-05 9.9997747e-01]]
小数第3桁で四捨五入
[[0. 1.]]
```
99.998%石原さとみだそうです。よろこび。
めでたしめでたし。