BLOG ARTICLE 프로젝트/motion capture | 2 ARTICLE FOUND

  1. 2011.09.07 joint skeleton tracking
  2. 2011.09.02 [AS3] 세선화, Thinning (2)


세선화를 하고 나면 이제 인체 뼈대 모델로 매핑할 수 있어야 한다..

아 어렵다는 느낌이 팍온다;;

일단 검색을 하니 Motion Capture Using Joint Skeleton Tracking and Surface Estimation라는 논문이 보였다.

뭔진 모르고 일단 다운 받아야지... --;; 

지금 생각에 이런 단계를 거쳐야 할거 같다..

1. 배경 제거
2. 색깔 단순화
3. 세선화
4. 뼈대 모델 적용
5. 뼈대 모델 트래킹

아.. 키넥트를 사면 개발자sdk를 이용해서 바로 될 수 있는 부분일텐데..
키넥트를 사야할거 같기도 하고 -_-.. 걍 한번 대충 만들어보고도 싶고..

고민된다 ㄷㄷ..


'프로젝트 > motion capture' 카테고리의 다른 글

joint skeleton tracking  (0) 2011.09.07
[AS3] 세선화, Thinning  (2) 2011.09.02
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST



세선화는 그림을 실선화 시키는 알고리즘이다. 가장 잘 알려진 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
[AS3] 세선화, Thinning  (2) 2011.09.02
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. BlogIcon kevin 2011.09.03 21:00 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. ^^ 글 잘 읽었습니다.
    위에 공개된 알고리즘을 사용해서 저도 실제로 한번 해봤는데요. 약간의 버그가 있는 것 같습니다. 제가 테스트 한 것은 다음의 배열이고요.

    http://www.sysnet.pe.kr/temp/triangle_before.txt

    그런데 변환은 다음과 같이 됩니다.

    http://www.sysnet.pe.kr/temp/triangle_after.txt

    이미지 상으로 보면, 굵은 테두리를 가진 삼각형인데 세선화 이후 밑변이 사라져버립니다. ^^

    • BlogIcon broneri 2011.09.06 15:51 신고  댓글주소  수정/삭제

      댓글 감사합니다. ^^
      코드를 보니 잘못 쓴 부분이 있군요 -_-;;

      일단 kevin님 블로그를 확인했구요 ^^
      http://blog.naver.com/PostView.nhn?blogId=techshare&logNo=100137156001

      여기에 있는 알고리즘 소스를 보니 하기와 같이 바탕색이 하나라도 있는 경우 조건을 처리하고 있고,..

      iteration 1, p1 = a[0] * a[2] * a[4], p2 = a[2] * a[4] * a[6]
      _o___o_
      o_o___o
      _____o_

      iteration 2, p1 = a[0] * a[2] * a[5], p2 = a[0] * a[4] * a[6]
      ______o
      o_o__o_
      _o____o

      제 코드에서는 오타가 나서 하기와 같이 iteration1용 조건이 잘못되어 있네요. ㅎㅎ

      __o____o_
      _o_o__o_o


      __o________
      ___o___o_o
      __o_____o_

      집에가서 한번 다시 확인해보겠습니다.

      덕분에 버그를 찾았네요 감사합니다 ^^



티스토리 툴바