LoginSignup
3
3

More than 5 years have passed since last update.

芸能人の顔を機械学習で分類してみた(その5)

Last updated at Posted at 2018-04-07

引数で与えた画像の分類

芸能人の顔を機械学習で分類してみた(その3)で、うまくいかなかった画像分類にもういちどトライ。

何をやったかというと、下記データを使って学習させ、正解率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
fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg

切り出された顔
fc0c597d5dad95acf207adff0b2f7c8a44f3383caf16f6b82a75ba8412459de0.jpg

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
f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg
切り出されたおかお
f61a4affa931e919b890d752d858a12500d168780e3b74835779033e590e009a.jpg

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

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

使った画像
fe08c1be52084dfc0781eae08d00678cc7230deefb80b575a89e6f344d735797.jpg
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
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
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%石原さとみだそうです。よろこび。
めでたしめでたし。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3