wataメモ

日々のメモをつらつらと書くだけ

[3][HTML][canvas]canvasで画像解析

 「canvasタグとそのAPIを使って、画像のピクセルデータが取得できる」というのを知って、「それならばユーザが投稿した画像を解析してどうこうすることもJavaScriptで可能か」と思い試してみた。

 やり方としては「画像ファイルをアップロード>imgタグとして表示>canvasに取り込み>画像解析」の流れでやってみた。

index.htmlの中身の抜粋。jquery.uploadを使って非同期にアップロード出来るようにしてみた。サーバサイドはCGI.pmを使用。

<script type="text/javascript" src="js/jquery.upload-1.0.2.min.js"></script>
<input type="file" name="filename" id="file"> // jquery.uploadがiframe作ってアップロードしてくれるのでformタグ無し

upload.cgiの中身。セキュリティはあまり考えていない。

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use File::Copy;
use File::Basename;

my $upload_dir  = 'upload';

my $q  = CGI->new();
my $fh = $q->upload('filename');
my $temp_path = $q->tmpFileName($fh);
fileparse_set_fstype('MSDOS');
my $filename = basename($fh);
my $upload_path = "$upload_dir/$filename";

move ($temp_path, $upload_path) or die $!;
close($fh);

print $q->header( -type=>'text/plain', -charset=>'UTF-8', );
print <<"END_OF_HTML";
$upload_dir/$filename
END_OF_HTML

exit;

__END__

 JavaScriptでonchangeイベントにアップロードを仕込んでおく。

$(document).on('change', '#file', function() {
	$(this).upload('upload.cgi', function(res) {
		// canvasタグを取得
		var c = document.getElementById('gazo');
		var ctx = c.getContext('2d');

		// resに画像パスが返ってくるので
		// 読み込んでonloadでcanvasに取り込む
		var img = new Image();
		img.src = path; // 投稿された画像へのパス
		img.onload = function() {
			// 画像サイズに合わせてcanvasのサイズ変更
			c.width = img.width;
			c.height = img.height;
			ctx.drawImage(img, 0, 0); // 画像読み込み
		}
	}, 'text');
});
 canvasに画像データが入れば後はcontextから画像情報を取得することが出来る。
var ctx = canvas.getContext('2d');
var id = ctx.getImageData(0, 0, w, h);
ここで取得出来るImageDataは配列で1次元配列が帰って来る。配列の要素が1ピクセル分を表しているのかと思いきや、4つの要素を使ってRGBとアルファ値(それぞれは0~255の値を取りうる)を表しているらしい。分かりづらいので図で書いてみると以下の様な感じ。上の0~が配列の添字で、画像の左から右、上から下の順番で入っている。

f:id:wata_htn:20120113165058p:plain

ここまで来れば画像情報が取れているので、後は煮くなり焼くなりすればいい。アップロードされた画像の顔認識をして、自動的にサムネイルの位置を決めてトリミングとか出来るだろう。
今回jquery.uploadとかCGI.pmとかcanvasとか触ったけど、これを1個と考えるのはどうなのかと一瞬考えがよぎった。