次のようなことをやります。
- Livetを使用したWPFアプリケーション
- NyARToolKitでカメラキャプチャとマーカー検出
- OpenCVSharpでマーカー位置に矩形を描画
次に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); } }