Javascriptで画像の顔認識をする方法【Face Detection】

この記事のイメージ

画像の中に顔はあるのか、また、画像の中のどの部分が顔なのか。いわゆる「顔認識」のアルゴリズムは様々ですが、その技術を利用するのにお金がかかるというケースも少なくありません。今回は無料で、しかもJavascript(jQuery)だけで顔認識を行なうライブラリ、Face Detectionの使い方を解説します。

サンプルデモ

今回紹介する、Face Detectionの動作デモです。下記の通り、写真の中の人間の顔を認識し、どこからどこまでがその範囲かを座標で取得することが可能です。今回、ハートをプルプルさせるブログメディア、prasmを運営するシンタロヲフレッシュさん(@shintarowfresh)にご協力いただき、写真をサンプルとして利用させていただきました。

サンプルの顔写真

ライブラリの入手

ライブラリはGitHub上で公開されています。まずは、ファイルをダウンロードして下さい。

ダウンロードしたファイル、jquery.facedetection-master.zipを解凍すると、様々なファイルがフォルダの中に入っています。ですが、必要なファイルは下記のjquery.facedetection.min.jsだけです。

ファイル構成

jquery.facedetection-master
dist
jquery.facedetection.min.js

使い方

Face Detectionを使って、顔認識を試してみましょう。あらかじめ、人間の顔が映った写真画像を用意しておいて下さいね。まずはHTML上のヘッダー部分で、jQueryとFace Detectを読み込みます。

HTML

<!-- jQueryライブラリの読み込み -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- ライブラリの読み込み -->
<script src="./jquery.facedetection.min.js"></script>

続いて、ボディ部分に、対象となる写真画像を読み込むimg要素を追加して下さい。後々、jQueryで操作するためのid属性値を付けておきます。また、img要素に、スタイルシートのpositionを利用して顔範囲を示す枠線を重ねるので、facial-image-wrapperというクラス属性値を付けたラッパーで囲んでおきます。なお、画像は自身のサーバー内にあるものしか利用できません。http経由で外部サーバーの画像を読み込んでも、プログラムは動作しない点にご注意下さい。

HTML

<figure class="facial-image-wrapper">
	<img src="./sample.jpg" id="facial-image"/>
</figure>

顔範囲を枠線で囲む要素(Javascriptで動的に生成)にはfacial-image-borderというクラス属性値を付けるようにしましょう。画像を囲むラッパー要素には、positionの基準となるよう、position:relativeを加えておきます。

CSS

.facial-image-wrapper{
	position:relative;
	margin:0 auto
}

.facial-image-border{
	position:absolute;
	border:2px solid #FFF;
}

当然ですが、このプログラムは、画像の読み込みが完了した以降に動作させないとエラーが発生してしまいます。画像を読み込むまではプログラムを実行しないよう、条件を付けておきます。

Javascript

$(function(){

	//ID要素が[facial-image]の画像を読み込んだ後にプログラムを実行する
	var img = new Image();
	img.src = $("#facial-image").attr("src");
	img.onload = function() {

		//処理の記述

	}

}

プログラムは、対象のエレメントに対してfaceDetection()というメソッドを実行します。成功すると、画像の中に映っている人数分のデータを配列で取得できるので、ループ処理でそれらのデータを処理します。画像に含まれる顔データの数だけ、顔範囲となる要素facial-image-borderを、追加していく形です。

Javascript

$(function(){

	//ID要素が[facial-image]の画像を読み込んだ後にプログラムを実行する
	var img = new Image();
	img.src = $("#facial-image").attr("src");
	img.onload = function() {

		//プログラムの実行
		$("#facial-image").faceDetection({

			//プログラムが完了すると[obj]に顔に関するデータが含まれている
			complete: function (obj){

				//顔を認識できなかった(objにデータがない)場合
				if(typeof(obj)=="undefined"){
					alert("顔情報を認識できませんでした…。");
					return false;

				//顔を認識できた場合
				}else{

					//人数分だけループ処理する
					for(var i=0;i<obj.length;i++){

						//ラッパー要素内に、顔範囲を示すdiv要素を追加
						$("#facial-image").after('<div class="facial-image-border"></div>');

						//顔範囲の場所を動的に指定
						$(".facial-image-border").eq(i).css({
							left:obj[i].x * obj[i].scaleX + "px",
							top:obj[i].y * obj[i].scaleY + "px",
							width:obj[i].width  * obj[i].scaleX + "px",
							height:obj[i].height * obj[i].scaleY + "px"
						});

					}

				}

			},

			//プログラムの実行に失敗した時の処理
			error:function(code,message){

				//エラーすると原因を示すテキストを取得できるのでアラート表示する
				alert("Error:" + message);

			}
		});

	}

}

例えば、画像に3人分の顔データが含まれていた場合、プログラム実行後のHTML構造は下記の通りになります。

HTML

<figure class="facial-image-wrapper">
	<img src="./sample.jpg" id="facial-image"/>
	<div class="facial-image-border"></div>
	<div class="facial-image-border"></div>
	<div class="facial-image-border"></div>
</figure>

以上のプログラムを実行すると、画像の顔の部分に、枠線が付きます。デモを見たい人は下記ページをご覧下さい。

デモを見る

取得できる値について

このプログラムが画像から抽出した顔データには、それぞれ、下記の項目が含まれています。サンプルで顔に枠線を重ねたのは、これらのデータを元に、HTMLとスタイルシートを生成して行なったものです。サンプルの値は、冒頭で紹介したシンタロヲフレッシュさんの写真のデモで取得した数値です。値はそれぞれ、画像本来のサイズに準拠したものなので、scaleX、またはscaleYをかけると、実用的な数値になります。

schema.orgのプロパティ

x
画像の中の顔範囲のX座標。顔範囲の左端が、画像の左端から何px離れているか。画像のオリジナルサイズに準拠する。
サンプル:
y
画像の中の顔範囲のY座標。顔範囲の最上部が、画像の最上部から何px離れているか。画像のオリジナルサイズに準拠する。
サンプル:
width
顔範囲の横幅。画像のオリジナルサイズに準拠する。
サンプル:
height
顔範囲の縦幅。画像のオリジナルサイズに準拠する。
サンプル:
positionX
親要素内の顔範囲の縦位置。親要素の最上部から何px離れているか?画像のオリジナルサイズに準拠する。
サンプル:
positionY
親要素内の顔範囲の横位置。親要素の左端から何px離れているか?画像のオリジナルサイズに準拠する。
サンプル:
offsetX
ドキュメント内の顔範囲の横位置。ページの左端から何px離れているか?画像のオリジナルサイズに準拠する。
サンプル:
offsetY
ドキュメント内の顔範囲の縦位置。ページの最上部から何px離れているか?画像のオリジナルサイズに準拠する。
サンプル:
scaleX
画像のオリジナルサイズの横幅と、表示されている横幅の比率。
サンプル:
scaleY
画像のオリジナルサイズの縦幅と、表示されている縦幅の比率。
サンプル:
confidence
プログラムが独自に算出した、顔認識の信頼性を示すレベル値。クオリティの調整に利用できる。
サンプル:

ダウンロード

この記事で紹介した、Face Detectionを利用するためのサンプルコードを配布します。顔認識を試したい人は、お使い下さい。全て、同ディレクトリに設置して、HTMLファイルにアクセスして下さい。なお、サンプル写真はパブリックドメイン・ライセンスのものを再配布しています。

ファイルの内容

facial-recognition.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8"/>
		<meta name="robots" content="noindex,nofollow">
		<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
		<title>顔認識をするデモ</title>
		<!-- スタイルシート -->
		<style>
.facial-image-wrapper{
   position:relative;
}

#facial-image{
	max-width:100%;
	height:auto;
}

.facial-image-border{
   position:absolute;
   border:2px solid #FFF;
}

textarea{
	width:95%;
	height:200px;
}
</style>
		<!-- jQueryライブラリの読み込み -->
		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
		<!-- ライブラリの読み込み -->
		<script src="./jquery.facedetection.min.js"></script>
		<!-- プログラムの実行 -->
		<script src="./facial-recognition.js"></script>
	</head>
<body>
<h1>顔認識をするデモ</h1>
<p>画像に含まれる顔を抽出し、位置を示すデータを取得します。写真を入れ替えて、試してみて下さい。写真はpixabayにてライセンスがパブリックドメイン(著作権放棄)で公開されているものを再配布しています。</p>
<p>(解説:<a href="http://syncer.jp/how-to-facial-recognition-by-javascript" target="_blank" rel="nofollow">Syncer</a>)</p>

<h2>プログラムの実行結果</h2>
<figure class="facial-image-wrapper">
	<img src="./sample.jpg" id="facial-image"/>
<figcaption>公開者: <a href="http://pixabay.com/en/girls-young-friends-smiling-happy-524239/" target="_blank">cherylholt</a> (pixabay)</figcaption>
</figure>

<h2>取得したデータの値</h2>
<textarea id="facial-data"></textarea>
</body>
</html>

facial-recognition.js

$(function(){

	//ID要素が[facial-image]の画像を読み込んだ後にプログラムを実行する
	var img = new Image();
	img.src = $("#facial-image").attr("src");
	img.onload = function() {

		//プログラムの実行
		$("#facial-image").faceDetection({

			//プログラムが完了すると[obj]に顔に関するデータが含まれている
			complete: function (obj){

				//顔を認識できなかった(objにデータがない)場合
				if(typeof(obj)=="undefined"){

					alert("顔情報を認識できませんでした…。");
					return false;

				//顔を認識できた場合
				}else{

					//テキストエリアに表示するためのデータ
					var object_str = "";

					//人数分だけループ処理する
					for (var i=0;i<obj.length;i++){

						//取得したデータをテキストエリアに表示していくためのデータ
						object_str += "[No: "+i+"]"+"\n";
						object_str += "x: "+obj[i].x+"\n";
						object_str += "y: "+obj[i].x+"\n";
						object_str += "width: "+obj[i].width+"\n";
						object_str += "height: "+obj[i].height+"\n";
						object_str += "positionX: "+obj[i].positionX+"\n";
						object_str += "positionY: "+obj[i].positionY+"\n";
						object_str += "offsetX: "+obj[i].offsetX+"\n";
						object_str += "offsetY: "+obj[i].offsetY+"\n";
						object_str += "scaleX: "+obj[i].scaleX+"\n";
						object_str += "scaleY: "+obj[i].scaleY+"\n";
						object_str += "confidence: "+obj[i].confidence+"\n\n";

						//ラッパー要素内に、顔範囲を示すdiv要素を追加
						$(".facial-image-wrapper").append('<div class="facial-image-border"></div>');

						//顔範囲の場所を動的に指定
						$(".facial-image-border").eq(i).css({
							left:obj[i].x * obj[i].scaleX + "px",
							top:obj[i].y * obj[i].scaleY + "px",
							width:obj[i].width  * obj[i].scaleX + "px",
							height:obj[i].height * obj[i].scaleY + "px"
						});
					}


					//取得したデータをテキストエリアに表示
					$("#facial-data").val(object_str).css("height",(object_str.split("\n").length+5)+"em");

				}
			},

			//プログラムの実行に失敗した時の処理
			error:function(code,message){
				//エラーすると原因を示すテキストを取得できるのでアラート表示する
				alert("Error:" + message);
			}
		});

	}

});

記事の更新履歴

2014-11-15
記事を公開しました。