以前にAmazon Rekognitionの顔比較 (CompareFaces)の使い方について触れたことがあったのですが、その時はPythonを使ったものでした。今回はPHPで顔分析する方法について少し調べてみたので、その備忘録として記事をまとめてみようかと思います。

Rekognitionは有料ですが、高精度かつ高機能な顔分析が可能で、応用すれば様々なアプリケーションを構築することができます。OpenCVを使い自前で実装するのはちょっと無理じゃないかな…と思えるような高度な分析もさらっとできてしまいます。

今回はPHPのGDライブラリのImage関数群も併用し、検出した顔を矩形で囲んだり、切り取って画像として保存したりする方法についてまとめてみます。

スポンサーリンク




目次

  1. AWSコンソールのIAMでシークレットキーを発行
  2. SDKをComposerで導入
  3. 顔分析後、矩形で囲んだ画像を保存してみる
  4. 顔分析後、顔の切り取り画像を保存してみる
  5. まとめ

1. AWSコンソールのIAMでシークレットキーを発行

SDKをダウンロードしてプログラムを走らせるには、IAMでユーザーを作成し、「アクセスキー」と「シークレットキー」を入手しなければなりません。では早速、AWSコンソールにアクセスしてみましょう。

AWS Identity and Access Management (IAM)
https://console.aws.amazon.com/iamv2/home#/users

アクセスできたら、画面右上の「ユーザーを追加」をクリックします。

次に「ユーザー名」を入力します。ユーザー名といっても、今回はアクセスキーの発行が目的なので、人名ではなくプロジェクト名を入力してみることにします。その方が分かりやすいと思います。

また「アクセスの種類を選択」で「アクセスキー・プログラムによるアクセス」にチェックしておきます。

アクセス許可の設定に進んだら「既存のポリシーを直接アタッチ」をクリックして「ポリシーのフィルター」で「Rekognition」を検索し「AmazonRekognitionReadOnlyAccess」にチェックして、次に進みます。

タグの追加に進んだら「キー」を入力しますが、今回は単にアクセスキーの発行が目的なので、適当に任意の文字列を入力しておきます。値は空欄で問題ありません。

確認画面です。問題なければ「ユーザの作成」ボタンをクリックします。

ユーザーが作成されました。この画面の「アクセスキーID」と「シークレットアクセスキー」を控えておきましょう。

2. SDKをComposerで導入

今度は、開発環境にSDKを導入します。今回はPHPでコードを用意することにしましたが、SDKは「Composer」で導入が可能なので簡単です。開発を行うディレクトリで実行してください。

curl -sS https://getcomposer.org/installer | php
php composer.phar require aws/aws-sdk-php

vendor」ディレクトリが作成されていればSDKの導入が完了です。

ちなみに、macOSにはComposerが入ってませんのでインストールが必要です。下記が参考になりました。

Qiita – Macにcomposerをインストール
https://qiita.com/shosho/items/572b3c356fc97214790b

3. 顔分析後、矩形で囲んだ画像を保存してみる

準備が整ったので、早速コードを書いてみましょう。顔認識は「DetectFaces」というAPIで行います。このAPIの凄いところは、様々な顔の特徴(目を開けているか、メガネをかけているか等)だけではなく、感情(落ち着いているか、幸福か、怒っているか等)のパラメーターまで返してくれるところです。

今回は基本的な顔認識のみ行い、単に顔を矩形線で囲ってみたいと思います。なお、矩形線で囲ったり、画像を出力したりする部分はPHPのGDライブラリが必要になります。

<?php
require 'vendor/autoload.php';
use Aws\Rekognition\RekognitionClient;

// Rekognition基本設定
$options = [
	'region'      => 'us-east-2',
	'version'     => 'latest',
	'credentials' => [
		'key'     => '----- アクセスキーID -----',
		'secret'  => '----- シークレットアクセスキー -----'
	]
];

// 顔検出画像
$target_img = 'image/target.jpg';

// 画像サイズ判定
$img_data = file_get_contents($target_img);
$scheme = 'data:application/octet-stream;base64,';
$image_size = getimagesize($scheme . base64_encode($img_data));
$img_w = $image_size[0];
$img_h = $image_size[1];

try {
	$rekognition = new RekognitionClient($options);

	// 顔検出
	$result = $rekognition->DetectFaces([
		'Image' => [
			'Bytes' => file_get_contents($target_img),
		]
	]);

} catch (Exception $e) {
	echo $e->getMessage() . PHP_EOL;
	exit('DetectFaces error');
}

// 顔配列初期化
$positions = [];

// 出力座標計算
foreach ($result["FaceDetails"] as $face_details) {
	$p1x = intval($face_details["BoundingBox"]["Left"] * $img_w);
	$p1y = intval($face_details["BoundingBox"]["Top"] * $img_h);
	$p2x = intval($face_details["BoundingBox"]["Width"] * $img_w + $p1x);
	$p2y = intval($face_details["BoundingBox"]["Height"] * $img_h + $p1y);
	array_push($positions, array($p1x, $p1y, $p2x, $p2y));
}

// 判定画像出力
$report = imagecreatefromjpeg($target_img);
foreach ($positions as $position) {
	imagesetthickness($report, 2);
	imagerectangle($report, $position[0], $position[1], $position[2], $position[3], 0xFFFF00);
}
imagejpeg($report, 'image/report.jpg');
imagedestroy($report);

exit();

7行目:
リージョンは料金の安い「オハイオ(us-east-2)」になっていますが、ややレスポンスが遅く感じます。気になる場合は少々高いですが「東京(ap-northeast-1)」にしてみるとよいかと思います。

ちなみに料金ですが、AWSの作りたてのアカウントなら、APIの使用が、最初の12ヶ月間(5,000回/月まで)は無料です。無料枠を過ぎている場合でも、そこそこリーズナブルで、DetectFacesのみの使用なら、オハイオの場合は1,000回APIを呼ぶごとに1.00USDです。東京は1.30USDのようです。

10、11行目:
ここには取得した「アクセスキーID」と「シークレットアクセスキー」を入力してください。

29行目:
返り値は「$result」にJSONで受け取りますが、この記述だと基本的なパラメーターのみを受け取ることになります。

	$result = $rekognition->DetectFaces([
		'Image' => [
			'Bytes' => file_get_contents($target_img),
		],
		'Attributes' => ['ALL']
	]);

このように「‘Attributes’ => [‘ALL’]」を追加すると、感情を含めた全てのパラメーターを受け取ることができます。顔を識別するだけなら不要です。いろいろパラメーターが帰ってきて面白いので、一度試してみてください。

パラメーターを参照する場合は「var_dump」で出力してみてください。

var_dump($result);

こんな感じで画像が出力されたら成功です。

条件にもよるのですが、OpenCVの場合だと背景の森のような部分に心霊写真的な「顔」が検出されてしまうことも時々あります。ですが、Rekognitionの場合はそういうこともなく、きちんと正確に検出されます!さすがAWSのサービスだけのことはあります。

なお、上記コードは、下記の記事を参考にさせていただきました。

Qiita – Amazon Rekognitionを使って顔分析してみた
https://qiita.com/erichama427/items/8ed77b9c2cfee8d6e7c4

4. 顔分析後、顔の切り取り画像を保存してみる

さて今度は、顔を検出した後に顔の部分のみ切り取って別の画像として保存するようにコードを少し改変してみたいと思います。今回は扱いませんが「CompareFaces」というAPIで同一人物かどうかの判定ができるので、そちらに渡したい時などに使えます。

下記のコードを最初のコードの43行目以降と置き換えればOKです。

// 出力座標計算
foreach ($result["FaceDetails"] as $face_details) {
	$p1x = intval($face_details["BoundingBox"]["Left"] * $img_w);
	$p1y = intval($face_details["BoundingBox"]["Top"] * $img_h);
	$p2x = intval($face_details["BoundingBox"]["Width"] * $img_w);
	$p2y = intval($face_details["BoundingBox"]["Height"] * $img_h);
	array_push($positions, array($p1x, $p1y, $p2x, $p2y));
}

// 判定画像出力
$report = imagecreatefromjpeg($target_img);
$i = 0;
foreach ($positions as $position) {
	$crop = imagecrop($report, ['x' => $position[0], 'y' => $position[1], 'width' => $position[2], 'height' => $position[3]]);
	imagejpeg($crop, 'image/face_'.sprintf('%02d', $i).'.jpg');
	imagedestroy($crop);
	$i++;
}
imagedestroy($report);

exit();

ちなみに一点注意点があって、今回画像を切り取るGDのimagecrop関数は先程のimagerectangle関数と渡すべきパラメーターが異なっている点です。先程は「左上 x、左上 y、右下 x、右下 y」で座標を渡していましたが、こちらは「左上 x、左上 y、幅 w、高さ h」で渡します。

こんな感じで画像が出力されていたら成功です!

5. まとめ

今回はPHPでAmazon Rekognitionの顔比較 (CompareFaces)を実行してみました。やってみた印象としては、OpenCVよりも手軽に正確な分析ができるだけでなく、様々な顔の特徴や感情のパラメーターも取得できてしまいます!OpenCVは自前で分類器(学習データ)を用意しさえすれば、応用範囲が広いのでそれはそれで用途がたくさんあるかと思いますが、今時のディープラーニングを応用したサービスの精度の高さにはただただ驚くばかりです。フォトサービス系のウェブサービスなど様々なプロジェクトに使えそうですね。