昨日は、中野ICTCOにて第4回IoT+AIもくもく会を開催しました。月に1回のイベントで第4回ですから、もう4ヶ月経つんですね。その前の企画(IoT+AI先遣隊)を合わせると半年くらい会が続いていることになります。ありがたいことです。
もくもく会なので、それぞれがやりたいことを気ままにやっています。私は、ついこの間、解散したアイドルグループ℃-uteのメンバーの顔認識をWatsonのVisual Recognitionでやってみようということで、℃-uteが解散した日にちょっとだけやったことの延長戦を。
まずは顔だけを切り抜くと認識精度が上がるのではないかというアイディアをFacebookでいただいていたので、そこから始めました。
OpenCVでやってみる
まずは定番というか、OpenCVを使って画像の中から顔の部分を検出してみることにしました。
import cv2
import glob
import os
from os.path import basename
#cascade_path = '/usr/local/opt/opencv3/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml'
cascade_path = '/usr/local/opt/opencv3/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
#cascade_path = '/usr/local/opt/opencv3/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml'
#cascade_path = '/usr/local/opt/opencv3/share/OpenCV/haarcascades/haarcascade_frontalface_alt_tree.xml'
image_path = './data/'
tmp_path = './tmp/'
members = ['airi', 'chisato', 'mai', 'maimi', 'saki']
for member in members:
member_image_path = image_path + member
member_tmp_path = tmp_path + member
for file in glob.glob(member_tmp_path + '/*.*'):
os.remove(file)
color = (255, 255, 255)
cascade = cv2.CascadeClassifier(cascade_path)
for file in glob.glob(member_image_path + '/*.*'):
print(file)
tmp_file = tmp_path + member + '/' + basename(file)
image = cv2.imread(file)
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
if len(facerect) > 0:
for rect in facerect:
cv2.rectangle(image, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), color, thickness=4)
cv2.imwrite(tmp_file, image)
else:
print('face not found! : ' + str(len(facerect)))
ざっと、こんなコード。これは切り抜くというより、画像の顔の部分に矩形を描く実装です。
これで、きちんと顔を検出できたのはだいたい3〜4割といったところでした。顔以外の部分も顔として検出してしまったり、まったく顔を検出できなかったり、いろいろでした。
OpenCVの場合、機械学習とかではなく、単なるパターン認識なので仕方ないのか・・・。
Watsonでやってみる
ということで、WatsonのVisual Recognitionを使い(具体的にはFace Detect)、顔の部分の座標を得て、切り抜くことにしました。
import cv2
import json
import glob
import os
from os.path import basename
from watson_developer_cloud import VisualRecognitionV3
vr = VisualRecognitionV3('2016-05-20', api_key='')
image_path = './data/'
tmp_path = './tmp/'
members = ['airi', 'chisato', 'mai', 'maimi', 'saki']
for member in members:
member_image_path = image_path + member
member_tmp_path = tmp_path + member
for file in glob.glob(member_tmp_path + '/*.*'):
os.remove(file)
color = (255, 255, 255)
for file in glob.glob(member_image_path + '/*.*'):
print(file)
tmp_file = tmp_path + member + '/' + basename(file)
image = cv2.imread(file)
try:
with open(file, 'rb') as image_file:
result = vr.detect_faces(images_file=image_file)
except:
continue
if 'faces' not in result['images'][0]:
continue
if len(result['images'][0]['faces']) > 0:
rect = result['images'][0]['faces'][0]['face_location']
top = int(rect['top'])
left = int(rect['left'])
height = int(rect['height'])
width = int(rect['width'])
print("top:%d left:%d width:%d height:%d" % (top, left, width, height))
#cv2.rectangle(image, (left, top), (left + width, top + height), color, thickness=4)
#cv2.imwrite(tmp_file, image)
dst = image[top:top+height, left:left+width]
cv2.imwrite(tmp_file, dst)
else:
print('face not found! : ' + str(len(result.images[0].faces)))
こちらは、きちんと切り抜く実装になっています。
Watsonを使うときちんと顔を認識した確率はなんと100%!
メンバー毎に15枚なので、全部で75毎の画像がありましたが、すべて顔の部分を検出し切り抜くことに成功したのです。
さすがのWatson。機械学習の威力か?
ただ、本題は・・・
で、ここまでの顔の切り抜きは前振りでありまして、本題はVisual Recognitionのカスタム学習器を作り、メンバーの画像から名前を予測したいのです。
こちらの方は、結局まだいまひとつの結果となってしまいました・・・。訓練データとして画像の枚数が少ないのか、ネガティブデータを入れていないのがマズいのか・・・。
もうちょっと調べてみたいと思います。
第5回IoT+AIもくもく会は7月16日開催
こんな感じでやっているもくもく会ですが、次回は7月16日開催です。
こちらのFacebookグループに参加いただくと、開催のお知らせを致します。