WPF(Livet)とNyARToolKitでマーカー検出

マーカーの位置検出を行うために、マーカーの検出をNyARToolKitで行うサンプルプログラムを作成しました。
次のようなことをやります。
  1. Livetを使用したWPFアプリケーション
  2. NyARToolKitでカメラキャプチャとマーカー検出
  3. OpenCVSharpでマーカー位置に矩形を描画
初めにXAML。Grid内だけ変更しています。ボタンを押すとマーカー検出がスタートします。
    



次にVeiwModel。
NyARToolKitはその実装の関係上「onBuffer」という関数が呼ばれるので、その中で処理をしています。
NyARToolKitのサンプル等ではBitmapで画像を処理しているので、
それをMatに変換してOpenCVSharpで矩形を描画しています。

そのあとに、MatをWriteableBitmapに直して、XAMLでBindingできるようにします。
ここで、onBufferという別タスクでUIで利用するWriteableBitmapを変更できないので、
Dispatchar.BeginInvokeを使用して、UI関係にアクセスできるようにしています。

using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using jp.nyatla.nyartoolkit.cs;
using jp.nyatla.nyartoolkit.cs.core;
using jp.nyatla.nyartoolkit.cs.detector;
using NyARToolkitCSUtils.Capture;
using NyARToolkitCSUtils.Direct3d;

using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;

namespace ar_SimpleLite.ViewModels
{
public class MainWindowViewModel : ViewModel, CaptureListener
{
private NyARToolkitCSUtils.Capture.CaptureDevice m_cap;
private const String AR_CODE_FILE = "patt.hiro";
private const String AR_CAMERA_FILE = "camera_para.dat";
private NyARSingleDetectMarker m_ar;
private DsRgbRaster m_raster;

private Dispatcher dispatcher;

public void Initialize()
{
//ARの設定
//AR用カメラパラメタファイルをロード
NyARParam ap = NyARParam.createFromARParamFile(new StreamReader(AR_CAMERA_FILE));
ap.changeScreenSize(320, 240);

//AR用のパターンコードを読み出し
NyARCode code = NyARCode.createFromARPattFile(new StreamReader(AR_CODE_FILE), 16, 16);

NyARDoubleMatrix44 result_mat = new NyARDoubleMatrix44();

//計算モードの設定
//キャプチャを作る
/**************************************************
このコードは、0番目(一番初めに見つかったキャプチャデバイス
を使用するようにされています。
複数のキャプチャデバイスを持つシステムの場合、うまく動作しないかもしれません。
n番目のデバイスを使いたいときには、CaptureDevice cap=cl[0];←ここの0を変えてください。
手動で選択させる方法は、SimpleLiteDirect3Dを参考にしてください。
**************************************************/
CaptureDeviceList cl = new CaptureDeviceList();
NyARToolkitCSUtils.Capture.CaptureDevice cap = cl[0];

cap.SetCaptureListener(this);

cap.PrepareCapture(320, 240, 30);
this.m_cap = cap;
//ラスタを作る。
this.m_raster = new DsRgbRaster(cap.video_width, cap.video_height, NyARBufferType.OBJECT_CS_Bitmap);
//1パターンのみを追跡するクラスを作成
this.m_ar = NyARSingleDetectMarker.createInstance(ap, code, 80.0);
this.m_ar.setContinueMode(false);

dispatcher = Dispatcher.CurrentDispatcher;
}


#region WBmp変更通知プロパティ
private WriteableBitmap _WBmp;

public WriteableBitmap WBmp
{
get
{ return _WBmp; }
set
{
if (_WBmp == value)
return;
_WBmp = value;
RaisePropertyChanged();
}
}
#endregion


#region ButtonCommand
private ViewModelCommand _ButtonCommand;

public ViewModelCommand ButtonCommand
{
get
{
if (_ButtonCommand == null)
{
_ButtonCommand = new ViewModelCommand(Button);
}
return _ButtonCommand;
}
}

public void Button()
{
this.m_cap.StartCapture();
}
#endregion


public void OnBuffer(NyARToolkitCSUtils.Capture.CaptureDevice i_sender, double i_sample_time, IntPtr i_buffer, int i_buffer_len)
{
int w = i_sender.video_width;
int h = i_sender.video_height;
int s = w * (i_sender.video_bit_count / 8);

Bitmap b = new Bitmap(w, h, s, System.Drawing.Imaging.PixelFormat.Format32bppRgb, i_buffer);

// If the image is upsidedown
b.RotateFlip(RotateFlipType.RotateNoneFlipY);
Mat img = b.ToMat();

//ARの計算
this.m_raster.setBuffer(i_buffer, i_buffer_len, i_sender.video_vertical_flip);
if (this.m_ar.detectMarkerLite(this.m_raster, 100))
{
NyARDoubleMatrix44 result_mat = new NyARDoubleMatrix44();
this.m_ar.getTransmationMatrix(result_mat);
Console.WriteLine("Maker is found.");

NyARSquare square = m_ar.refSquare();

var point = new OpenCvSharp.CPlusPlus.Point[4];
point[0] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[0].x, square.sqvertex[0].y);
point[1] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[1].x, square.sqvertex[1].y);
point[2] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[2].x, square.sqvertex[2].y);
point[3] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[3].x, square.sqvertex[3].y);

img.FillConvexPoly(point, new Scalar(0, 0, 255));
}
else
{
Console.WriteLine("Maker is NOT found.");
}

dispatcher.BeginInvoke(new Action(delegate()
{

WBmp = img.ToWriteableBitmap();
}));
}

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
}
}