face.comの顔認識APIとim.kayac.comを使ってPCに人(の顔)が近付いたらiPod touchに知らせる
face.comの顔認識APIが公開された(1年で70億枚の顔写真をスキャンしたFace.comが顔認識APIを無料で一般公開 | TechCrunch Japan)。珍しいAPIなので、何に使えるか考えて、とりあえず、カメラに近付いた人の顔の認識に使ってみることにした。
ただ近付いたと分かるだけでもつまらないので、Arduinoの状態をim.kayac.comに送信してiPod touchで確認する - DiaryExceptionのネタを流用して、顔が近付いたらiPod touchに知らせる。
少し長いエントリーになったが、以下の4つの章に分けられる。
画像アップローダの設置
face.comの顔認識APIは画像のURLを引数に取るため、PC(ローカル)にある画像を解析対象とさせることは出来ない。そこで、予め画像アップローダを設置し、PCからURLで参照出来る位置に画像をアップロードして顔認識APIに読ませる。
アップローダとなるCGIスクリプト(Python)は以下のようにした。
#!/usr/bin/python # -*- coding: utf-8 -*- import cgi import os.path import sys print "Content-Type: text/html\n" html = """ <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>File uploader</title> </head> <body> <h1>File uploader</h1> <form action="%s" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" /> </form> </body> </html>""" form = cgi.FieldStorage() if "file" in form: item = form["file"] if item.file: out = open(os.path.join('uploader_images', item.filename), "wb") out.write(item.file.read()) out.close() print html % sys.argv[0]
このスクリプトを、face.comが参照出来るWebサーバに設置する。スクリプトと同じ場所に、uploader_imagesという名前のディレクトリを作り、CGIがディレクトリ内にファイルを書き込めるようにパーミッションを変更しておく。
face.comとim.kayac.comのアカウント登録(APIキー取得)
Logo.com (@heylogoapp) • Instagram photos and videosとim.kayac.comでアカウント登録をすることが出来る。
face.comはアプリケーション登録を適当にしておけば、API keyとAPI Secretを取得出来る。
iPod touchにはim.kayac.comのアプリを入れておくこと。
PCに接続したカメラからカメラ画像を読み取り、画像をアップローダに転送、face.comで顔認識結果を取得し、もし顔があればim.kaya.comでiPod touchに知らせる
Webカメラの画像を取得するために、バーコードリーダ/ライタと同じくProcessingのライブラリを用いた。WebカメラにはiSightを用いる。
スクリプトはJythonで書き、外部ライブラリとしてProcessingの他にJSONIC - simple json encoder/decoder for javaを使っている。
画像アップローダに画像を転送するために、横着をしてcurlコマンドを使っている。Macならデフォルトで入っているので気にしない。
#!/opt/usr/bin/jython # -*- coding: utf-8 -*- from processing.core import PApplet from processing.video import Capture from net.arnx.jsonic import JSON from javax.swing import JFrame, JPanel, BoxLayout from java.util import Timer, TimerTask from java.io import File from javax.imageio import ImageIO import os import time import urllib import hashlib CHECK_INTERVAL = 30 # (sec) # カメラ画像をチェックする時間間隔 / 短すぎるとface.comのAPIアクセス回数制限に引っかかる UPLOADER_URL = "http://MYCGISERVER/uploader.py" # アップローダのURL UPLOADER_IMAGEURL = "http://MYCGISERVER/uploader_images/%s" # アップローダに転送された画像の位置 / %sに画像ファイル名が入る FACE_URL = "http://api.face.com/faces/detect.json" FACE_APIKEY = "YOUR_FACE_COM_API_KEY" FACE_APISECRET = "YOUR_FACE_COM_API_SECRET" IMKAYACCOM_USER = "YOUR_IM_KAYAC_COM_USER" IMKAYACCOM_SECRETKEY = "YOUR_IM_KAYAC_COM_SECRET_KEY" ## im.kayac.com # im.kayac.com -> iPod touch def postImkayaccom(faces, imgurl): url = "http://im.kayac.com/api/post/" + IMKAYACCOM_USER msg = u"" for face in faces: msg += u"「%s」" % face msg += u"がお前のPCに近付いているッ!" message = msg.encode("UTF-8") signature = hashlib.sha1(message+IMKAYACCOM_SECRETKEY).hexdigest() opt = urllib.urlencode({ "message": message, "handler": imgurl, "sig": signature, }) res = urllib.urlopen(url, opt) # print res ## Processing WIN_W = 320 WIN_H = 240 class FacePanel(PApplet): def __init__(self): self.mC = None def setup(self): self.size(WIN_W, WIN_H) self.background(255) self.frameRate(12) self.mC = Capture(self, self.width, self.height, 12) class FaceCheck(TimerTask): def __init__(self, mc): super(FaceCheck, self).__init__() self.mC = mc def run(self): if self.mC.available(): IMAGE_FILENAME = "out_" + time.strftime("%Y%m%d%H%M%S") + ".jpg" # 画像ファイル名 out = File(IMAGE_FILENAME) ImageIO.write(self.mC.getImage(), "jpg", out) os.system("curl -F file=@" + IMAGE_FILENAME + " " + UPLOADER_URL) # アップローダに画像を転送 print("Upload a shot") params = urllib.urlencode({ "api_key": FACE_APIKEY, "api_secret": FACE_APISECRET, "urls": UPLOADER_IMAGEURL % IMAGE_FILENAME, }) time.sleep(2) request = urllib.urlopen(FACE_URL + "?%s" % params ) response = request.read() json_data = JSON.decode(response) # face.comからのレスポンスをJSONデータとして読み込み faces = json_data["photos"][0]["tags"] if len(faces) != 0: # 認識される顔は0個以上 genders = [] for face in faces: gender = face["attributes"]["gender"]["value"] # 顔の性別を取得 genders.append(gender) postImkayaccom(genders, UPLOADER_IMAGEURL % IMAGE_FILENAME) # im.kayac.comで知らせる timer = Timer() timer.schedule(FaceCheck(self.mC), 0, CHECK_INTERVAL * 1000) def draw(self): if self.mC.available(): self.mC.read() self.image(self.mC, 0, 0) ## main mainframe = JFrame(title="FaceReader", resizable=0, defaultCloseOperation=JFrame.EXIT_ON_CLOSE) frame = JPanel() frame.setLayout(BoxLayout(frame, BoxLayout.Y_AXIS)) fpanel = FacePanel() frame.add(fpanel) fpanel.init() while fpanel.defaultSize and not fpanel.finished: pass mainframe.add(frame) mainframe.pack() mainframe.visible = 1
実行
実行するためには、外部ライブラリをCLASSPATHに追加しておく必要がある。
$ export CLASSPATH=/Applications/Processing.app/Contents/Resources/Java/libraries/video/library/video.jar:/Applications/Processing.app/Contents/Resources/Java/core.jar:./jsonic-1.2.0/jsonic-1.2.0.jar:$CLASSPATH $ jython facetotouch.py -d32
動作チェックのために、自分の顔も使ったが、顔を晒すのは恥ずかしいので、本棚にあった眞鍋かをりのブログ本を使って動作チェックをした様子を公開する。
上記スクリプトでは、30秒毎にカメラ画像をチェックしている(クリティカルな場面では長過ぎる間隔だが)。しばらくすると、face.comから顔認識結果が返ってきて、眞鍋かをりの顔が認識されたので、iPod touchにそれを知らせるメッセージがプッシュされてくる。
im.kayac.comのアプリを開き、リストからメッセージをクリックすると、Safariで画像URLが開く。
face.comはWebアプリで顔認識APIを用いることを想定しているようだが、このようにデスクトップアプリでも使える可能性を示すことが出来た。