Loading [MathJax]/extensions/tex2jax.js

2014-05-30

Dynamic Data Displayはじめの一歩

Dynamic Data Displayの使い方です。

(1)DLLを参照設定に割り当てる
”DynamicDataDisplay.dll”というのが必須ですので、これを参照に追加します。

(2)XAMLに直接記述する
下記のように記述します。NameSpaceの設定を忘れないようにしてください。下記の例は、LineChartを利用するためのコンテナになる部分になります。

<Window x:Class="KinectSampleWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
Title="MainWindow" Height="868" Width="1297" Loaded="Window_Loaded" Background="White">
<Grid>
<d3:ChartPlotter Grid.Column="1" Name="plotter" Margin="202,507,846,116">
</d3:ChartPlotter>
</Grid>
</Window>
(3)C#コードを書く
あとは、コード内でplotterというのを呼び出すことができますので、これに対して操作をしていきます。

Dynamic Data DisplayでWPF版グラフ処理

WPFではFormアプリケーションと比べるとライブラリの数が少ない傾向があります。グラフ作成に関して、FormアプリケーションではChart コンポーネントが標準であるのですが、WPFでは今だに標準では用意されていない状況です。とりあえず以下の3つを使うのが一般的なようです。各ライブラリの細かい説明は省きますが、だいたい次の特徴があります。
(1)WPF Toolkit
Chartコンポーネントの実装がunstableになっているなど、一部不安定。更新もされていない。後継に、Extended WPF Toolというのがある?
(2)Dynamic Data Display
動的な変化に強い。更新はされてない
(3)Metoro Chart
Windows8のメトロUI向け。最近更新されている。

本ラボでは、動的なLineChartのグラフ更新をしたかったので(2)を選択しました。(1)も試してみたんですが、unstableな状態のせいか、だんだん速度が遅くなって最終的に動作が停止してしまうんです。同じような使い方で(2)では問題なくサクサク更新してくれました。(3)については将来的に使うようになるかもしれません。


2014-05-19

スレッド外にあるImageクラス(WPF)にWritableBitmapを割り当てる

WindowsのUIクラスは、基本的にメインのスレッドで動いており、他のスレッドから操作することはできないようになっています。例えば、他のスレッドからカメラの映像をリアルタイムで取り出し、それをImageクラス(WPF)に表示するという記述は原則できません。
もちろん、これを解決する策はあり、Invokerを経由すれば可能です。一番簡単な方法は、下記のサンプルソースに示すようにラムダ式を利用することで簡潔に表現できます。

なお、このケースでの注意点はもう1つあります。それは、Imageクラスに描画するためのWritableBitmapもスレッド外から操作できるように、Freezeしておく必要があります。実はここが一番の悩みどころだったりしました。

wbmp = new WriteableBitmap(BitmapFrame.Create(mstr)); //MemoryStreamからWritebleBitmapを生成
wbmp.Freeze(); //Freezeさせるのがポイント
newImage.Dispatcher.Invoke(
new Action(() => {
newImage.Source = wbmp;
})
);


Byte[]に入っているJPEGデータをBitmapImageに変換する

Byte[]に格納されているデータをWritableBitmapに変換するためには、

MemoryStream を経由してBitmapImageのStreamSourceに設定する 
のがよいらしいです。ただし、BeginInitとEndInitが必要です。これがないとダメです。
MemoryStream mstr = new MemoryStream(data);
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = mstr;
bitmapImage.EndInit();


2014-05-17

Byte[]に入っているJPEGデータをWritableBitmapに変換する

Byte[]に格納されているデータをWritableBitmapに変換するためには、
MemoryStream -> BitmapFrame -> WritableBitmap
という流れでやるとよいらしいです。下記のサンプルでは、MemoryStreamへの変換を2回やってますが、1回でいいかもしれません。
//dataはByteArray
MemoryStream mstr = new MemoryStream(data);
//MemoryStream ms = new MemoryStream(mstr.ToArray()); //この処理は多分不要
WriteableBitmap wbmp = new WriteableBitmap(BitmapFrame.Create(ms));


2014-05-16

WPFでChartを利用するには、Silverlight/WPF Data Visualization Developmentを使えばよい

C#のデスクトップアプリでグラフ(Chart)を利用するには、Windows Formプロジェクトであれば、
System.Windows.Forms.DataVisualization.Charting
を利用すればいいわけですが、WPFプロジェクトであればそう簡単にはいきません。なんと標準ではChart系のGUIコンポーネントがないという信じられない状況。
で、どうやら
というのをダウンロードするといいようです。

使い方
次のいずれかの方法で使えます。
  • ダウンロードしたプロジェクトを参照する
  • \Binaries\WPF4にあるSystem.Windows.Controls.DataVisualization.Toolkit.dll を参照に追加
とりあえず、Visual Studio2010でデスクトップアプリ(WPFプロジェクト)で動作確認しました。ネットの資料が少なそうですが、WPF ToolKitと同じ流れにあるようなので、その関連資料をみれば使い方がわかるのではないでしょうか?



2014-05-14

C#:WritableBitmap とIplImageの相互変換

前記事で、KinectではWPFのWritableBitmapを利用することをオススメしました。しかし現実には、Kinectの画像をただ表示するだけでなく、OpenCVで加工するなども処理も必要になります。この辺りの対応については心配なところですが、当然できています。下記のコードに示す通り、WritableBitmapクラスやIplImageクラスが相互変換するためのメソッドを実装しています。

ここで注意点は、2番めと3番目の処理の違いです。いずれもIplImageからWritableBitmapへの変換をしているわけですが、2番めはごっそり入れ替わる事になります。具体的に言えば、WPFのImageクラスのSourceにWritableBitmapを割り当てていた場合、2番めの処理をするとSourceに割り当てていた領域とは違うメモリ領域(アドレス)が割り当てられてしまい、以後、Imageの描画が反映されなくなります。後者の場合は、Sourceに割り当てたWritableBitmapの中身だけを書き換えるので、以後もImageの描画が反映されます。

// WritableBitmap からIplImageへの変換
IplImage image = wBitmap.ToIplImage();
//IplImageからWritableBitmapへの変換
wBitmap= image.ToWriteableBitmap();
//IplImageからWritableBitmapへの変換(WritePixelsと同じ)
WriteableBitmapConverter.ToWriteableBitmap(image,wBitmap);
// Mat と WriteableBitmapの相互変換
Mat mm =wBitmap.ToMat();
wBitmap= mm.ToWriteableBitmap();


Kinectプログラミングをする時は、WPFプロジェクト がお勧めです

Windowsプログラミング(.NETフレームワーク)において、GUIアプリの開発アプローチとしては、歴史的に
  • Formアプリケーション
  • WPFアプリケーション
の2つに分けられます。前者は従来のWindowsGUIプログラムの流れです。後者はVista以降に標準搭載された.NETフレームワーク3.0に最適化されたもので、GUI定義がXAMLと呼ばれるXMLで書かれたファイルで表現されるだけでなく、2Dや3Dを含めた各種GUI処理を統一的に扱えるフレームワークを持つという特徴があります。

ラボでは過去の実装ノウハウを活かすこととWPFに関する資料が少なかったことから、現在まで原則前者を使ってきており、Kinect のプログラミングでもそうしてました。しかし、画面描画処理のパフォーマンスをあげるなら、WPFの方が良いということに今更気づいたのと、さすがにWPFを無視することができなくなりましたので、以後、KinectプログラミングについてはWPFに乗り換えることにします。

WritableBitmapを利用するのがポイント
KinectのColorFrameをWPFで表示する際は、
  • PictureBoxクラスではなくImageクラスに表示
  • BitmapではなくBitmapSourceを割り当てるのが基本
  • WritableBitmapを割り当てると表示処理が高速化
という点が変わります。ポイントは3つめです。下記のサンプルを見てもらえばわかりますが、WritableBitmapを作成しImageクラスのSourceに1度だけ割り当てるだけで、あとはWritableBitmapの内容を更新するだけで更新されます。Formでは各フレーム画像ごとに毎回Bitmap変換して貼り付けていましたから、プログラムのスッキリしますし速度の向上も期待できます。

Int32Rect colorImageBitmapRect = new Int32Rect(0, 0, kinect.ColorStream.FrameWidth, kinect.ColorStream.FrameHeight);
int colorImageStride = kinect.ColorStream.FrameWidth * kinect.ColorStream.FrameBytesPerPixel;
WriteableBitmap wBitmap = new WriteableBitmap(kinect.ColorStream.FrameWidth, kinect.ColorStream.FrameHeight, 96, 96, PixelFormats.Bgr32, null);
//imageクラス(WPF)の描画ソースをWritableBitmapに指定しておく(1度だけでよい)
image1.Source = WBitmap;
// --以下は~FrameReadyでの処理 ---
//ColorFrameの取得
using (ColorImageFrame colorFrame = args.OpenColorImageFrame()){
if (colorFrame != null) {
byte[] pixelData = new byte[colorFrame.PixelDataLength];
colorFrame.CopyPixelDataTo(pixelData);
//ここでWritableBitmapを書き換えるだけで、image1の描画は更新される
this.wBitmap.WritePixels(this.colorImageBitmapRect, pixelData, this.colorImageStride, 0);
}
}


2014-05-11

反転授業用ビデオ作成にOffice Mixが面白そう


Microsoftから Office Mixというツールが登場しています。これは、
オンラインレッスンを簡単に作る
というコンセプトの元で作られたパワーポイントのアドインソフトウェアです。このソフトを利用するには、
  1. Office2013 with ServicePack1のインストール
  2. Offece Mixのサイトからプラグインをダウンロード&インストール
という手順が必要です。インストールが成功すると、パワーポイントにMixというリボンができています。


使い方の詳細はここでは書きませんが、基本的に、
  • パワーポイントスライドまたはデスクトップの画面をベースにする
  • スライドを任意のタイミングで進行させながらスライドへの書き込みが可能
  • 書き込みと同時に、ビデオ、音声の埋め込みが可能。
というシンプルな操作で直感的に理解できるでしょう。

下の画面は、Khan Academy っぽく、パワーポイントのスライドを黒地にしてそれに書き込んでみました。試してみるとわかりますが、ペンタブレットで書くのって意外と難しいですね。慣れが必要です。


まだまだPreview版ということで
  • 書き込みの削除不可
  • 音声、ビデオの編集不可
というように機能としては不十分ですが、これからどんどん改善されると思います。反転授業用のビデオ教材作成に使えないかなとちょっと思ってます。


2014-05-09

Funcデリゲートを使って実行内容を柔軟に変更する

C#には、デリゲートと呼ばれる枠組みがあります。C言語でいう「関数ポインタ」みたいな位置づけと思えばいいです。.NET Framework3.5から採用されています。抽象メソッドに似てますが、違うところは、
抽象メソッドはメソッド名まで定義されているが、デリゲートでは引数と戻り値だけが定義。名前は自由。
というところでしょうか。使い方は下記の通りです。抽象メソッドよりも何かクールな気がしませんか?
/*-----------------------------------------------------*/
//引数が(int, int)で戻り値がintのメソッドを受け取るデリゲート
//プロパティによりメソッドを登録する
Func<int, int, int> method;
public Func<int, int, int> Method {
get { return method; }
set { method = value; }
}
private void process(){
for(int i=0,i<10;i++){
//iとi+1を引数として渡す(ここでは中身は決まってない)
System.Diagnostics.Debug.WriteLine(this.method(i,i+1));
}
}
/*--------以下、処理を定義し登録する側 --------*/
//xxxxは上記のクラスのインスタンス
//Methodプロパティで関数を登録
xxxx.Method = test;
//登録する関数の実際の処理
int test(int x,int y){
return x + y;
}