Home > 梅原 > Marilenaを使って顔検知してみる

Marilenaを使って顔検知してみる

20100422
Category:梅原 /Tags:

AS3で顔検知のできるMarilenaというライブラリを使ってみた。
*要WebCam

OpenCVっていうC/C++用のライブラリがあって、画像処理まわりの便利関数がたくさんある。その中の特に顔検知に必要な物体検出(Object Detection)まわりの処理をAS3に移植したのが、今回使ったMarilena。移植したのはwonderfl作った人だ。凄いもんだ。

Get Adobe Flash player


ここでは、ウェブカムから取得した顔に、絵柄を乗っけるようにしてみた。やはり1枚あたりの処理時間がかかるので、スムーズな動画生成は厳しい。
ただ、1枚の画像の加工だったら演出によってはなんとかなるかもね。例えば「写真を読み込み/WebCamで撮影→ジャカジャカジャカ、ジャン!→はいできました~」みたいなのとか。
なんにしても、活用できたら楽しそう。

▼ActionScript AS3(FP9)

/*
 * Marilenaを使って顔検知してみる。
 * http://www.libspark.org/wiki/mash/Marilena
 *
 * WebCamから画像を取得して、MarilenaのObjectDetectorに
 * 投げているだけ。
 *
 * */

package
{
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.display.Sprite;
	import flash.display.Graphics;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.geom.Rectangle;

	public class Main extends Sprite {
		private var _faceDetect:FaceDetect;
		private var _faceRectContainer:Sprite;
		private var _bitmap:Bitmap;
		private var _snapShot:SnapShot;

		public function Main() {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;

			_bitmap = new Bitmap(new BitmapData(320, 240));
			this.addChild(_bitmap);

			_faceRectContainer = new Sprite();
			this.addChild(_faceRectContainer);

			_snapShot = new SnapShot();
			_snapShot.onStart = onStart;
			_snapShot.y = 240;
		}
		private function onStart():void {
			_faceDetect = new FaceDetect();
			_faceDetect.setBitmap(_snapShot.getBitmap());
			_faceDetect.onComplete = onComplete;
		}

		private function onComplete(rects:*):void {
			_bitmap.bitmapData.draw(_faceDetect.getBitmap());
			if( rects ){
				var g:Graphics = _faceRectContainer.graphics;
				g.clear();

				rects.forEach(function(r:Rectangle, idx:int, arr:Array):void {

					g.beginFill(0xFF6666, 0.8);
					g.drawEllipse(r.x - r.width * 0.15, r.y - r.height * 0.28, r.width * 1.3, r.height * 1.3);
					g.drawEllipse(r.x, r.y, r.width, r.height);

					g.beginFill(0,0);
					g.lineStyle(1, 0xFF0000);
					g.drawCircle(r.x + r.width / 3.6, r.y + r.height / 3, r.width/7);
					g.drawCircle(r.x + r.width - r.width / 3.6, r.y + r.height / 3, r.width / 7);
					g.endFill();

					g.lineStyle(1, 0x000000);
					g.moveTo(r.x + r.width / 3.6, r.y + r.height / 1.4);
					g.lineTo(r.x - r.width / 20, r.y + r.height / 1.5);
					g.moveTo(r.x + r.width / 3.6, r.y + r.height / 1.3);
					g.lineTo(r.x - r.width / 10, r.y + r.height / 1.32);
					g.moveTo(r.x + r.width / 3.6,r.y + r.height / 1.25);
					g.lineTo(r.x, r.y + r.height / 1.1);

					g.moveTo(r.x + r.width - r.width / 3.6, r.y + r.height / 1.4);
					g.lineTo(r.x + r.width + r.width / 20, r.y + r.height / 1.5);
					g.moveTo(r.x + r.width - r.width / 3.6, r.y + r.height / 1.3);
					g.lineTo(r.x + r.width + r.width / 10, r.y + r.height / 1.32);
					g.moveTo(r.x + r.width - r.width / 3.6, r.y + r.height / 1.2);
					g.lineTo(r.x + r.width, r.y + r.height / 1.1);
					g.endFill();

					g.lineStyle(0,0,0);
					g.beginFill(0xFF0000, 1);
					g.drawCircle(r.x + r.width / 2, r.y + r.height / 1.8, r.width / 12);
					g.endFill();
				});
			}
			_faceDetect.setBitmap(_snapShot.getBitmap());
		}
	}
}

//webカムからbitmapを取得するクラス
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.ActivityEvent;
import flash.media.Camera;
import flash.media.Video;
class SnapShot extends Sprite {
	private var _video:Video;
	private var _camera:Camera;
	public var onStart:Function = function():void { };
	public function SnapShot() {
		_camera = Camera.getCamera();
		_camera.setMode(320, 240, 10);

		if (_camera != null) {
			_video = new Video(320, 240);
			_video.attachCamera(_camera);
			this.addChild(_video);
		} else {
			trace("You need a camera.");
		}
		_camera.addEventListener(ActivityEvent.ACTIVITY, _onActivity);
	}

	private var _isStart:Boolean;
	//カメラから画像が取得できたら、一度だけ動く
	private function _onActivity(event:ActivityEvent):void {
		_camera.removeEventListener(ActivityEvent.ACTIVITY, _onActivity);
		if (!_isStart) {
			_isStart = true;
			onStart();
		}
	}

	//カメラの画像をBitmapとして取り出す。
	public function getBitmap():Bitmap {
		var bitmap:Bitmap = new Bitmap(new BitmapData(_video.width, _video.height));
		bitmap.bitmapData.draw(_video);
		return bitmap;
	}
}

//Bitmapを投げると、顔の範囲をあれば返すクラス。
import flash.display.Bitmap;
import jp.maaash.ObjectDetection.ObjectDetector;
import jp.maaash.ObjectDetection.ObjectDetectorOptions;
import jp.maaash.ObjectDetection.ObjectDetectorEvent;
class FaceDetect {
	private var _detector:ObjectDetector;
	public var onComplete:Function = function(rects:*):void { };
	private var _bitmap:Bitmap;
	public function FaceDetect() {
		_detector = new ObjectDetector();
		_detector.options = getDetectorOptions();
		_detector.addEventListener(ObjectDetectorEvent.DETECTION_COMPLETE, DETECTION_COMPLETE);
	};
	private function DETECTION_COMPLETE(event:ObjectDetectorEvent):void {
		onComplete(event.rects);
	}
	public function setBitmap(bitmap:Bitmap):void {
		_detector.loadHaarCascades("face.zip");
		//アップされているswfではblogに乗せるように↓にしている。
		//_detector.loadHaarCascades("http://www.mztm.jp/wp/wp-content/uploads/2010/04/face.zip");
		_detector.detect(bitmap);
		_bitmap = bitmap;
	}
	public function getBitmap():Bitmap {
		return _bitmap;
	}
	private function getDetectorOptions() :ObjectDetectorOptions {
		var options:ObjectDetectorOptions = new ObjectDetectorOptions();
		options.min_size  = 50;
		options.startx    = ObjectDetectorOptions.INVALID_POS;
		options.starty    = ObjectDetectorOptions.INVALID_POS;
		options.endx      = ObjectDetectorOptions.INVALID_POS;
		options.endy      = ObjectDetectorOptions.INVALID_POS;
		return options;
	}
}

関連記事:

Comments are closed.