Face API:Dev Basics/Keyword
Face APIはマイクロソフトのCognitive Servicesに含まれるAPIの1つで、顔検出/画像のグループ化/人物の特定などの機能を提供する。
Face APIは、マイクロソフトのCognitive Servicesに含まれるAPIの1つで、画像ファイルから顔を検出したり、グループ化したりといった処理を簡単なAPI呼び出しで実現できる。
Face APIでできること
Face APIは主に以下の機能を提供する。
- 顔検出
- 顔識別
ここでいう「顔検出」とは、APIに与えた画像から最大で64人までの(人の)顔を検出すること。このとき、検出した顔の画像内での位置に加えて、性別、年齢などの情報も抽出してくれる。
もう一方の「顔識別」は、複数の画像の中から指定した顔と似た顔を含む画像を識別したり、同じく複数の画像を与えると、顔が似ているかどうかを基にそれらをグループ化したりする機能である。
これらの機能が以下のAPIで提供されている。
- Detect
- Find Similar
- Group
- Identify
- Verify
また、顔の一覧(リスト)を作成したり、識別用に個人個人の顔を登録したりするためのAPIも用意されている。Face APIが提供する全APIは「Face API - V1.0」ページで一覧できるので、詳しくはそちらを参照されたい。
Face APIを利用するには、Azureでのサブスクリプションの追加が必要となる。また、2017年6月26日現在、Face APIは「West US」「East US 2」「West Central US」「West Europe」「Southeast Asia」など、Azureのリージョンの一部でのみ利用可能となっていて、リクエストURLもリージョンごとに異なるものとなる。
Face APIの価格については「Cognitive Services の価格 - Face API」ページを参照のこと。簡単にまとめると、20トランザクション/分、30,000トランザクション/月までは無料で利用できるFree、最大で10トランザクション/秒、1000トランザクションごとに課金が発生するStandardの2つの価格レベルがあり、それとは別に画像を保存するために使用する「フェースストレージ」を使用する場合には、そのための料金が別途発生する。
以下では、AzureでFace APIのサブスクリプションを追加し、APIの利用に必要なアクセスキーを取得したものとして、幾つかのAPIを実際に使ってみよう。サブスクリプションの追加/アクセスキーの取得の手順については「Dev Basics/Keyword: Microsoft Translator Text API」などを参考にしてほしい(本稿では割愛する。なお、Microsoft Translator Text APIではアクセスに必要なトークンを作成しているが、Face APIではトークンの作成は不要だ)。
Detect APIを使ってみる
ここでは、最もシンプルに顔を検出するDetect APIを使用してみよう。テストをするだけであれば、Detect APIのドキュメントページで、APIのテストコンソールを開き、必要な情報を入力して[Send]ボタンをクリックすればよい。詳しい手順は割愛するが、以下にこれを行っている様子を示す。
Detect APIのドキュメントを見ると、このAPIを呼び出す際には次のような情報を与えることが分かる。
- リクエストURL: リージョン.api.cognitive.microsoft.com
- メソッドの種類: POST
- returnFaceIdパラメーター: 検出された顔に関連付けられたIDを返すか。オプション(既定値はtrue)
- returnFaceLandmarksパラメーター: 検出された顔に含まれる目や鼻の位置を返すか。オプション(既定値はfalse)
- returnFaceAttributesパラメーター: 検出された顔を解析して、年齢や性別などの情報のうち、返送するものを指定する。オプション。指定可能な値にはage/gender/headPose/smile/facialHair/glasses/emotionなどがある(カンマ区切りで複数を指定可能)
これらの情報を基にリクエストURLを組み立て、リクエストボディーには画像ファイルのURLもしくは画像そのものを含める。
JavaScriptでこれを行うコード例を以下に示す。ここではreturnFaceIdパラメーターとreturnFaceLandmarksパラメーターについては既定値(それぞれ、true=IDを返送する、false=目や鼻の位置を返送しない)を利用するようにして、returnFaceAttributesパラメーターにはage(年齢)、gender(性別)、smile(笑顔かどうかを0〜1の数値で示す)を指定している。画像ファイルのURLを指定するコードに加えて、リクエストに画像ファイルをそのまま含めるコードも用意してある。
const request = require("request");
const fs = require("fs");
const key = "アクセスキー";
const url = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect";
const body = {
url: "https://insidernetpictures.blob.core.windows.net/pictures/face3.png"
};
const attrib="age,gender,smile";
const param=`?returnFaceAttributes=${attrib}`;
var opt = {
url: url + param,
headers: {
"Ocp-Apim-Subscription-Key": key,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
};
request.post(opt, (err, res, body) => {
console.log("URL");
console.log(JSON.parse(body));
});
// ローカルの画像ファイルを渡す場合
const image = fs.readFileSync("face3.png");
opt = {
url: url + param,
headers: {
"Ocp-Apim-Subscription-Key": key,
"Content-Type": "application/octet-stream"
},
body: image
};
request.post(opt, (err, res, body) => {
console.log("local file");
console.log(JSON.parse(body));
});
実際に利用した画像を以下に示す(以下ではぼかしを入れてあるが、実際にはぼかしなしの画像を使用)。
検出結果はJSON形式のデータとして返送される。以下に上のコードを実行した結果を示す。
> node facedetect.js
URL
[ { faceId: '4e3690d7-6220-4039-b2fd-fb591347ed8c',
faceRectangle: { top: 418, left: 491, width: 239, height: 239 },
faceAttributes: { smile: 0.001, gender: 'male', age: 37 } } ]
local file
[ { faceId: 'e67ae29b-0e89-4197-ad82-ce99e22cf0d2',
faceRectangle: { top: 418, left: 491, width: 239, height: 239 },
faceAttributes: { smile: 0.001, gender: 'male', age: 37 } } ]
どちらも同じファイルなので、笑顔ではない(smile=0.001)、男性、37歳という結果になっている。
Find Similar APIを使用してみる
Find Similar APIは、複数の画像ファイルのグループ化するものだ。グループ化にはDetect APIの呼び出しで返送されるfaceIdの値が用いられる。faceId値の配列をAPIに渡すと、それらの値を利用して、画像のグループ化を行い、それがfaceId値の配列として返送される。詳細は割愛するが、実際にこのAPIを呼び出すコードを以下に示す。
const request = require("request");
const key = "アクセスキー";
const detectUrl = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect";
const groupUrl = "https://westus.api.cognitive.microsoft.com/face/v1.0/group";
var opt = {
headers: {
"Ocp-Apim-Subscription-Key": key,
"Content-Type": "application/json"
}
};
function callDetectAPI(image) {
return new Promise(function(resolve, reject) {
opt.url = detectUrl;
opt.body = JSON.stringify({
url: image
});
request.post(opt, (err, res, body) => {
var tmp = JSON.parse(body);
resolve(tmp[0].faceId);
});
})
}
function callGroupAPI(ids) {
return new Promise(function(resolve, reject) {
opt.url = groupUrl;
opt.body = JSON.stringify({
faceIds: ids
});
request.post(opt, (err, res, body) => {
resolve(body);
})
})
}
const images = [
"https://insidernetpictures.blob.core.windows.net/pictures/face2.png",
"https://insidernetpictures.blob.core.windows.net/pictures/face3.png",
"https://insidernetpictures.blob.core.windows.net/pictures/face4.png",
"https://insidernetpictures.blob.core.windows.net/pictures/face5.png",
"https://insidernetpictures.blob.core.windows.net/pictures/face6.png"
];
var promiselist = images.map(callDetectAPI);
Promise.all(promiselist)
.then(result => {
console.log(result);
return callGroupAPI(result);
})
.then(group => console.log(JSON.parse(group)));
簡単にコードの説明をしておこう。まず、ここでは画像ファイルのURLを含んだ配列を用意して(face1.pngが配列にないのは、うまく顔検出ができなかったため)、それにcallDetectAPI関数を適用している。callDetectAPI関数はJavaScriptのPromiseオブジェクトを返すようになっていて、呼び出し完了時にはfaceId値が得られるようになっている。そして、Promise.allメソッドを使って、配列の全要素のfaceId値が得られるのを待機する。
全てのfaceId値がそろったら、callGroupAPI関数を呼び出す。Group APIの詳細な仕様はドキュメントをご覧いただくとして、簡単にいえば、リクエストボディーにfaceId値を格納した配列を指定して、呼び出せばよい。返送される値は例えば、次のようなものになる。
{
"groups": [
[
"faceIdその1",
"faceIdその2",
],
[
"faceIdその3",
"faceIdその4",
]
],
"messyGroup": [
"faceIdその5",
]
}
groupsプロパティには、グループ化された画像が配列の配列として格納される。判断できなかったものはmessyGroupプロパティに格納される。上の例であれば、2つのグループに画像がグループ化されたということになる。
実際に上のコードを実行した結果を以下に示す。
> node facegrouping.js
[ '37a06702-e803-48b6-a768-61b21dc6ac62',
'642e6bc2-6368-4859-a738-7000d21b582e',
'5e9269e9-075f-40df-83ea-6721fbb73352',
'9cdc5a92-4484-419c-aa7f-69239fc49c3f',
'74c865ee-4995-4430-857a-cd45f41ba503' ]
{ groups:
[ [ '5e9269e9-075f-40df-83ea-6721fbb73352',
'74c865ee-4995-4430-857a-cd45f41ba503',
'37a06702-e803-48b6-a768-61b21dc6ac62' ] ],
messyGroup:
[ '642e6bc2-6368-4859-a738-7000d21b582e',
'9cdc5a92-4484-419c-aa7f-69239fc49c3f' ] }
最初の出力は、得られた画像ファイルのfaceId値だ(24時間有効)。その次が、グループ化の結果である。出力結果を見ると分かるが、groupsプロパティに配列が1つしかないことから、うまくグループ化ができていない。上のコードで画像ファイルのURLの配列に、同じURLを含めるようにすると、次のように複数のグループが得られたので、おそらくは画像ファイルの選定がよくなかったのだと思われる(つまり、Group APIの動作自体に問題はなさそうだ)。
> node facegrouping.js
[ '37a06702-e803-48b6-a768-61b21dc6ac62',
'642e6bc2-6368-4859-a738-7000d21b582e',
'5e9269e9-075f-40df-83ea-6721fbb73352',
'9cdc5a92-4484-419c-aa7f-69239fc49c3f',
'74c865ee-4995-4430-857a-cd45f41ba503',
'37a06702-e803-48b6-a768-61b21dc6ac62',
'642e6bc2-6368-4859-a738-7000d21b582e',
'5e9269e9-075f-40df-83ea-6721fbb73352',
'9cdc5a92-4484-419c-aa7f-69239fc49c3f',
'74c865ee-4995-4430-857a-cd45f41ba503' ]
{ groups:
[ [ '5e9269e9-075f-40df-83ea-6721fbb73352',
'5e9269e9-075f-40df-83ea-6721fbb73352',
'74c865ee-4995-4430-857a-cd45f41ba503',
'74c865ee-4995-4430-857a-cd45f41ba503',
'37a06702-e803-48b6-a768-61b21dc6ac62',
'37a06702-e803-48b6-a768-61b21dc6ac62' ],
[ '642e6bc2-6368-4859-a738-7000d21b582e',
'642e6bc2-6368-4859-a738-7000d21b582e' ],
[ '9cdc5a92-4484-419c-aa7f-69239fc49c3f',
'9cdc5a92-4484-419c-aa7f-69239fc49c3f' ] ],
messyGroup: [] }
興味のある方は、上のコードを利用して、ご自分でも画像ファイルのグループ化をしてみよう。
Face APIは画像ファイルから顔を検出したり、グループ化したりできる。本稿では触れなかったが、faceId値あるいは画像ファイルを保存した「フェースリスト」から、指定した顔をよく似たものを選別したり、「これは誰それの顔」と個人を特定したりもできる。簡単なAPI呼び出しでこうした処理を行えるので、興味のある方はぜひ使ってみよう。
参考資料
- Face API: Face APIのトップページ
- Face API JavaScript Quick Starts: クイックスタートページ。JavaScriptだけではなく、さまざまな言語でFace APIを使うための基本が説明されている
- Face API - V1.0: Face APIが提供するAPIの一覧とドキュメント
Copyright© Digital Advantage Corp. All Rights Reserved.