輪郭をズームインするエフェクト

卒業研究として、エフェクト作成をしているため、
自分が作成したエフェクトを紹介します。


今回は、輪郭を大きくしていくエフェクト。
輪郭の取得は、
ただ単に、
オブジェクトの色をピクセルごとにとり、
その上下左右のピクセルに透明色があれば、
それは輪郭と判断するというアルゴリズムにしています。


これでは、画像の真ん中とかに透明色を使ってしまうとだめという制約ができてしまいますが、
透明色を使わなければ、成り立つので現状はこれで行きたいと思います。





実行結果は、上のような感じになります。


ソースは以下です。

package {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	[SWF(width=800, height=600, backgroundColor=0xAADDFF)]

	public class Main03 extends Sprite {
		
		[Embed(source="images/test.gif")] private var P1:Class;
		private var image:Bitmap = new P1();
		
		private var circle:Sprite = new Sprite();		// 円の画像用
		
		public function Main03() {
			createCircle();
			createImage();
		}
		
		private function createCircle():void {
			const g:Graphics = circle.graphics;
			g.lineStyle(10, 0xFFFF00);
			g.beginFill(0xFF0000);
			g.drawCircle(0, 0, 50);
			g.endFill();
			
			circle.x = 500;
			circle.y = 300;
			addChild(circle);
			circle.addEventListener(MouseEvent.CLICK, onClick);
		}
		
		private function createImage():void {
			var sp:Sprite = new Sprite();
			sp.x = 200;
			sp.y = 300;
			addChild(sp);
			
			image.x = -image.width/2;
			image.y = -image.height/2;
			sp.addChild(image);
			
			sp.addEventListener(MouseEvent.CLICK, onClick);
		}
		
		private function isOutLine(xx:int, yy:int, bmp:BitmapData):Boolean {
			// 自身が透明なら輪郭にはならない
			if (bmp.getPixel32(xx, yy)>>24 == 0) {
				return false;
			}
			
			// 周りのピクセルのどこか1か所が透明だった場合輪郭と判断する
			if (bmp.getPixel32(xx+1, yy)>>24 == 0) {
				return true;
			}
			if (bmp.getPixel32(xx-1, yy)>>24 == 0) {
				return true;
			}
			if (bmp.getPixel32(xx, yy+1)>>24 == 0) {
				return true;
			}
			if (bmp.getPixel32(xx, yy-1)>>24 == 0) {
				return true;
			}
			
			// 上記の条件に当てはまらない場合は輪郭ではない
			return false;
		}
		
		private function createEffect(obj:DisplayObject):void {
			var rect:Rectangle = obj.getBounds(null);
			var tempBmp:BitmapData = new BitmapData(rect.width, rect.height, true, 0x00FFFFFF);
			var mat:Matrix = new Matrix();
			mat.translate(-rect.left, -rect.top);
			tempBmp.draw(obj, mat);
			tempBmp.threshold(tempBmp, tempBmp.rect, new Point(), "!=", 0xFF000000, 0x00FFFFFF, 0xFF000000);
			
			
			var bmp:BitmapData = new BitmapData(tempBmp.width, tempBmp.height, true, 0x00FFFFFF);
			for (var xx:int=0; xx<bmp.width; xx++) {
				for (var yy:int=0; yy<bmp.height; yy++) {
					if (isOutLine(xx, yy, tempBmp)) {
						bmp.setPixel32(xx, yy, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx-1, yy-1, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx+1, yy+1, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx-1, yy+1, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx+1, yy-1, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx-1, yy, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx, yy-1, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx+1, yy, tempBmp.getPixel32(xx, yy));
						bmp.setPixel32(xx, yy+1, tempBmp.getPixel32(xx, yy));
					}
				}
			}
			
			var outLine:OutLine = new OutLine(bmp.clone());
			outLine.x = obj.x + rect.left + rect.width/2;
			outLine.y = obj.y + rect.top + rect.height/2;
			addChildAt(outLine, 0);
		}
				
		private function onClick(event:MouseEvent):void {
			createEffect(event.currentTarget as DisplayObject);
		}
		
	}
}


import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.display.PixelSnapping;
import flash.filters.BlurFilter;

class OutLine extends Sprite {

	public function OutLine(bmp:BitmapData) {
		var image:Bitmap = new Bitmap(bmp, PixelSnapping.AUTO, true);
		image.x = -image.width/2;
		image.y = -image.height/2;
		addChild(image);
		
		var bf:BlurFilter = new BlurFilter(5, 5, 3);
		filters = [bf];
		
		addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}
		
	private function onEnterFrame(event:Event):void {
		scaleX += 0.1;
		scaleY += 0.1;
		
		if (scaleX > 3 || scaleY > 3) {
			removeEventListener(Event.ENTER_FRAME, onEnterFrame);
			parent.removeChild(this);
		}
	}
}