[XNA , Texture2D] Texture2D from Bitmap (fast copy)


종전의 방식 (http://scripter.egloos.com/2548511) 으로는 너무 느려 실시간으로 이미지를 갱신하는데에
무리가 있었다.

그래서 아에 Stream 으로 복사하는 방법을 찾았고 Aforge 의 영상을 붙이는데 성공했다.







이전의 http://www.codeproject.com/KB/game/VidTextureClassWebcamApp.aspx?msg=2630927
보다 화질은 좋아졌다.(쨍 .. 하다..)
간혹 보이는 계단현상이 없어졌다.

속도는 .. 처음엔 조금 딜레이가 생기다가 곧 VideoTexture 만큼 복귀 되었으나 약간 속도가
불안정하긴 했다.

하지만 VideoTexture 에서 런타임중 간헐적으로 나오는 오퍼레이터 에러는 없어 덜컥? 거리는 현상이
없다.

그리고 VideoTexture 보다는 시피유 점유율이 조금 높게 나왔다.

Created with colorer-take5 library. Type 'csharp'

private Texture2D tx;
        //Aforge �� 플레이어
        VideoSourcePlayer player = new VideoSourcePlayer();

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            tx = new Texture2D(graphics.GraphicsDevice, 1024, 768);//dummy;


            //Aforge �� 디바이스 설정 
            FilterInfoCollection device = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            VideoCaptureDevice cam = new VideoCaptureDevice(device[0].MonikerString);
            
            player.VideoSource = cam;
            player.Start();

            //플레이어가 갱신될때 마다 ��출
            player.NewFrame += new VideoSourcePlayer.NewFrameHandler(player_NewFrame);
        }


        //인��로 비트맵을 받음
        void player_NewFrame(object sender, ref Bitmap _image)
        {
            //비트맵�� 고속 복사
            MemoryStream camStream = new MemoryStream();
            player.GetCurrentVideoFrame().Save(camStream, ImageFormat.Bmp);
            camStream.Position = 0;
            tx = Texture2D.FromFile(graphics.GraphicsDevice, camStream);
            
        }
 
 
 
포인트 : 비트맵의 고속복사. 


나중에 곧.. ? Aforge의 VideoSourcePlayer의 stream 을 직접 참조 할수 있는 방법을 모색하여 좀더
높은 퍼포먼스를...
Yamecoder 야매코더_
tags : bitmap, copy, texture2D, XNA
분류없음 2010.12.04 03:48

[Draw Line Algorithm] 1. 기본(1)


[Draw Line Algorithm] 1. 기본(1)

XNA 에 별다른 비트맵 API가 없다는것을 알고 , 한번 픽셀을 다루기로 했다.

우선 브레슨햄 알고리즘 에 들어가기 전에 일반적인 선을 그리는 알고리즘을

살펴 보아야 하겠다.

먼저 우리가 비트맵에 선을 긋기 위해서는 일반적으로 두점을 필요로 한다. 
(물론 한점과 기울기를 이용할수도 있겠지만 특별한 경우가 아니라면 정확한 포인팅이 가능한 두점을 이용한다)  

우선 고등학교 기초 수학에 보면 두점을 알때 직선 방정식은 ..

(공통수학의 정석 p554)

p0(x0 , y0) 와 p1(x1,y1) 을 알때 직선의 방정식은 

Y - y0 = ( y1 - y0 / x1 - x0 ) * ( X - x0)  (단 , x1  !=  x0)

이러하다. 기본적인 Y = m*X 라는 공식에 대힙하면  ( y1 - y0 / x1 - x0 ) 이 기울기 이자

변화량 이란것쯤은 알수있다. 나머지 Y - y0  ,  X - x0  은 평행 이동 이다.

누구나 알고 있을법한 이 방정식을 비트맵 위에 표현해보자.

우선 비트맵은 정수들 "맵" 이다, 위의 공식의 영역은 "실수" 이다.

따라서 정수로 다운캐스팅 하여 표현 해야 한다.


이제 한번 본격적으로 for 루프를 생각해 보자

기본적으로 X 축 변화량을 생각하면 범위를 쉽게 생각할수 있다.
이다. 따라서 for 루프는 다음과 같이 될수 있겠다.

for( var _x:int =p0.x   ; _x < p1.x  ; ++_x)
{
    //
}


이것으로 공식의 우변 _x 를 설정 했다. 그리고 이것을 Y에 넣기 전에 기울기 m을 설정하자

var m:Number = (p1.y-p0.y)/(p1.x-p0.x);

이다

이제 루프를 완성하면

for( var _x:int =p0.x   ; _x < p1.x  ; ++_x)
{
     var _y:int =Math.round(m*(_x-p0.x) + p0.y);
     data.setPixel(_x,_y,0);
}


완성하면 여기서 dataBitmapData 이다.

그리고 위의 직선 공식을 정리하면 _y 값을 얻을수 있는데 

아까도 말했드시 비트맵은 정수를 사용하여서  round 로 반올림을 하여 정수화 했다.

이 공식을 이용하여 간단히 프로그래밍 해보면,.

Bresenham1_as.swf

p0 와 p1을 직접 움직여 보자



와 같은 결과를 낸다.  ( 브라우저에서 해보기 보단 직접 다운하여 로컬에서 추천)

그런데 조건이 있다.

1.
Y - y0 = ( y1 - y0 / x1 - x0 ) * ( X - x0)  (단 , x1  !=  x0)
에서의 조건인데 p0.x 와 p0.y 가 같으면 안되고

2.
또한 위의 결과물에서는 기울기가 (-) 이 되었을때 , 즉( p0.x > p1.x ) 가 되었을때,

3.
x의 변화량 보다 y의 변화량이 클때 , 즉 기울기가 1 보다 클때 비트맵의 양 조절


이렇게 3개 이고 이것에 대해 파생되는 여러 예외를 제어 해야 한다.

'수학' 카테고리의 다른 글

[Draw Line Algorithm] 1. 기본(2) 총정리  (90) 2010.12.04
[Draw Line Algorithm] 1. 기본(1)  (65) 2010.12.04
[회전변환] 특정좌표를 중심으로 회전변환  (122) 2010.12.04
[삼각함수] 기울어진 그리드의 좌표 구하기  (39) 2010.12.04
정렬  (45) 2010.12.04
atan2 를 "도" 로 환산  (200) 2010.12.04
Yamecoder 야매코더_
수학 2010.12.04 03:39

[bitmapData Capture] stage capture 시 유의점

상황은 트위너로 5개의 cicle을 랜덤하게 트위닝 하고,
그것을 엔터프레임으로 비트맵 데이터로 캡춰를 하는 상황이다.

그리고 엔터프레임 안에는 기본적으로 아래와 같이 작성을 한다.

//in EnterFrame
capture = new BitmapData(stage.stageWidth, stage.stageHeight , false ,0xd0d0d0)
capture.draw(stage)
//

그럼 결과는


하지만 이것은 원하는결과가 아니다.
잔상이 없는 결과를 원하면 스테이지에 바로 addChild하지말고
컨테이너를 하나 만든다음 해줘야 한다.

//in EnterFrame
capture = new BitmapData(stage.stageWidth, stage.stageHeight , false ,0xd0d0d0)
capture.draw(contaner) // contaner 는 Sprite 인스턴스이다.
//

결과는



테스트 코드는 captureTest.txt
Yamecoder 야매코더_
AS3 2010.12.04 02:41

[XNA , Texture2D] Texture2D from Bitmap (very Simple)


Content.Load<T> 로 불러올수 있는것은 *.xnb밖에 없다.

동적으로 캡춰되거나 연산된 비트맵을 받아오기가 영 까다롭다.

그래서 매우 간단한 비트맵 복사 방법을 생각했다.


Created with colorer-take5 library. Type 'csharp'

private Texture2D tx;
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //비트맵을 만든다.
            Bitmap b = new Bitmap(@"c:\a.jpg");
            //xna �� 컬러배열을 타겟 비트맵 크기만큼 생성한다.
            xColor[] pixels = new xColor[b.Width * b.Height];
            //x , y 루프를 돌려 비트맵�� 컬러를 검출��여 xna 컬러배열에 넣는다.
            for (int y = 0; y < b.Height; ++y)
                for (int x = 0; x < b.Width; ++x)
                {
                    cColor c = b.GetPixel(x, y);
                    pixels[(y * b.Width) + x] = new xColor(c.R, c.G, c.B, c.A);
                }
            //texture2d를 생성��고 컬러를 적용한다.
            tx = new Texture2D(graphics.GraphicsDevice, b.Width, b.Height, 1, TextureUsage.None, SurfaceFormat.Color);
            tx.SetData<xColor>(pixels);


        }
실시간으로 캡춰가 될때 퍼포먼스는 아직 무리수
 
 
Yamecoder 야매코더_
XNA 2010.12.04 02:28

[C# XNA][texture2D.Setdata] XNA에서 픽셀을 하나하나 다루어 보자.

xna의 API 가 익숙하지 않았던때, 픽셀을 다루기 위해 C#의 기본 GDI를 이용해여
마샬링 하여 텍스쳐에 붙였다.

그런데,. 반전이.. zune hd 에서 사용할수 있는 네임스페이스가 극히 제한적이라..
Bitmap은 가져 오지 못한다.

그래서 텍스쳐하나당 한픽셀을 그려야 된다고 생각하자 말도안되는 리소스 낭비이다.
텍스쳐2D 와 Draw메소드를 엄청나게 사용해야되서, 도저히 용납할수 없는 코딩이 될것이다.


고민끝에,  ,.XNA짱인,.  곰동님에게 긴급 질문했다. 그리고 친절히 답해 주셨다.
http://blog.naver.com/fly33499  )



위의 그림처럼 하나의 Texture2D에 여러개의 setData를 이용해 픽셀들을 다룰수 있다.

드디어 2D 비트맵을 다룰수 있게 되었다 마치 bitmapData의 setPixel 처럼 자유롭다.

기본적인 사용법은 이러하다.

주석 위주로 보면 됨


Created with colorer-take5 library. Type 'csharp'

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace WindowsGame9
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D tx;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 272;
            graphics.PreferredBackBufferHeight = 480;
        }

        protected override void Initialize() { base.Initialize(); }
                
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            tx = new Texture2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);

            //픽셀����그리기 (레벨 , 위��(x좌표,y좌표,1,1), 컬러값  ~ )
            tx.SetData<Color>(0, new Rectangle(0, 0, 1, 1),new Color[]{Color.Black} ,0, 1, SetDataOptions.None);
            

            //응용! 면적 체우기 

            //화려한?컬러값을 위해 랜덤 함�� ��출
            Random r = new Random();
            Color c;

            //가로크기
            for (int i = 0; i < graphics.PreferredBackBufferWidth; ++i)
            {
                //세로크기
                for (int j = 0; j < graphics.PreferredBackBufferHeight; ++j)
                {
                    //랜덤 컬러
                    c = new Color(new Vector3(r.Next(i), r.Next(j), r.Next(3)));
                    //픽셀만들기 , 총 272 * 280 개 만큼 그린다.
                    tx.SetData<Color>(0, new Rectangle(i, j, 1, 1), new Color[]{ c } , 0, 1, SetDataOptions.None);
                }
            }
        }

        protected override void UnloadContent(){  }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            
            //시작��고 그리고 끝내고 는 기본.
            spriteBatch.Begin();
            spriteBatch.Draw(tx, new Vector2(0, 0), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

아직 깊게 봐야 할것이 많이 있지만, 우선 요것 가지고 쉽게 사용할수있도록
AS3 스타일로 클래스를 랩핑하면 매우 유용할듯하다.

원하는대로 Circle 이라던지 Line 이라던지 이제 루프만 잘 돌리면 된다.

다시한번 곰동님께 감사입니다~

※ zune hd의 해상도가 272 * 480 이라서 이러한 크기에서 테스트중..
 
Yamecoder 야매코더_
XNA 2010.12.04 00:08
Powerd by Tistory, designed by criuce
rss