ネタ的にはこの記事の続きです。
yamaguchi-1024.hatenablog.com
ただし、今回は顔認識でなく目認識です。
目認識準備
上のリンクの記事を参考にしていただいて、detector.svmを作ったのと同様の手順でeyes_detector.svmを作ります。
メガネ準備
適当なサイトからいい感じのメガネの画像を取ってきます。
画像の白い背景を透明にします。
$ mogrify 9.png -fuzz 60% -transparent white
こうなります。(実は背景はちゃんと透明になってます)
メガネ男子かわいい
このスクリプトと同じディレクトリにeyes_detector.svmを入れ、glasses/というディレクトリにメガネを入れます。
下記のサンプルでは、qを押すと終了、sで保存、3~9とw,e,r,tでかけてくれるメガネが変わるようにしてあります。
#!/usr/bin/python # -*- coding: utf-8 -*- import math import os import sys import dlib from skimage import io import cv2 ##入力している。 detector = dlib.simple_object_detector("eyes_detector.svm") cap=cv2.VideoCapture(0) glass=cv2.imread("glasses/2_tra.png",-1)#最初のメガネはこれ。-1をつけるとアルファチャンネルも読んでくれるみたい。 ##メガネの中心の座標 center_glasses=[[214,214],[490,214]] nyan=0 #後で使う while(cap.isOpened()): ##そのままだと遅れが生じてしまうので、時間稼ぎしている。 cap.read() cap.read() cap.read() cap.read() cap.read() cap.read() ##いっかいのwhile文の中で使い捨てるglass_useをつくる glass_use=glass height,width=glass_use.shape[:2] ##読み込んでいる。 ret,frame = cap.read() ##detectしている。ついでに目の中心の座標center_eyeも求めている。 dets = detector(frame) center_eye=[[0,0],[0,0]] i=0 for d in dets: if i<2: cv2.rectangle(frame, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 2) center_eye[i]=[math.fabs(d.right()+d.left())/2,math.fabs(d.top()+d.bottom())/2] i=i+1 print "center_eye=",center_eye if (center_eye[0][0]!=0 and center_eye[1][0]!=0 and center_eye[0][1]!=0 and center_eye[1][1]!=0): ##目の中心から目の中心の距離とメガネの中心からメガネの中心の距離を求め、メガネの倍率を求めている。 dist=math.fabs((center_eye[1][0]-center_eye[0][0])**2+(center_eye[1][1]-center_eye[0][1])**2) sqrt=math.sqrt(dist) proportion=sqrt/math.fabs(center_glasses[0][0]-center_glasses[1][0]) #print "proportion=",proportion #print dist ##glass_useがproportionに調度良くなるようにresizeしている。 #print "x,y=",(math.fabs(proportion*width),math.fabs(proportion*height)) width2=int(math.fabs(proportion*width))#整数のほうが見やすく、特に問題がなかったのでキャストしてあります。 height2=int(math.fabs(proportion*height)) #glass_use2=cv2.createImage(cvSize(math.fabs(proportion*width),math.fabs(proportion*height)),IPL_DEPTH_8U,3) #cv2.resize(glass_use,glass_use2,(math.fabs(proportion*width),math.fabs(proportion*height)),0,0,0) glass_use2=cv2.resize(glass_use,(width2,height2)) #cv2.imshow("glass",glass_use2) ##メガネをresizeしてしまったのでメガネの中心の座標もresizeします。 center_glass_newx=center_glasses[0][0]*proportion center_glass_newy=center_glasses[0][1]*proportion ##メガネが目の位置に合うように、初期位置(0,0)からずらすglass_x,glass_yを作っている。 if center_eye[0][0]<center_eye[1][0]: glass_x=center_eye[0][0]-center_glass_newx glass_y=center_eye[0][1]-center_glass_newy else: glass_x=center_eye[1][0]-center_glass_newx glass_y=center_eye[1][1]-center_glass_newy glass_x=math.fabs(int(glass_x)) glass_y=math.fabs(int(glass_y)) ##メガネの画像のアルファチャンネルだけ取り出したmaskを作っている。 mask=glass_use2[:,:,3] #cv2.imshow("mask",mask) mask=cv2.cvtColor(mask,cv2.cv.CV_GRAY2BGR) mask=mask/255.0 print "width2=",width2 print "height2=",height2 #print "mask=",mask #glass=glass[:,:,:3] ##frameに重ねている。 print "glass_x=",glass_x print "glass_y=",glass_y frame[glass_y:height2+glass_y,glass_x:width2+glass_x]*=1-mask#スライス怖かったです frame[glass_y:height2+glass_y,glass_x:width2+glass_x]+=glass_use2[:,:,:3]*mask #frame[0:height2,0:width2]=glass_use2[:,:,:3] ##表示させている。あとはキー入力のおまけ。 cv2.imshow("nyan",frame) k=cv2.waitKey(2) & 0xFF if k==ord('q'): sys.exit() elif k==ord('s'): image="gift"+str(nyan)+".png" cv2.imwrite(image,frame) elif k==ord('3'): glass=cv2.imread("glasses/3_tra.png",-1) elif k==ord('4'): glass=cv2.imread("glasses/4_tra.png",-1) elif k==ord('5'): glass=cv2.imread("glasses/5_tra.png",-1) elif k==ord('6'): glass=cv2.imread("glasses/6_tra.png",-1) elif k==ord('7'): glass=cv2.imread("glasses/7_tra.png",-1) elif k==ord('8'): glass=cv2.imread("glasses/8_tra.png",-1) elif k==ord('9'): glass=cv2.imread("glasses/9_tra.png",-1) elif k==ord('w'): glass=cv2.imread("glasses/10_tra.png",-1) elif k==ord('e'): glass=cv2.imread("glasses/11_tra.png",-1) elif k==ord('r'): glass=cv2.imread("glasses/13_tra.png",-1) elif k==ord('t'): glass=cv2.imread("glasses/14_tra.png",-1)
初心者なので、画像はどうしても(x,y)というイメージを持っていたのですが行列として処理しているため(列、行)みたいな感じで混乱しました。
結果
C=5でもまあまあ良く出来ています。誤判定はほぼなく、正面を向いてできるだけカメラを見て斜め前方から光を当てれば認識してくれます。
・・・ってかなりダメダメな気もしますが今回はこの程度で十分なのでよしとしました。