세선화는 그림을 실선화 시키는 알고리즘이다. 가장 잘 알려진 Zhang Suen 알고리즘을 선택하였다.
코드 작성은 action script를 사용하였으며 wonderfl.net을 사용하였다.
실행하면 왼편이 원본 이미지이고 이를 세선화 한것이 오른 편에 나타나도록 하였다.
thinning on 2011-8-24 - wonderfl build flash online
kevin님이 버그를 발견해주셔서 (감사합니다 ㅎㅎ) 버그를 수정하고 코드를 약간 간략하게 수정하였다.
아래는 코드다.
/* 2011/09/01 Kyungmin Cho broneri@gmail.com thinning test : Zhang Suen algorithm -------------------------------------- 2011-09-01 - initial code. 2011-09-07 - bug fix. thanks to kevin. */ package { import flash.display.Sprite; import flash.events.Event; import flash.display.*; public class FlashTest extends Sprite { private var img_width:int = 20; private var img_height:int = 20; private var img:Array = new Array ( [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ); private var img_triangle:Array = new Array ( [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0], [0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0], [0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0], [0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0], [0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ); private var _bitmap:BitmapData= new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xff000000); private var _image:Bitmap= new Bitmap(_bitmap); private var org_img:Array; private var org_img_triangle:Array; public function FlashTest() { // write as3 code here.. addChild( _image ); org_img = make_bitmap_array( img_width, img_height ); copy_bitmap_array( img, org_img, img_width, img_height ); thin_image ( img, img_width, img_height ); org_img_triangle = make_bitmap_array( img_width, img_height ); copy_bitmap_array( img_triangle, org_img_triangle, img_width, img_height ); thin_image ( img_triangle, img_width, img_height ); addEventListener( Event.ENTER_FRAME, onEnterFrame ); } public function onEnterFrame (event:Event) : void { // original image draw_image ( org_img, img_width, img_height, 100, 50 ); // thining image draw_image ( img, img_width, img_height, 200, 50 ); // original image draw_image ( org_img_triangle, img_width, img_height, 100, 150 ); // thining image draw_image ( img_triangle, img_width, img_height, 200, 150 ); } public function draw_image ( img_src:Array, w:int, h:int, xpos:int, ypos:int ) : void { for ( var x:int = 0 ; x < w; x ++ ) { for ( var y:int = 0 ; y < h; y ++ ) { var col:int; if ( img_src[y][x] == 1 ) col = 0x00ffffff; else col = 0x00000000; _bitmap.setPixel( xpos +x, ypos +y, col ); } } } public function thin_pixel_common ( s:Array, x:int, y:int ) : int { // pixel removal condition // 1. pixel is black if ( s[y][x] == 0 ) return 0; var near:Array = new Array( s[y-1][x-1], s[y-1][x], s[y-1][x+1], s[y][x+1], s[y+1][x+1], s[y+1][x], s[y+1][x-1], s[y][x-1], s[y-1][x-1] ); var count: int = 0; var connect:int = 0; for( var i:int = 0; i <= 7; i++ ) { if( near[i] == 1 ) count ++; if( near[i] == 1 && near[i+1] == 0 ) connect ++; } // 2. near pixels // check black pixels are >=2 and <=6 if ( count >= 2 && count <= 6 && // 3. connectivity is 1 connect == 1 ) return 1; return 0; } public function thin_pixel_loop1 ( s:Array, x:int, y:int ) : int { if ( thin_pixel_common ( s, x, y ) == 0 ) return 0; if ( (s[y][x-1] == 0 || s[y-1][x] == 0 || s[y][x+1] == 0) && (s[y-1][x] == 0 || s[y][x+1] == 0 || s[y+1][x] == 0) ) { return 1; } return 0; } public function thin_pixel_loop2 ( s:Array, x:int, y:int ) : int { if ( thin_pixel_common ( s, x, y ) == 0 ) return 0; if ( (s[y][x-1] == 0 || s[y+1][x] == 0 || s[y][x+1] == 0) && (s[y-1][x] == 0 || s[y][x-1] == 0 || s[y+1][x] == 0) ) { return 1; } return 0; } public function thin_loop1 ( img_src:Array, width:int, height:int ) : int { var del:Array; del = make_bitmap_array( width, height ); var thin_flag:int = 0; var y:int = 1; var x:int = 1; for ( y = 1; y < height-1; y++ ) { for ( x = 1; x < width-1; x++ ) { if ( thin_pixel_loop1( img_src, x,y ) == 1 ) { del [y][x] = 1; } } } thin_flag = del_bitmap_array ( img_src, del, width, height ); return thin_flag; } public function thin_loop2 ( img_src:Array, width:int, height:int ) : int { var del:Array; del = make_bitmap_array( width, height ); var thin_flag:int = 0; var y:int = 1; var x:int = 1; for ( y = 1; y < height-1; y++ ) { for ( x = 1; x < width-1; x++ ) { if ( thin_pixel_loop2( img_src, x,y ) == 1 ) { del [y][x] = 1; } } } thin_flag = del_bitmap_array ( img_src, del, width, height ); return thin_flag; } public function del_bitmap_array ( src:Array, del:Array, width:int, height:int ) : int { var thin_flag:int = 0; var y:int = 1; var x:int = 1; for ( y = 1; y < height-1; y++ ) { for ( x = 1; x < width-1; x++ ) { if ( del [y][x] == 1 ) { src[y][x] = 0; thin_flag = 1; } } } return thin_flag; } public function make_bitmap_array ( width:int, height:int ) : Array { var y:int = 0; var x:int = 0; var arr:Array = new Array(height); for ( y = 0; y < height; y ++ ) { arr[y] = new Array(width); for ( x = 0; x < width; x ++ ) { arr[y][x] = 0; } } return arr; } public function copy_bitmap_array ( s:Array, d:Array, width:int, height:int ) : void { var y:int = 0; var x:int = 0; for ( y = 0; y < height; y ++ ) { for ( x = 0; x < width; x ++ ) { d[y][x] = s[y][x]; } } } // thining algorithm : Zhang Suen public function thin_image ( img_src:Array, width:int, height:int ) : void { var cont : int = 1; while (cont) { cont = 0; if ( thin_loop1( img_src, width, height ) == 1 ) cont = 1; if ( thin_loop2( img_src, width, height ) == 1 ) cont = 1; } } } }
'프로젝트 > motion capture' 카테고리의 다른 글
joint skeleton tracking (0) | 2011.09.07 |
---|