引数で与えた画像の分類
芸能人の顔を機械学習で分類してみた(その3)で、うまくいかなかった画像分類にもういちどトライ。
何をやったかというと、下記データを使って学習させ、正解率98%の精度にできたモデルを使って、引数に画像を与えて結果を0/1に返すってやつをやっていました。
<使ったデータ>
trainデータ:石原さとみ(100枚), 西島秀俊(100枚)
testデータ :石原さとみ(30枚), 西島秀俊(30枚)
<ラベル>
0:西島秀俊
1:石原さとみ
今回は、画像を与えると、顔部分だけを切り出して、その計算結果を返すように修正しました。
#!/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
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
切り出されたおかお
99.999%西島さんという結果が出ました〜。よかった。
というのも、計算させるときに切り出した顔のデータ出なく、引数に与えたデータそのまま使ってました(苦笑いしかない...)
石原さとみの画像でもテストします。
使った画像
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
$ 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
$ 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%石原さとみだそうです。よろこび。
めでたしめでたし。