Members‎ > ‎Wataru-Fujimura‎ > ‎Kinect Tips‎ > ‎

シェーダーを使った実画像取得

実画像取得の処理をシェーダーを交えて行います。
(作成日:2012/04/02)

以前行った実画像取得のプログラムでは、イベントハンドラ内で以下のような操作を行っていました。

    for (int y = 0; y < image.Height; y++)
    {
        for (int x = 0; x < image.Width; x++, no += 4)
        {
            // BGRAからRGBAに変換する
            temp = imageData[no];
            imageData[no] = imageData[no + 2];
            imageData[no + 2] = temp;

            // Alphaを255にする
            imageData[no + 3] = 255;
        }
    }

この処理で何を行いたかったかというと、byte配列の情報をRGBAの順にする・A(アルファ)値を255に指定することです。
KinectではBGRAの順で色情報が格納されています。またA値は0です。
XNA上でそのまま描画すると下図のようになります。



このようにならないために処理を行っていましたが、XNAを用いているのでシェーダーで処理してみましょう。




1.プロジェクトを作る
2.参照設定を追加

XNAによる実画像取得のようにしてください。


3.エフェクトファイルを作る

XNAではシェーダーの処理をエフェクトファイルに記述します。
エフェクトファイルはソリューションエクスプローラ内の[Content]を右クリックし、[追加]→[新しい項目]を選択します。




エフェクトファイルを選択、ファイル名を指定し追加してください。



追加するとエフェクトファイルが生成され、[Content]内に表示されます。



imageeffect.fxには下記のように記述してください。

imageEffect.fx

// テクスチャー
texture imageTexture;

struct VertexShaderInput
{
float4 texcoord : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 texcoord : TEXCOORD0;
};

sampler textureSampler = sampler_state
{
Texture = imageTexture;
};

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// 画像の色情報の取得
float4 tex = tex2D(textureSampler, input.texcoord);
// BとRの値を交換
float tmp = tex.r;
tex.r = tex.b;
tex.b = tmp;

// アルファ値を255に設定
tex.a = 255;
return tex;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}



4.プログラミング

以下のコードのように入力してください。

Game1.cs

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;

// kinectのセンサクラス
// Microsoft.Kineを参照に追加
using Microsoft.Kinect;

namespace xnaimageshader
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        /// <summary>
        /// 実画像テクスチャ
        /// 640x480
        /// </summary>
        private Texture2D imageTexture;

        /// <summary>
        /// kinectから取得したRGBデータ
        /// (byte型配列)
        /// </summary>
        private byte[] imageData;

        /// <summary>
        /// KINECTのセンサクラス
        /// </summary>
        private KinectSensor kinect;

        /// <summary>
        /// 画像処理用のエフェクトファイル
        /// </summary>
        private Effect imageEffect;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // ウィンドウサイズの指定
            graphics.PreferredBackBufferHeight = 480;
            graphics.PreferredBackBufferWidth = 640;
        }

        protected override void Initialize()
        {
            // kinectの初期化
            kinect = KinectSensor.KinectSensors[0];

            // カラー画像の取得を開始する
            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(ColorImageReady);
            kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

            // Kinectを起動する
            kinect.Start();

            base.Initialize();
        }

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

            imageEffect = Content.Load<Effect>("imageEffect");
        }

        protected override void UnloadContent(){}
        
        protected override void Update(GameTime gameTime)
        {

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);


            // 通常の描画
            spriteBatch.Begin();

            // 実画像Textureの描写(描画サイズを半分に指定)
            if (imageTexture != null)
                spriteBatch.Draw(imageTexture, Vector2.Zero, null, Color.White, 0.0f, Vector2.Zero, 0.5f, SpriteEffects.None, 0.0f);

            spriteBatch.End();



            // エフェクトファイルを使った描画
            spriteBatch.Begin(0, null, null, null, null, imageEffect);

            if (imageTexture != null)
                spriteBatch.Draw(imageTexture, new Vector2(320,0), null, Color.White, 0.0f, Vector2.Zero, 0.5f, SpriteEffects.None, 0.0f);

            spriteBatch.End();


            base.Draw(gameTime);
        }


        /////////// イベントハンドラ ///////////

        /// <summary>
        /// カラー画像の取得
        /// </summary>
        void ColorImageReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            // kinectからカラーイメージを取得
            ColorImageFrame image = e.OpenColorImageFrame();

            if (image != null)
            {
                // imageData配列の初期化
                imageData = new byte[image.PixelDataLength];

                // imageのピクセルデータをpixelDataへコピーする
                image.CopyPixelDataTo(imageData);

                // imageTextureの初期化
                imageTexture = new Texture2D(GraphicsDevice, image.Width, image.Height);

                // imageTextureにimageDataを反映する
                imageTexture.SetData(imageData);
            }
        }
    }
}




実行結果

このような感じで表示されるはずです。
(画像は半分の大きさで表示しています)




ċ
xnaimageshader.zip
(46k)
Wataru Fujimura,
Apr 2, 2012, 12:15 AM
Comments