2017/11/25

pybluezを利用すると"untimeError: Channel or attrib not ready"とエラーになる

pybluezをインストールしたので、サンプルなどを動作させようとしたのですが、、、
https://github.com/karulis/pybluez/tree/master/examples/ble
"read_name.py"を実行したのですが、下記のエラーで動作しません。
Connecting... Traceback (most recent call last):
  File "read_name.py", line 41, in 
    Reader("C7:7A:98:EA:17:17")
  File "read_name.py", line 16, in __init__
    self.connect()
  File "read_name.py", line 23, in connect
    self.requester.connect(True)
RuntimeError: Channel or attrib not ready
エラー名でぐぐってみると、gattlibが古いことが原因かもしれないと書いてあるので、
https://github.com/ev3dev/ev3dev/issues/775
pybluez, pygattlibともにソースからインストールしましたが、現状変わりません。
https://github.com/karulis/pybluez
https://bitbucket.org/OscarAcena/pygattlib
(というか、pygattlibは2年更新があまり無いですね。。。)

解決したら、また記事にする予定ですが、一応pybluez以外も試してみます。。。


2017/10/31

Choregrapheで独自ライブラリの作成方法

Choregrapheで分散開発を行う時に、各モジュールを「ボックスライブラリ」として分割することで、
各人でモジュールごとに開発して、別プロジェクトで利用することができます。

今回は例として"hello"というボックスライブラリを新規作成して、別プロジェクトに持っていき、実行してみます。

"Hello"というプロジェクトを新規作成して、サンプルとしてsayボックスを配置します。

次に全ボックスを選択し、右クリック->ボックスに変換 を行います。
このようにすることで、複数あるボックスを1つにまとめることができます。
今回は"Hello"というボックス名としました。

次に空のボックスライブラリを作成します。
下記画面部で新規作成します。
今回は"Hello"というライブラリ名にしました。
cblという拡張子で保存します。

ボックスライブラリはできました。
しかし、中身が空なので展開等はできません。


次に、先ほど1つのボックスにした"Hello"ボックスを"Hello"ボックスライブラリにドラッグ&ドロップします。そして、ボックスライブラリを保存します。
これで、"Hello"という独自ボックスを他のプロジェクトでも利用できるようになります。

次は、独自ボックスを利用したいプロジェクトでの利用方法です。
"Main"というプロジェクトを新規作成します。
次に、「ボックスライブラリを開く」で"Hello.cbl"を選択します。
このようにすることで、利用側でも"Hello"ボックスを使うことができるようになります。
利用方法は他のボックスと同じです。

参考にしたサイト
https://qiita.com/Atelier-Akihabara/items/db907ed319b8af0984db

https://qiita.com/ForexRobotics/items/5258892f1588319d0204

2017/09/04

Ubuntuにpybluezをインストール

UbuntuでBLEアプリを開発するので、pybluezをインストールします。

まずは、BlueZをインストールします。
ネットでは、ソースコードをコンパイルしている記事が多いですが、apt-getでインストールしたものでも動作確認できました。
sudo apt-get install bluez
次は、pybluezをインストールしていきます。
これもapt-getで入れてみたんですが、pythonで使おうとすると、「bluetooth.bleパッケージがない」と怒られてしまいます。。。

pipでインストールすると、bluetooth.bleパッケージができました。
(apt-getでもpipでもどちらでも0.22が入るはずなので、同じだろうと思うのですが、
実際にはpipではbleパッケージが追加されていました。)
pip install pybluez
pipでインストールにエラーが出てしまう場合は、下記のサイトのトラブルシューティングで解決できました。
http://qiita.com/dz_/items/4e858e4d50db19b57491

2017/08/21

PCE-AC55BTを購入しました

Bluetooth Low Energyを利用したソフトの開発を行うにあたって、デスクトップPCにBluetoothがついていなかったので、PCI Expressで拡張しました。

USBドングルでも拡張できますが、ほとんどがBluetooth 4.0までしか対応していないですし、ものによって動作の安定性が異なるのでPCI Expressでの拡張を行いました。

実際に取り付けたかったのは「Intel Dual Band Wireless-AC8260」.。
https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/dual-band-wireless-ac-8260-brief.pdf

アマゾンでも単体で売っていますが、m2をPCI Expressに変換するものを別途買う必要があります。

そこで注目したのが、PCE-AC55BTです。PCI Expressへの変換ボードも含めて売られています。
http://akiba-pc.watch.impress.co.jp/docs/news/news/1063334.html

こちらもアマゾンでも見つけたんですが。。。
https://www.amazon.co.jp/gp/product/B071PDKP7F/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1

ん!?
画像がちょっと違うくね!?
端子がmini PCI Expressじゃね?
説明にもBluetooth 4.0ってかいてね?
しかも、ついてんの「Intel Dual Band Wireless-AC 7260」じゃね!??


詳しく調べると、今までは7260がついていたのですが、最近8260がついた新モデルが出たらしい。
だけど、どちらも同じ型番なので区別がつかない。。。

一か八かでアマゾンから買ってみました。

届いたのを見てみるとアマゾンの画像のものではなく、記事と同じもの。
8260がついていて、Bluetooth 4.2まで対応と書いていました。


おー。よかった。
これからUWPやXamarinでBLEアプリケーションを開発していきます!

2017/08/13

global::System.Diagnostics.Debugger.Breakdeでデバッグが止まったら・・・

UWPでサンプルプログラムを作成したとき、次の下記の位置でデバッグが停止してしまいました。。。
ちなみに、環境は、
  • Windows 10 64bit
  • Visual Studio 2015 Express
  • UWPアプリケーション
  • NugetでPrism.Unityをインストール済み
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();


そこで、エラーとなっている内容を確認すると、、、
Could not load file or assembly 'System.Runtime.WindowsRuntime, Version=4.0.11.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

どうやら、WindowsRuntimeのバージョンが悪いそうです。
また、ビルドしたとき下記のWarningも出ています。
Warning        Detected package downgrade: Microsoft.NETCore.UniversalWindowsPlatform from 5.2.2 to 5.1.0
 uwp_sample (>= 1.0.0) -> Prism.Unity (>= 6.3.0) -> Prism.Windows (>= 6.3.0) -> Microsoft.NETCore.UniversalWindowsPlatform (>= 5.2.2)
 uwp_sample (>= 1.0.0) -> Microsoft.NETCore.UniversalWindowsPlatform (>= 5.1.0)            0   
そこで、NugetでMicrosoft.NETCore.UniversalWindowsPlattformのバージョンを5.1.0→5.2.2にへんこうしたら、デバッグで止まらなくなりました。
本当は最新の5.4.0にしたかったんですが、VisualStudio2017のみそうだったので、5.2.2で、

2017/07/25

Androidへファクトリーイメージをインストール

Androidのダウングレードを実施したので、その記録を残します。
 今回はNexus6をAndroid 6.0.1へダウングレードしました。

はじめに、下記URLにあるように以下の作業が必要です
  •  AndroidでのUSBデバッグの有効化
  •  WindowsへのJava, Android Studioのインストール
  •  Android StudioのSDK Managerでplatform-toolsをインストール 
  •  platform-toolsフォルダをPATHに追加する(現時点では"C:\Users\(USER_NAME)\AppData\Local\Android\sdk\platform-tools"です。)
  • ファクトリーイメージ(Nexus6のAndroid6.0.1のイメージ)をダウンロード。解凍
http://denshikousaku.net/downgrade-android-lollipop
https://plaza.rakuten.co.jp/jashi/diary/201506200000/
http://androidlover.net/android-os/android-5-0-lollipop/android-5-0-lollipop-android-4-4-4-kitkat-download.html

後は、Googleの公式にあるようにコマンドを打っていくだけです。
https://developers.google.com/android/images

まず、デバイスをPCが認識しているか確認します。下記コマンドで、デバイス名が出てくれはOKです。
adb devices

この時に、他ページでは「○○ボタンと○○ボタンを長押しして、fastbootモードで起動する」という作業をやっていますが、以下のコマンドでその作業が行えるので、通常起動のままで下記コマンドを打ってください。
adb reboot bootloader

これでfastmodeになります。
ですが、"Device is LOCKED"となっていて、ブートローダーがアンロックされていません。
下記コマンドでアンロックします。
fastboot oem unlock

//もしデバイスがNexus 5X or Nexus 6Pだったらこちら
fastboot flashing unlock

"Device is UNLOCKED"と表示が変わったと思います。
最後に、ファクトリーイメージのflash-all.batをコマンドプロンプトで叩けばOKです。


参考になったサイト
http://taka-hama.sakura.ne.jp/blog/?p=731




 

2017/02/20

WPF PrismとNyARToolKitCSで複数のマーカー位置推定

先ほど、マーカーの位置推定プログラムを書きましたが、今度は複数のマーカーの位置推定を行うプログラムです。
http://kowaimononantenai.blogspot.jp/2017/02/wpf-prismnyartoolkit.html

ファイル構成は上のサイトと同じです。

初めにViewのXamlです。これは上のサイトと全く同じです。

    
        
        

次はViewModelです。
カメラ画像を表示するために、async/awaitで非同期処理を行っています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.Commands;

using System.Threading;
using System.Windows.Media.Imaging;
using System.Numerics;  //.Net Framework 4.6以上

namespace NyARCaptureTest
{
    class MainWindowViewModel: BindableBase
    {
        NyARPositionEstimation NyAr;
        bool isTask;

        /// 
        /// Notifying Property Change
        /// 
        private WriteableBitmap bmp;
        public WriteableBitmap Bmp
        {
            get { return bmp; }
            set { SetProperty(ref bmp, value); }
        }

        /// 
        /// DelegateCommand
        /// 
        private DelegateCommand startCommand;
        public DelegateCommand StartCommand
        {
            get{ return startCommand ?? (startCommand = new DelegateCommand(Start));}
        }
        private async void Start()
        {
            NyAr.Start();

            isTask = true;
            await ShowImage();
        }

        private DelegateCommand stopCommand;
        public DelegateCommand StopCommand
        {
            get { return stopCommand ?? (stopCommand = new DelegateCommand(Stop)); }
        }
        private void Stop()
        {
            NyAr.Stop();
            isTask = false;
        }


        public MainWindowViewModel()
        {
            NyAr = new NyARPositionEstimation();
        }

        /// 
        /// Task
        /// 
        /// 
        private async Task ShowImage()
        {
            while (isTask)
            {
                if (NyAr.IsCaptureOk)
                {
                    Bmp = NyAr.GetImage();

                    Matrix4x4[] matrix;
                    bool[] isEstimateOk;
                    NyAr.GetMatrix(out matrix, out isEstimateOk);

                    if (isEstimateOk[0] == true)
                    {
                        Console.WriteLine(matrix[0]);
                    }
                }
                await Task.Delay(30);
            }
        }
    }
}




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.Threading;
using System.Numerics;  //.Net Framework 4.6以上

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 NyARCaptureTest
{
    class NyARPositionEstimation : CaptureListener
    {
        private NyARToolkitCSUtils.Capture.CaptureDevice cap;
        private String[] arCodeFile = { "patt.hiro", "patt.kanji" };
        private const String arCameraFile = "camera_para.dat";
        private NyARDetectMarker ar;
        private DsRgbRaster raster;
        private Mat img;
        private Object lockObj = new object();
        private Matrix4x4[] Matrix;

        public bool IsCaptureOk { get; private set; }


        public NyARPositionEstimation()
        {
            IsCaptureOk = false;
            Matrix = new Matrix4x4[2];
            Matrix[0] = Matrix4x4.Identity;
            Matrix[1] = Matrix4x4.Identity;

            //ARの設定
            //AR用カメラパラメタファイルをロード
            NyARParam ap = NyARParam.loadFromARParamFile(File.OpenRead(arCameraFile), 320, 240);

            //AR用のパターンコードを読み出し
            NyARCode[] code = new NyARCode[2];
            code[0] = NyARCode.loadFromARPattFile(File.OpenRead(arCodeFile[0]), 16, 16);
            code[1] = NyARCode.loadFromARPattFile(File.OpenRead(arCodeFile[1]), 16, 16);

            //計算モードの設定
            //キャプチャを作る
            /**************************************************
            このコードは、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.cap = cap;

            //ラスタを作る。
            this.raster = new DsRgbRaster(cap.video_width, cap.video_height);

            this.ar = new NyARDetectMarker(ap, code, new double[] { 80.0, 80.0 }, 2);
            this.ar.setContinueMode(false);
        }


        public void Start()
        {
            this.cap.StartCapture();
        }

        public void Stop()
        {
            this.cap.StopCapture();
        }


        public WriteableBitmap GetImage()
        {
            WriteableBitmap bmp;
            lock (lockObj)
            {
                bmp = img.ToWriteableBitmap();
            }
            return bmp;
        }
        
        public void GetMatrix(out Matrix4x4[] matrix, out bool[] isEstimateOk)
        {
            lock (lockObj)
            {
                matrix = new Matrix4x4[2];
                matrix[0] = GetDeepCopyMatrix4x4(Matrix[0]);
                matrix[1] = GetDeepCopyMatrix4x4(Matrix[1]);

                isEstimateOk = new bool[2];
                if (matrix[0].Equals(Matrix4x4.Identity))
                {
                    isEstimateOk[0] = false;
                }
                else
                {
                    isEstimateOk[0] = true;
                }

                if (matrix[1].Equals(Matrix4x4.Identity))
                {
                    isEstimateOk[1] = false;
                }
                else
                {
                    isEstimateOk[1] = true;
                }
            }
        }
        
        
        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, PixelFormat.Format32bppRgb, i_buffer);
            b.RotateFlip(RotateFlipType.RotateNoneFlipY);
            this.raster.setBuffer(i_buffer, i_buffer_len, i_sender.video_vertical_flip);

            lock (lockObj)
            {
                img = b.ToMat();
                int detectedMarkerNum = this.ar.detectMarkerLite(this.raster, 100);
                int markerId = 0;

                for (int marker = 0; marker < detectedMarkerNum; marker++)
                {
                    markerId = ar.getARCodeIndex(marker);

                    if (markerId == 0)
                    {
                        NyARDoubleMatrix44 result_mat = new NyARDoubleMatrix44();
                        this.ar.getTransmationMatrix(markerId, result_mat);
                        Matrix[0] = ConvertNyARDoubleMatrix44ToMatrix4x4(result_mat);
                        NyARSquare square = ar.getSquare(markerId);

                        var point = new OpenCvSharp.CPlusPlus.Point[4];
                        for (int i = 0; i < 4; i++)
                        {
                            point[i] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[i].x, square.sqvertex[i].y);
                        }
                        img.FillConvexPoly(point, new Scalar(0, 0, 255));
                    }

                    if (markerId == 1)
                    {
                        NyARDoubleMatrix44 result_mat = new NyARDoubleMatrix44();
                        this.ar.getTransmationMatrix(markerId, result_mat);
                        Matrix[1] = ConvertNyARDoubleMatrix44ToMatrix4x4(result_mat);
                        NyARSquare square = ar.getSquare(markerId);

                        var point = new OpenCvSharp.CPlusPlus.Point[4];
                        for (int i = 0; i < 4; i++)
                        {
                            point[i] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[i].x, square.sqvertex[i].y);
                        }
                        img.FillConvexPoly(point, new Scalar(255, 0, 0));
                    }
                }

                if (detectedMarkerNum == 1)
                {
                    if (markerId == 0)
                    {
                        Matrix[1] = Matrix4x4.Identity;
                    }
                    else if (markerId == 1)
                    {
                        Matrix[0] = Matrix4x4.Identity;
                    }
                }
                else if (detectedMarkerNum == 0)
                {
                    Matrix[0] = Matrix4x4.Identity;
                    Matrix[1] = Matrix4x4.Identity;
                }
                IsCaptureOk = true;
            }
        }

        private Matrix4x4 ConvertNyARDoubleMatrix44ToMatrix4x4(NyARDoubleMatrix44 m)
        {
            return new Matrix4x4((float)m.m00,
                                    (float)m.m01,
                                    (float)m.m02,
                                    (float)m.m03,
                                    (float)m.m10,
                                    (float)m.m11,
                                    (float)m.m12,
                                    (float)m.m13,
                                    (float)m.m20,
                                    (float)m.m21,
                                    (float)m.m22,
                                    (float)m.m23,
                                    (float)m.m30,
                                    (float)m.m31,
                                    (float)m.m32,
                                    (float)m.m33);
        }

        private Matrix4x4 GetDeepCopyMatrix4x4(Matrix4x4 m)
        {
            return new Matrix4x4(m.M11,
                                    m.M12,
                                    m.M13,
                                    m.M14,
                                    m.M21,
                                    m.M22,
                                    m.M23,
                                    m.M24,
                                    m.M31,
                                    m.M32,
                                    m.M33,
                                    m.M34,
                                    m.M41,
                                    m.M42,
                                    m.M43,
                                    m.M44);
        }
    }
}







WPF PrismとNyARToolKitでマーカー位置推定

マーカーの位置推定を行うプログラムです。
以下のことを行います。
①カメラ座標系からマーカー座標系への同時変換行列を取得(Consoleに出力)
②マーカーにグラフィックを描画して、カメラ画像を表示

 これでは、NyARToolKitCS, OpenCVSharp,Prism.MVVMを使用しています。


初めにXamlです。


    
        
        


次にViewModelです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.Commands;

using System.ComponentModel;
using System.Data;
using System.Drawing;

using System.Windows.Threading;
using System.Threading;
using System.Windows.Media.Imaging;

namespace NyARCaptureTest
{
    class MainWindowViewModel: BindableBase
    {
        NyARPositionEstimation NyAr;
        bool isTask;

        /// 
        /// Notifying Property Change
        /// 
        private WriteableBitmap bmp;
        public WriteableBitmap Bmp
        {
            get { return bmp; }
            set { SetProperty(ref bmp, value); }
        }

        /// 
        /// DelegateCommand
        /// 
        private DelegateCommand startCommand;
        public DelegateCommand StartCommand
        {
            get{ return startCommand ?? (startCommand = new DelegateCommand(Start));}
        }
        private async void Start()
        {
            NyAr.Start();

            isTask = true;
            await ShowImage();
        }

        private DelegateCommand stopCommand;
        public DelegateCommand StopCommand
        {
            get { return stopCommand ?? (stopCommand = new DelegateCommand(Stop)); }
        }
        private void Stop()
        {
            NyAr.Stop();
            isTask = false;
        }


        public MainWindowViewModel()
        {
            NyAr = new NyARPositionEstimation();
        }

        /// 
        /// Task
        /// 
        /// 
        private async Task ShowImage()
        {

            while (isTask)
            {
                if (NyAr.IsCaptureOK)
                {
                    Bmp = NyAr.GetImage();
                    Console.WriteLine(NyAr.Matrix);
                }

                await Task.Delay(30);
            }
        }
    }
}


最後にModelです。
マーカーの位置推定はNyARToolKitCSのサンプルを参考にNyARPositionEstimationクラスを作りました。
基本的に処理はこちらで行っています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ComponentModel;
using System.Data;
using System.Drawing;

using System.Drawing.Imaging;
using jp.nyatla.nyartoolkit.cs;
using jp.nyatla.nyartoolkit.cs.core;
using jp.nyatla.nyartoolkit.cs.detector;
using NyARToolkitCSUtils.Capture;
using NyARToolkitCSUtils.Direct3d;
using System.IO;

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

using System.Windows.Threading;
using System.Windows.Media.Imaging;

using System.Numerics;  //.Net Framework 4.6以上

namespace NyARCaptureTest
{
    class NyARPositionEstimation : 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 Mat Img;
        public Matrix4x4 Matrix { get; private set; }

        public bool IsCaptureOK { get; private set; }


        public NyARPositionEstimation()
        {
            IsCaptureOK = false;
            //ARの設定
            //AR用カメラパラメタファイルをロード
            NyARParam ap = NyARParam.loadFromARParamFile(File.OpenRead(AR_CAMERA_FILE), 320, 240);

            //AR用のパターンコードを読み出し 
            NyARCode code = NyARCode.loadFromARPattFile(File.OpenRead(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);
            //1パターンのみを追跡するクラスを作成
            this.m_ar = NyARSingleDetectMarker.createInstance(ap, code, 80.0);
            this.m_ar.setContinueMode(false);
        }


        public void Start()
        {
            this.m_cap.StartCapture();
        }

        public void Stop()
        {
            this.m_cap.StopCapture();
        }


        public WriteableBitmap GetImage()
        {
            return Img.ToWriteableBitmap();
        }


        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, PixelFormat.Format32bppRgb, i_buffer);

            // If the image is upsidedown
            b.RotateFlip(RotateFlipType.RotateNoneFlipY);
            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);
                Matrix = ConvertNyARDoubleMatrix44ToMatrix4x4(result_mat);

                //Console.WriteLine("Maker is found.");

                NyARSquare square = m_ar.refSquare();

                var point = new OpenCvSharp.CPlusPlus.Point[4];
                for (int i = 0; i < 4; i++)
                {
                    point[i] = new OpenCvSharp.CPlusPlus.Point(square.sqvertex[i].x, square.sqvertex[i].y);
                }
                Img.FillConvexPoly(point, new Scalar(0, 0, 255));
            }
            else
            {
                //Console.WriteLine("Maker is NOT found.");
            }

            IsCaptureOK = true;
        }

        private Matrix4x4 ConvertNyARDoubleMatrix44ToMatrix4x4(NyARDoubleMatrix44 m)
        {
            return new Matrix4x4(   (float)m.m00,
                                    (float)m.m01,
                                    (float)m.m02,
                                    (float)m.m03,
                                    (float)m.m10,
                                    (float)m.m11,
                                    (float)m.m12,
                                    (float)m.m13,
                                    (float)m.m20,
                                    (float)m.m21,
                                    (float)m.m22,
                                    (float)m.m23,
                                    (float)m.m30,
                                    (float)m.m31,
                                    (float)m.m32,
                                    (float)m.m33);
        }
    }
}



2017/02/05

WPF PrismとOpenCVSharpでWebカメラの画像表示

OpenCVSharpを使ってWebカメラの画像を取得し、WPFのImageで表示します。
プロジェクトは以下のようになっていて、View、Model、ViewModelそれぞれ1ファイルづつあります。

初めに、ViewのMainWindow.xamlです。

    
        
        



次にViewModelのMainWindowViewModel.cs。
画像の表示は別タスクにしていて、async/awaitで非同期処理を行っています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CaptureCamera.Model;

using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.Commands;
using System.Windows.Media.Imaging;

namespace CaptureCamera.ViewModel
{
    class MainWindowViewModel: BindableBase
    {
        Camera camera;
        bool isTask = true;

        public MainWindowViewModel()
        {
        }

        /// 
        /// Change Property
        /// 
        private WriteableBitmap bmp;
        public WriteableBitmap Bmp
        {
            get { return bmp; }
            set { SetProperty(ref bmp, value); }
        }


        /// 
        /// DelegateCommand
        /// 
        private DelegateCommand startCaptureCommand;
        public DelegateCommand StartCaptureCommand
        {
            get { return startCaptureCommand ?? (startCaptureCommand = new DelegateCommand(StartCapture)); }
        }
        private async void StartCapture()
        {
            camera = new Camera();
            await ShowImage();
        }

        private DelegateCommand stopCaptureCommand;
        public DelegateCommand StopCaptureCommand
        {
            get { return stopCaptureCommand ?? (stopCaptureCommand = new DelegateCommand(StopCapture)); }
        }
        private void StopCapture()
        {
            isTask = false;
        }


        /// 
        /// Task
        /// 
        /// 
        private async Task ShowImage()
        {
            while (isTask)
            {
                Bmp = camera.Capture();
                if (Bmp == null) break;

                await Task.Delay(30);
            }
        }
    }
}


最後にModelのCamera.cs。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Win32;
using System.Windows.Media.Imaging;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;

namespace CaptureCamera.Model
{
    class Camera
    {
        VideoCapture capture;
        Mat frame;

        public Camera()
        {
            capture = new VideoCapture(0);
            if (!capture.IsOpened())
                throw new Exception("capture initialization failed");
            frame = new Mat();
        }

        public WriteableBitmap Capture()
        {
            capture.Read(frame);
            if (frame.Empty())
                return null;

            return frame.ToWriteableBitmap();
        }
    }
}


WPF PrismとOpenCVSharpを使って画像の表示

先ほど、Prismを使って画像を表示するWPFアプリケーションを作成しました。

○○○○に怖いものなんてない!!: WPF(Prism)で画像の表示
http://kowaimononantenai.blogspot.jp/2017/02/wpfprism.html

画像処理等にはOpenCVSharpを使用することが多いので、
画像入力はOpenCVSharpを使用して、Matで管理するサンプルプログラムに変更しました。
でも、画像の表示はWPFのImageで表示しています。

プログラムは同じようにView,ViewModel,Modelに分けて管理しています。

まずはDisplayImageWindow.xamlです。

    
        
        



次はDisplayImageWindowViewModel.cs。
さきほどと違うのはBitmapImageからWriteableBitmapに変更になったところです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.Commands;
using DisplayImage.Model;

using System.Windows.Media.Imaging;

namespace DisplayImage.ViewModel
{
    class DisplayImageWindowViewModel: BindableBase
    {
        public DisplayImageWindowViewModel()
        {
            Displayer = new ImageDisplayer();
        }

        ImageDisplayer Displayer;

        //=================
        //Change Property
        //=================
        private string filePath;
        public string FilePath
        {
            get { return filePath; }
            set { SetProperty(ref filePath, value); }
        }

        private WriteableBitmap bmp;
        public WriteableBitmap Bmp
        {
            get { return bmp; }
            set { SetProperty(ref bmp, value); }
        }

        //=================
        //DeligateCommand
        //=================
        private DelegateCommand fileOpenCommand;
        public DelegateCommand FileOpenCommand
        {
            get { return fileOpenCommand ?? (fileOpenCommand = new DelegateCommand(FileOpen)); }
        }
        public void FileOpen()
        {
            Displayer.FileOpen();

            FilePath = Displayer.FilePath;
            Bmp = Displayer.GetImage();
        }
    }
}


最後にImageDisplayer.csです。
OpenCVSharpで画像を入力した後、表示するときだけWriteableBitmapに変換して渡します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Win32;
using System.Windows.Media.Imaging;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;

namespace DisplayImage.Model
{
    class ImageDisplayer
    {
        public ImageDisplayer()
        {
        }

        public string FilePath { get; set; }
        private Mat Img;

        public void FileOpen()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Open Image File.";
            dlg.Filter = "Image File|*.jpg";

            if (dlg.ShowDialog() == true)
            {
                FilePath = dlg.FileName;
                Img = new Mat(FilePath);
            }
        }

        public WriteableBitmap GetImage()
        {
            return Img.ToWriteableBitmap();
        }
    }
}





WPF(Prism)で画像の表示

Prismを利用したWPFアプリケーションで、選択した画像を表示するプログラムを作成します。

実際に作ったのは下図で、このような機能があります。
①Openボタンでファイル選択ダイヤログが開き、jpgファイルを選択する
②TextBoxにファイルのパスが表示される
③画像が下に表示される


まず、NuGetで「Prism.MVVM」をインストールしておいてください。
プロジェクトでは下図のように3つのフォルダでMVVMごとに管理しています。


 まず、DisplayImageWindow.xamlは以下のようになります。

    
        
        

次に、DisplayImageWindowViewModelは以下のようになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.Commands;
using DisplayImage.Model;

using System.Windows.Media.Imaging;

namespace DisplayImage.ViewModel
{
    class DisplayImageWindowViewModel: BindableBase
    {
        public DisplayImageWindowViewModel()
        {
            Displayer = new ImageDisplayer();
        }

        ImageDisplayer Displayer;

        //=================
        //Change Property
        //=================
        private string filePath;
        public string FilePath
        {
            get { return filePath; }
            set { SetProperty(ref filePath, value); }
        }

        private BitmapImage bmp;
        public BitmapImage Bmp
        {
            get { return bmp; }
            set { SetProperty(ref bmp, value); }
        }

        //=================
        //DeligateCommand
        //=================
        private DelegateCommand fileOpenCommand;
        public DelegateCommand FileOpenCommand
        {
            get { return fileOpenCommand ?? (fileOpenCommand = new DelegateCommand(FileOpen)); }
        }
        public void FileOpen()
        {
            Displayer.FileOpen();

            FilePath = Displayer.FilePath;
            Bmp = Displayer.Bmp;
        }
    }
}


最後にImageDisplayerです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Win32;
using System.Windows.Media.Imaging;

namespace DisplayImage.Model
{
    class ImageDisplayer
    {
        public ImageDisplayer()
        {
        }

        public string FilePath { get; set; }
        public BitmapImage Bmp;

        public void FileOpen()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Open Image File.";
            dlg.Filter = "Image File|*.jpg";

            if (dlg.ShowDialog() == true)
            {
                FilePath = dlg.FileName;

                Bmp = new BitmapImage();
                Bmp.BeginInit();
                Bmp.UriSource = new Uri(FilePath);
                Bmp.EndInit();

            }
        }
    }
}