FaMirror Project

報告的なこと、技術的なこと

Webカメラの映像をface++に送信する【JavaScript】

概要

前回の記事で、Webカメラの映像の画像を取得する方法を書きました。
famirror.hateblo.jp

今度は、顔認識などの機能を持つ無料API「face++」にWebカメラの映像を送信します。

Webカメラの映像をバイナリ化して、「face++」にajax(非同期通信)でPOST送信します。

API解説

face++は中国のWebサービスで、顔認証だけでなく、顔の判別や検索など、様々な機能を持つ無料APIです。
www.faceplusplus.com

「face++」の基本的な使い方に関しては以前の記事をご覧ください。
famirror.hateblo.jp

前回同様、顔認識機能「/detection/detect」を試してみます。

Webカメラの映像を取得する

Webカメラの映像を「video」領域に流し、ボタンが押された時にそれを「canvas」にコピーします。

詳しい解説は前回の記事をご覧ください。
famirror.hateblo.jp

以下のソースで「submit」ボタンを押すと「canvas」領域にWebカメラの映像がコピーされます。

HTML(index.html)

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<link rel="stylesheet" href="style.css">
	<title>Webカメラの映像をface++に送信</title>
</head>
<body>
	<h2>Video</h2>
	<video id="camera" autoplay></video>
	<button id="submit">submit</button>
	<h2>Canvas</h2>
	<canvas id="canvas"></canvas>
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript" src="./script.js"></script>
</body>
</html>

CSS(style.css)

@charset "UTF-8";

#camera {
	width: 400px;
	height: 300px;
}

JavaScript(script.js)

$(function() {
	//videoタグを取得
	var video = document.getElementById('camera');
	//カメラが起動できたかのフラグ
	var localMediaStream = null;
	//カメラ使えるかチェック
	var hasGetUserMedia = function() {
		return (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
	};

	//エラー
	var onFailSoHard = function(e) {
		console.log('エラー!', e);
	};

	if(!hasGetUserMedia()) {
		alert("未対応ブラウザです。");
	} else {
		window.URL = window.URL || window.webkitURL;
		navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
		navigator.getUserMedia({video: true}, function(stream) {
			video.src = window.URL.createObjectURL(stream);
			localMediaStream = stream;
		}, onFailSoHard);
	}

	$("#submit").click(function() {
		if (localMediaStream) {
			var canvas = document.getElementById('canvas');
			//canvasの描画モードを2sに
			var ctx = canvas.getContext('2d');
			var img = document.getElementById('img');

			//videoの縦幅横幅を取得
			var w = video.offsetWidth;
			var h = video.offsetHeight;

			//同じサイズをcanvasに指定
			canvas.setAttribute("width", w);
			canvas.setAttribute("height", h);

			//canvasにコピー
			ctx.drawImage(video, 0, 0, w, h);
		}
	});
});

canvasを以下のように非表示にしても問題ありません。

CSS(style.css)追加

#canvas {
	display: none;
}

画像をバイナリ化

このままの状態では送信できたいので、画像データをバイナリ化します。

JavaScriptの44行目「ctx.drawImage(video, 0, 0, w, h);」の後に以下のコードを追加してください。

JavaScprit(script.js)追加

//ここから画像のバイナリ化
var can = canvas.toDataURL();
// Data URLからBase64のデータ部分のみを取得
var base64Data = can.split(',')[1];
// base64形式の文字列をデコード
var data = window.atob(base64Data); 
var buff = new ArrayBuffer(data.length);
var arr = new Uint8Array(buff);

// blobの生成
for(var i = 0, dataLen = data.length; i < dataLen; i++){
	arr[i] = data.charCodeAt(i);
}
var blob = new Blob([arr], {type: 'image/png'});

これで画像のバイナリデータがblobに入りました。

face++に送信する

続いてそのデータを送信します。

今回はajaxを使って非同期通信でPOST送信を行います。

先ほど追加したソースに、さらに以下のソースを続けてください。

JavaScript(script.js)追加

//ここから画像データ送信
//urlを設定
var api_key = 'b81fd92a7779b24eddf6b556ccb9baa9';
var api_secret = 'Pq9T3A_pboK4ANRSAnK7ea9XQZdTbVpH';
var url = 'https://apicn.faceplusplus.com/detection/detect' + '?api_key=' + api_key + '&api_secret=' + api_secret;

//データをセット
var formData = new FormData();
formData.append('img', blob);

//非同期通信開始
$.ajax({
	url: url,
	type: 'POST',
	data: formData,
	contentType: false,
	processData: false,
	success: function(data, dataType) {
		console.log(data);
	},
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		console.log('Error : ' + errorThrown);
	}
});

<API Key>と<API Secret>はご自身のものをお使いください。

コンソールを確認すると、情報が得られているのがわかると思います。

結果を表示する

ついでに結果を表示しましょう。

表形式で一部の情報だけ表示します。

HTMLの「canvas」タグの下に以下のソースを追加します。

HTML(index.html)追加

<h2>Result</h2>
<div id="result"></div>

JavaScriptの方は、resultという関数を作成し、ajaxの成功時に呼び出します。

先ほど「console.log(data)」となっていたところを以下のように変更してください。
JavaScript(script.js)変更

result(data);

また、以下の関数を宣言してください。

JavaScript(script.js)追加

var result = function(data) {
	var i, face;
	$('#result').html('');

	for(i = 0; i < data['face'].length; i++) {
		face = data['face'][i]['attribute'];
		$('#result').append('<h3>' + (i + 1) + '人目</h3>');
		$('#result').append('<table><tr><th>名前</th><th>データ</th></tr>');
		$('#result').append('<tr><td>年齢</td><td>' + face['age']['value'] + '±' + face['age']['range'] + '歳</td></tr>');
		$('#result').append('<tr><td>性別</td><td>' + face['gender']['value'] + '(' + face['gender']['confidence'] + '%)' + '</td></tr>');
		$('#result').append('<tr><td>人種</td><td>' + face['race']['value'] + '(' + face['race']['confidence'] + '%)' + '</td></tr>');
		$('#result').append('<tr><td>笑顔度</td><td>' + face['smiling']['value'] + '%</td></tr></table>');
	}

	if(i == 0)
		$('#result').html('顔が検出されませんでした。');
}

ボタンを押してしばらくすると表が表示されるようになったと思います。

ちなみに、私の結果はこんな感じでした。
f:id:famirror:20151215173650p:plain

実年齢よりちょっと若目に出ていますね。

コード

HTML(index.html)

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<link rel="stylesheet" href="style.css">
	<title>Webカメラの映像をface++に送信</title>
</head>
<body>
	<h2>Video</h2>
	<video id="camera" autoplay></video>
	<button id="submit">submit</button>
	<h2>Canvas</h2>
	<canvas id="canvas"></canvas>
	<h2>Result</h2>
	<div id="result"></div>
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript" src="./script.js"></script>
</body>
</html>

CSS(style.css)

@charset "UTF-8";

#camera {
	width: 400px;
	height: 300px;
}

JavaScript(script.js)

$(function() {
	//videoタグを取得
	var video = document.getElementById('camera');
	//カメラが起動できたかのフラグ
	var localMediaStream = null;
	//カメラ使えるかチェック
	var hasGetUserMedia = function() {
		return (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
	};

	//エラー
	var onFailSoHard = function(e) {
		console.log('エラー!', e);
	};

	var result = function(data) {
		var i, face;
		$('#result').html('');

		for(i = 0; i < data['face'].length; i++) {
			face = data['face'][i]['attribute'];
			$('#result').append('<h3>' + (i + 1) + '人目</h3>');
			$('#result').append('<table><tr><th>名前</th><th>データ</th></tr>');
			$('#result').append('<tr><td>年齢</td><td>' + face['age']['value'] + '±' + face['age']['range'] + '歳</td></tr>');
			$('#result').append('<tr><td>性別</td><td>' + face['gender']['value'] + '(' + face['gender']['confidence'] + '%)' + '</td></tr>');
			$('#result').append('<tr><td>人種</td><td>' + face['race']['value'] + '(' + face['race']['confidence'] + '%)' + '</td></tr>');
			$('#result').append('<tr><td>笑顔度</td><td>' + face['smiling']['value'] + '%</td></tr></table>');
		}

		if(i == 0)
			$('#result').html('顔が検出されませんでした。');
	}

	if(!hasGetUserMedia()) {
		alert("未対応ブラウザです。");
	} else {
		window.URL = window.URL || window.webkitURL;
		navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
		navigator.getUserMedia({video: true}, function(stream) {
			video.src = window.URL.createObjectURL(stream);
			localMediaStream = stream;
		}, onFailSoHard);
	}

	$("#submit").click(function() {
		if (localMediaStream) {
			var canvas = document.getElementById('canvas');
			//canvasの描画モードを2sに
			var ctx = canvas.getContext('2d');
			var img = document.getElementById('img');

			//videoの縦幅横幅を取得
			var w = video.offsetWidth;
			var h = video.offsetHeight;

			//同じサイズをcanvasに指定
			canvas.setAttribute("width", w);
			canvas.setAttribute("height", h);

			//canvasにコピー
			ctx.drawImage(video, 0, 0, w, h);

			//ここから画像のバイナリ化
			var can = canvas.toDataURL();
			// Data URLからBase64のデータ部分のみを取得
			var base64Data = can.split(',')[1];
			// base64形式の文字列をデコード
			var data = window.atob(base64Data); 
			var buff = new ArrayBuffer(data.length);
			var arr = new Uint8Array(buff);

			// blobの生成
			for(var i = 0, dataLen = data.length; i < dataLen; i++){
				arr[i] = data.charCodeAt(i);
			}
			var blob = new Blob([arr], {type: 'image/png'});

			//ここから画像データ送信
			//urlを設定
			var api_key = '<API KEY>';
			var api_secret = '<API SECRET>';
			var url = 'https://apicn.faceplusplus.com/detection/detect' + '?api_key=' + api_key + '&api_secret=' + api_secret;

			//データをセット
			var formData = new FormData();
			formData.append('img', blob);

			//非同期通信開始
			$.ajax({
				url: url,
				type: 'POST',
				data: formData,
				contentType: false,
				processData: false,
				success: function(data, dataType) {
					result(data);
				},
				error: function(XMLHttpRequest, textStatus, errorThrown) {
					console.log('Error : ' + errorThrown);
				}
			});
		}
	});
});