Forked from: xlune's 画像のアウトラインを一筆書き diff:171 forked from: 画像のアウトラインを一筆書きじゃない xlune forked:1favorite:4lines:188license : All rights reserved modified : 2009-04-04 00:02:53 Embed Tweet // forked from xlune's 画像のアウトラインを一筆書き package { import __AS3__.vec.Vector; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.CapsStyle; import flash.display.Graphics; import flash.display.JointStyle; import flash.display.LineScaleMode; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.geom.Matrix; import flash.geom.Point; import flash.net.URLRequest; import flash.system.LoaderContext; [SWF(width=465, height=465, frameRate=15, backgroundColor=0xFFFFFF)] public class main extends Sprite { //画面幅 private var _width:uint = 465; //画面高さ private var _height:uint = 465; //精度 private var _prec:uint = 1; //描画スピード private var _speed:uint = 3; //閾値 private var _threshold:uint = 0xCC; //ガイド画像 private var _imgUrl:String = 'http://farm4.static.flickr.com/3366/3409173374_d1a4af8142.jpg'; private var _img:Loader; private var _guide:BitmapData; private var _canvas:Sprite; private var _gp:Graphics; private var _pointMap:Vector.<Vector.<Boolean>>; private var _pointGroups:Vector.<Vector.<Point>>; private var _drowGroup:Vector.<Point>; private var _basePoint:Point; private var _closePoint:Point; /** * コンストラクタ */ public function main() { var request:URLRequest = new URLRequest(_imgUrl); var context:LoaderContext = new LoaderContext(true); _img = new Loader(); _img.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler); _guide = new BitmapData(_width, _height, false, 0x00FFFFFF); _canvas = new Sprite(); _gp = _canvas.graphics; _gp.lineStyle(1, 0xFF0000, 1, true, LineScaleMode.NONE, CapsStyle.ROUND, JointStyle.MITER, 2); try { _img.load(request, context); } catch (error:Error) { trace("image load failed."); } } /** * Event Complete Handler */ private function completeHandler(event:Event):void { _img.x = _width / 2 - _img.width / 2; _img.y = _height / 2 - _img.height / 2; _img.alpha = 0.1; var gMatrix:Matrix = new Matrix(); gMatrix.tx = _img.x; gMatrix.ty = _img.y; _guide.draw(_img, gMatrix); makePoints(); addChild(_img); addChild(_canvas); this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); } /** * Event EnterFrame Handler */ private function enterFrameHandler(event:Event):void { if(_pointGroups.length > 0 || _drowGroup.length > 0) { var drowPoint:Point; if(!_drowGroup || _drowGroup.length == 0) { _basePoint = new Point(0, 0); _drowGroup = Vector.<Point>(_pointGroups.shift()); _drowGroup.sort(drowPointSort); drowPoint = Point(_drowGroup.shift()); if(_closePoint) { _gp.lineTo(_closePoint.x, _closePoint.y); } _gp.moveTo(drowPoint.x, drowPoint.y); _closePoint = _basePoint = drowPoint; } else { _drowGroup.sort(drowPointSort); drowPoint = Point(_drowGroup.shift()); if(Point.distance(_basePoint, drowPoint) > Math.sqrt(_prec*_prec*2)) { if(_closePoint) { _gp.lineTo(_closePoint.x, _closePoint.y); } _gp.moveTo(drowPoint.x, drowPoint.y); _closePoint = drowPoint; } else { _gp.lineTo(drowPoint.x, drowPoint.y); } _basePoint = drowPoint; } } else { _img.visible = false; this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler); } } /** * 境界点ソート */ private function drowPointSort(a:Point, b:Point):int { var numA:Number = Point.distance(_basePoint, a); var numB:Number = Point.distance(_basePoint, b); if(numA > numB) { return 1; } else if(numA < numB) { return -1; } return 0; } /** * 境界点生成 */ private function makePoints():void { var groupNum:uint = 0; _pointMap = new Vector.<Vector.<Boolean>>(uint(_height/_prec)); _pointGroups = new Vector.<Vector.<Point>>(); for(var i:uint=0,iMax:uint=_pointMap.length; i<iMax; i++) { _pointMap[i] = new Vector.<Boolean>(uint(_width/_prec)); } for(i=0,iMax=_pointMap.length; i<iMax; i++) { for(var j:uint=0,jMax:uint=_pointMap[i].length; j<jMax; j++) { if(_pointMap[i][j] != true && isFillPoint(j * _prec, i * _prec)) { _pointGroups[groupNum] = new Vector.<Point>(); groupAgent(j, i, groupNum++); } } } } /** * 境界点をグループ化 */ private function groupAgent(xNum:int, yNum:int, groupNum:uint):void { if(0 <= xNum && xNum < uint(_width/_prec) && 0 <= yNum && yNum < uint(_height/_prec)) { if(_pointMap[yNum][xNum] != true) { _pointMap[yNum][xNum] = true; if(isFillPoint(xNum * _prec, yNum * _prec)){ if(isUniquePoint(xNum * _prec, yNum * _prec)) { _pointGroups[groupNum].push(new Point(xNum * _prec, yNum * _prec)); } groupAgent(xNum, yNum-1, groupNum); groupAgent(xNum+1, yNum, groupNum); groupAgent(xNum, yNum+1, groupNum); groupAgent(xNum-1, yNum, groupNum); } } } } /** * 境界点を抽出 */ private function isUniquePoint(posX:int, posY:int):Boolean { if(isFillPoint(posX, posY)) { if(!isFillPoint(posX, posY-_prec) || !isFillPoint(posX+_prec, posY) || !isFillPoint(posX, posY+_prec) || !isFillPoint(posX-_prec, posY)) { return true; } } return false; } /** * 2値化 */ private function isFillPoint(posX:int, posY:int):Boolean { if(posX < 0 || posX > _width) return false; if(posY < 0 || posY > _height) return false; var color:uint = _guide.getPixel(posX, posY); color = (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff)) / 3; if(color < _threshold) return true; return false; } } } Code Fullscreen Preview Fullscreen mashu hacker_fimwf.. ibu4gin assen_nissen.. Bitmap line outline 一筆書きじゃない 重い Point.distance LoaderContext sort Point Boolean visible Error graphics Event.COMPLETE shift alpha removeEventListener URLRequest height width addChild Math.sqrt trace addEventListener uint sort new page view favorite forked pv326 forked from: forked from: 画像のア.. doodoo forked:0 favorite:0lines:188 (diff:3)