ページ

2013年8月20日火曜日

Intel Perceltual Computing SDKのPXCMImage.ImageDataからWriteableBitmapに直接データをコピーする

WPFでPerC SDKを利用したアプリケーション開発を行なっているのですが、その際に画面への表示にはImageSourceとしてWriteableBitmapを利用するのが便利です。PXCMImage.ImageDataにはToWriteableBitmapという便利なメソッドが存在していて、これを使えば簡単に変換を行うことができます。

しかし、このメソッドでは1フレーム表示ごとにWriteableBitmapのインスタンスが作られ、しばらく溜まるとGCによって開放されるということが繰り返されるようで、メモリ使用量がのこぎりの刃のようになってしまいます。
実際のところそれでも良いのかもしれないのですが、メモリは明示的に開放しないと気が済まないたちなので、なんとかして解決したいところです…

そこで、ToWriteableBitmapの使用を諦め、PerC SDKのPXCMImage内のメモリを直接触って、WriteableBitmapにコピーすることにしました。

--

手順は2段階に分かれていて、まずPXCMImageからbyte配列にデータをコピーします。
PXCMImage.ImageInfo info;
image.QueryInfo(out info);

PXCMImage.ImageData data;
image.AcquireAccess(PXCMImage.Access.ACCESS_READ, PXCMImage.ColorFormat.COLOR_FORMAT_RGB32, out data);

byte* p = (byte*)data.buffer.planes[0];
for (int i = 0; i < info.width * info.height * 4; i++)
    _buffer[i] = p[i];

image.ReleaseAccess(ref data);
この時、画像データにAcquireAccessするときにフォーマットを指定するのがポイントです。ここでRGB32を指定することで、1ピクセルあたり4バイトとして画像データにアクセスすることができます。
また、画像の先頭番地はplanes[0]にあるので、byte*に変換してアクセスします(unsafeを付ける必要があります)。

そして次に、コピーしたデータをUIスレッドの持つWriteableBitmapに書き込みます。
PXCMImage.ImageInfo info;
image.QueryInfo(out info);

var pw = (int)info.width;
var ph = (int)info.height;
var st = (int)info.width * 4;

var gs = _writeableBitmap;
var bf = _buffer;

//copy PXC image to image source
DispatcherHelper.BeginInvoke(new Action(() =>
    {
        gs.WritePixels(new Int32Rect(0, 0, pw, ph), bf, st, 0);
        RaisePropertyChanged("GestureImageSource");
    }));
一度バッファーに読み込んで、それをコピーするといった2段階に分けて処理を行っているのは、ImageSourceとなるWriteableBitmapはUIスレッドに存在していて、画像の更新を行うスレッドからはFreezeしない限りアクセス出来ないためです。

このようにすることで、WriteableBitmapのインスタンスを無駄に生成せずに画面表示を行うことが出来ました。

0 件のコメント:

コメントを投稿