FrameDescription から得られるプロパティに注意
About
KinectV2(SDK2.0) では、各データはその Frame クラスのインスタンスで与えられます。それらのインスタンスは、そのデータの形式などを示す FrameDescription を持っています。(あるいは、FrameDescription は 対象の FrameSource からも取得することができます。)
FrameDescription には、そのデータの幅や高さなど示す、Width, Height プロパティなどがありますが、このプロパティの値を活用する方法に注意する必要があります。
これらの情報は Kinect-V2 OpenBeta と SDK2.0 PublicPreview 時点のものであり、製品版のリリース、あるいはバージョンアップによって変更される可能性があります。また、実行環境に依存する問題の可能性がある点に注意してください。
&ref(): File not found: "WpfApplication1_KinectV2.zip" at page "Kinect/KinectForWindowsSDK/Tips/Careful about FrameDescription Property";- サンプルはサーバを引っ越した都合上、公開できなくなりました。
- .NetFrameork4.5 - WPF
- KinectSDK 2.0 PublicPreview
処理負荷が大きい
結論から言うと、FrameDescription の Width プロパティなどの値を取得すると、非常に負荷がかかります。実装レベルでの詳細などは不明ですが、以下に ColorFrame から FrameDescription を取得して実験した結果を示します。
特に画像処理などのために各データを参照するようなプログラムを書くときには注意が必要になるでしょう。リアルタイムに実行するようなパターンは十分に注意が必要です。詳細は後述します。
10,000 回の実行
まず ColorFrame から得られた FrameDescription のプロパティを 10,000 万回参照して、代入するだけのプログラムを実行して、処理時間を計測します。比較対象として、あるオブジェクトのインスタンスに含まれる値を参照する場合も用意しました。
public class DummyA { public class DummyB { public int Value { get; set; } } public DummyB DummyChild { get; set; } public DummyA() { this.DummyChild = new DummyB(); } } #region Pattern-A stopWatch.Restart(); for (int i = 0; i < 10000; i++) { dummyValue = colorFrame.FrameDescription.Width; } stopWatch.Stop(); Console.WriteLine("Pattern-A : " + stopWatch.Elapsed.TotalMilliseconds); #endregion Pattern-A #region Pattern-B stopWatch.Restart(); for (int i = 0; i < 10000; i++) { dummyValue = this.dummyParent.DummyChild.Value; } stopWatch.Stop(); Console.WriteLine("Pattern-B : " + stopWatch.Elapsed.TotalMilliseconds); #endregion Pattern-B
この実行結果は次の通りです。しばらく実行して間の3回を抜粋しました。単位はミリ秒です。全体を通してバラつきはありますが、10倍以上パフォーマンスが違うことが分かります。
/ | Pattern-A | Pattern-B |
1 | 1.9229 | 0.1677 |
2 | 1.9226 | 0.1668 |
3 | 1.9633 | 0.1704 |
問題となりやすいパターン
先のような形で FrameDescription を参照することは殆どないでしょう。現実的に注意が必要な例としては、画像処理などを目的として、取得したフレームに含まれる大量のデータを for などで繰り返し参照する場合が上げられます。
公式のサンプルでは、CoordinateMappingBasics などが該当します。CoordinateMappingBasics では、ユーザが映し出された画素領域内だけを表示するために、取得した BodyIndexFrame や ColorFrame のデータを繰り返し参照しています。
そこで、現実的に起こりうる実装方法で実験を行うことにします。ここでは ColorFrame から得られたデータを for を使って繰り返し参照するコードをいくつか実装して実行時間を計測しました。
C のパターンは、取得した ColorFrame から直接 FrameDescription.Width を参照し、繰り返し処理を実行します。ここでは Width は 1920 の値を示しています。
D のパターンでは、あから締め FrameDescription を取得しておき、そこから Width プロパティを参照して繰り返し処理を実行します。同じく Width は 1920 です。
E のパターンでは、int 型で FrameDescription.Width の値を取得しておき、繰り返し構文では確保した int 型の値を参照します。
#region Pattern-C stopWatch.Restart(); for (int i = 0; i < colorFrame.FrameDescription.Width; i++) { dummyValue = 0; } stopWatch.Stop(); Console.WriteLine("Pattern-C : " + stopWatch.Elapsed.TotalMilliseconds); #endregion Pattern-C #region Pattern-D FrameDescription colorFrameDescription = colorFrame.CreateFrameDescription(ColorImageFormat.Bgra); stopWatch.Restart(); for (int i = 0; i < colorFrameDescription.Width; i++) { dummyValue = 0; } stopWatch.Stop(); Console.WriteLine("Pattern-D : " + stopWatch.Elapsed.TotalMilliseconds); #endregion Pattern-D #region Pattern-E int width = colorFrameDescription.Width; stopWatch.Restart(); for (int i = 0; i < width; i++) { dummyValue = 0; } stopWatch.Stop(); Console.WriteLine("Pattern-E : " + stopWatch.Elapsed.TotalMilliseconds); #endregion Pattern-E
実行結果は次の通りです。単位はミリ秒です。for 構文の中で参照する場合でもこれだけパフォーマンスに開きがあります。現実的に、D のパターン程度の実行時間であれば許容できる気がしますが、積極的に E のパターンで実装しても良いでしょう。C のパターンだけは絶対に避けたいところです。
/ | Pattern-C | Pattern-D | Pattern-E |
1 | 1.0941 | 0.0117 | 0.0075 |
2 | 1.0917 | 0.0117 | 0.0075 |
3 | 1.0986 | 0.0114 | 0.0075 |