先日RaspberryPiにOpecCVをインストールしてみました。(Raspberry Pi のカメラモジュールとOpen CV3で顔認識する - Qiita)
OpenCVの特徴分類器を利用すれば顔識別も出来るようなのですが、少々難易度が高そうなので、今回は中国製API、FACE++ を利用しました。
環境
- Raspberry Pi3 (RASPBIAN JESSIE WITH PIXEL 4.4 / node.js v6.8.1)
- Raspberry Pi カメラモジュール Raspberry Pi Camera Board
- Raspberry Pi カメラモジュール専用 Blackケース
- パルプ・フィクション/ サミュエル・L・ジャクソン ジュールス・ウィンフィールド 13インチ トーキングフィギュア
- パルプ・フィクション/ ジョン・トラボルタ ビンセント・ベガ 13インチ トーキングフィギュア
FACE++
結構以前に話題になったWebサービスで、APIも公開されています。パラメーターはこちらで詳しく解説されています。
Face++のAPIを使って、PHPで顔認証をする方法 - Syncer
さらに認識した顔をグルーピングし、識別するAPIがありました。こちらで詳しく解説されています。
無料API「face++」で顔から双子を判別 - FaMirror Project
OpenCVを利用してRasPiから顔画像の抽出が出来るようになったので、それを利用します。今回読み込む画像は各10枚づつにしました。
ちなみに画像をGETリクエストするとこんなレスポンスが得られます。
{
"face": [
{
"attribute": {
"age": {
"range": 7,
"value": 42
},
"gender": {
"confidence": 99.9747,
"value": "Male"
},
"race": {
"confidence": 97.8304,
"value": "Black"
},
"smiling": {
"value": 0.734695
}
},
"face_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
//略
}
黒人男性で42歳前後、と識別されました。
{
"face": [
{
"attribute": {
"age": {
"range": 7,
"value": 34
},
"gender": {
"confidence": 96.3747,
"value": "Male"
},
"race": {
"confidence": 99.90299999999999,
"value": "White"
},
"smiling": {
"value": 9.09543
}
},
"face_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
//略
}
白人男性で34歳前後と出ました。
これらのidを名前毎に分類し、さらにグループとして登録します。今回はサミュエル・L・ジャクソン、ジョン・トラボルタ、私の3名を登録しました。
登録したグループに撮影した写真をGETリクエストするとこのようなレスポンスが得られます。
{
"face": [
{
"candidate": [
{
"confidence": 75.559387,
"person_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"person_name": "samuel",
"tag": ""
},
{
"confidence": 2.307938,
"person_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"person_name": "travolta",
"tag": ""
},
{
"confidence": 0.967236,
"person_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"person_name": "pon_dad",
"tag": ""
}
],
"face_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
//略
"session_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
samuel
の確率75.5%、travolta
の確率2.3%、pon_dad
の確率0.9%と出ました。まあ、間違いなく私では無いということが分かります。
curl -X POST コマンドでリクエスト
RasPiとOpenCVで撮影・保存した画像をGETリクエストで送信するのにrequestモジュールを使おうと思ったのですが、上手くいかなかったのでここはchild_prosess
とcurl -X POST
コマンドを利用することにしました。
//略 OpenCVで顔画像を切り出して保存
im2.save('./public/images/face_2.jpg');
var filename = "./public/images/face_2.jpg"
var facepp = exec('curl -X POST "https://apicn.faceplusplus.com/recognition/identify?api_key=<API KEY>e&api_secret=<API Secret>&group_name=pulp_fiction" -F "img=@' + filename + '"')
jsonデータの抽出
配列と連想配列が混在したjsonデータを抽出すると訳が分からなくなるのですが、こちらの記事(【js】jsonデータの配列を取得して取り出すお話 - 仕事の事やプライベートな事を適当に書いていくブログ)を参考になんとか欲しいデータを抽出することが出来ました。
こんな感じです。
//略 OpenCVで顔画像を切り出して保存
im2.save('./public/images/face_2.jpg');
var filename = "./public/images/face_2.jpg"
var facepp = exec('curl -X POST "https://apicn.faceplusplus.com/recognition/identify?api_key=<API KEY>e&api_secret=<API Secret>&group_name=pulp_fiction" -F "img=@' + filename + '"',
function (error, res) {
console.log(res)
var identify = JSON.parse(res)
var a = identify.face
var b = []
var c = []
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < a[i]["candidate"].length; j++) {
b.push(a[i]["candidate"][j].person_name);
c.push(a[i]["candidate"][j].confidence);
};
};
if(c[0] > 60){
console.log(b[0])
console.log(c[0])
io.sockets.emit('msg', b[0] + ' ' + c[0]);
}
今回のグループは3人なので、レスポンスデータの3人を配列に入れて一番最初の人名と割合を抽出しました。
今回は確率が60%以上で本人と判断し、本人に場合はsocket.io
のemit
を利用してクライアントサイドにその内容を送信します。
## まとめ
今回は対象がフィギュアということもあり、またRasPiのカメラを使って正面から撮影しているので、学習させる写真が10枚位でも判別がつきました。(本人認証を思いつきで60%以上と設定したのですが、根拠は特ありません。一般的には何%位で本人だと判断するのでしょうか…。)
スナップ写真やインターネット上の画像などを利用する際は、トリミングの加工・変形などもう少し工夫が必要だと思います。
ロボットに取り付けた固定式のカメラなどでは、結構使えるかもしれませんね。ではまた。