Loading [MathJax]/extensions/tex2jax.js

2015-02-22

Arduino:Bluetooth 4.0 Low Energy BLEシールドを入手しましたが、、、


表題のとおり、ArduinoにBluetoothシールドを入手しましたが、いろいろトラブっている最中なので作業録です。

対応するArduino IDEは1.0.6まで
まず、これにハマりました。ライブラリを追加してコンパイルすると、
C:\Program Files (x86)\Arduino\libraries\RBL_nRF8001\RBL_nRF8001.cpp:25:23: error: setup_msgs causes a section type conflict with __c
みたいなエラーがでます。現在、Arduino IDEは1.6が最新ですが、コレじゃダメ。なんと、1.06までしか対応してないようです(公式の回答をネットで目にしました)。で、1.06をダウンロードしてコンパイルしたら見事成功。iPhoneアプリでも接続を確認しました。

Bluetooth 4.0 Low Energy ってのが曲者
Low Energy...最新の低電力版ってことだね。。と安易に考えておりましたが、これは対応機種が限定されるようです。AndroidやiOSでも最新版が必要なのはわかるんですが、Windowsでも8.1以上が必要らしいです。手元にWindows7のノートPCがあって、検索にひっかかるけどコネクションできない、、、というよくわからない状況で、プログラムがおかしいのか、デバイスが4.0対応じゃないのか、、と思ったりしたのですが、Win8.1以上とは、、、とりあえずは旧式のBluetoothボードにした方がいいかもしれません。


2015-02-21

Arduino:PCからの入力に合わせてLEDをON・OFFする 〜USB接続編〜




新規立ち上げの研究テーマでArduinoを利用することになったので、C#でUSBを通してArduinoを制御するプログラムを書いてみました。具体的には、USBで接続されたArduino本体のLEDを、PC側のクライアントソフトでON・OFFするというものです。
Arduino側のプログラム(スケッチというらしい)は下記のようになります。C#のプログラムは書くまでもない(シリアルポートに対してWriteするだけでよい)ので省略します。
void setup() {
// initialize digital pin 13 as an output.
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
if(Serial.available()>0){
char msg = Serial.read();
switch(msg){
case 'h':
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
break;
case 'l':
digitalWrite(13, LOW);
break;
}
}
}


C#にてシリアルポートからの通信を受信する

C#でシリアルポートからの通信結果を受信するサンプルです。簡単ですね。
static void Main(string[] args){
SerialPort sPort = new SerialPort("COM3");
sPort.BaudRate = 9600;
sPort.Open();
while (true){
string myData = sPort.ReadLine();
Console.WriteLine(myData);
}
}


2015-02-19

Kinect v2にてMultiSourceFrameを利用する

Kinectプログラミングでは、v1ではAllFrameReadyイベントを用いて各種フレームを一括で処理するのが便利ですが、v2でも同様のイベントがあります。が、名前が変わっており、処理の仕方やメソッド名も違うので注意が必要です。具体的には以下のようになります。
private void Window_Loaded(object sender, RoutedEventArgs e){
KinectSensor kinect = KinectSensor.GetDefault();
if (kinect != null){
MultiSourceFrameReader multiReader = kinect.OpenMultiSourceFrameReader(FrameSourceTypes.Color | FrameSourceTypes.Depth|FrameSourceTypes.Body);
multiReader.MultiSourceFrameArrived += multiReader_MultiSourceFrameArrived;
kinect.Open();
}
}
void multiReader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e){
MultiSourceFrame reference = e.FrameReference.AcquireFrame();
// Color
using (ColorFrame myColorFrame = reference.ColorFrameReference.AcquireFrame())
using (DepthFrame myDepthFrame = reference.DepthFrameReference.AcquireFrame())
using (BodyFrame myBodyFrame = reference.BodyFrameReference.AcquireFrame()){
// ここにいろいろ書いていく
}


2015-02-18

NuGetを利用したOpenCVSharpのインストール

※OpenCVSharp3用に少し記事を書き換えました(2016/09/30)

OpenCVSharp3のインストールは、NuGetを利用するのが一番です。そのほうが、実行マシンでのOpenCVのバージョンの変化に対応しやすいです。下記はその手順です。なお、環境は、Visual Studio 2013を想定しています。

1.Nugetを利用したインストール

(1)NuGetマネージャーの起動
プロジェクトを右クリックして「NuGetパッケージの管理」を選択してください。


(2)OpenCVSharp3の検索とインストール

左のサイドバーからオンライン → すべて を選択したあと、右上の検索ウィンドウに「OpenCVSharp3」と入力してください(フルに歌入力しないと検索に引っかからないです)。“without DLLs”というのは、OpenCV本体のDLLを含まないという意味ですが、OpenCVSharp3はOpenCV本体とのバージョンの差異で動かなくなりますので、DLLを含んだもの(without DLLsと書いていないやつ)を選んで下さい。



2.サンプルを試す
下記のソースコードが実行できればOKです。testの画像は別途、どこかから用意してください。

/*
* 以下、OpenCVSharp3対応です
*/
//画像ファイル読み込み
Mat img = new Mat(@"C:\Users\ochi\Documents\temp\test.png");
Mat img2 = img.Clone();
Mat img3 = img.Clone();
//トリミング(ROI)
img3 = img3[new OpenCvSharp.Rect(200, 200, 180, 200)];
//表示
Cv2.ImShow("img", img);
Cv2.ImShow("img3", img3);
//反転
Cv2.BitwiseNot(img2, img2);
Cv2.ImShow("img2", img2);
Cv2.WaitKey();
注意事項
プロジェクトのプロパティで下記の設定を確認してください。
  • 対象のフレームワークを .NET Framework4にする
  • 64bit版のOpenCVを利用する場合は、プラットフォームターゲットを64bitにする


2015-02-17

Kinect v2にて骨格情報を取ってくる

Kinect v2にて骨格情報を取ってくる方法です。クラス名に変更がありますが、やり方はほぼ同じですね。
BodyFrameReader bodyFrameReader;
Body[] bodies;
private void Window_Loaded(object sender, RoutedEventArgs e){
KinectSensor kinect = KinectSensor.GetDefault();
if(kinect!=null){
kinect.Open();
// Bodyを入れる配列を作る
bodies = new Body[kinect.BodyFrameSource.BodyCount];
// ボディーリーダーを開く
bodyFrameReader = kinect.BodyFrameSource.OpenReader();
bodyFrameReader.FrameArrived += bodyFrameReader_FrameArrived;
}
void bodyFrameReader_FrameArrived(object sender, BodyFrameArrivedEventArgs e){
using (var bodyFrame = e.FrameReference.AcquireFrame()) {
if (bodyFrame == null) {
return;
}
// ボディデータを取得する
bodyFrame.GetAndRefreshBodyData(bodies);
//認識しているBodyに対して
foreach (var body in bodies.Where(b => b.IsTracked)) {
//左手のX座標を取得
System.Diagnostics.Debug.WriteLine("X="+body.Joints[JointType.HandLeft].Position.X);
}
}
}


Kinect v2にて人物領域を取得する

Kinect v2ではv1よりフレームワークが変わっているところが所々あります。今回の話は、BodyFrame(人物領域)の取得について。v2からは人物領域だけを格納するBodyFrameというのが新たに用意されました。v1ではDepthFrameからその情報の一部として取得していました。人物だけを表示するには、今までは自前のプログラミングが必要でしたが、その手間がなくなりますね。
KinectSensor kinect;
BodyIndexFrameReader bodyIndexFrameReader;
FrameDescription bodyIndexFrameDesc;
byte[] bodyIndexBuffer;
WriteableBitmap bodyIndexColorImage;
Int32Rect bodyIndexColorRect;
int bodyIndexColorStride;
int bodyIndexColorBytesPerPixel = 4;
Color[] bodyIndexColors;
private void Window_Loaded(object sender, RoutedEventArgs e){
kinect = KinectSensor.GetDefault();
if(kinect!=null){
kinect.Open();
bodyIndexFrameDesc = kinect.DepthFrameSource.FrameDescription;
bodyIndexBuffer = new byte[bodyIndexFrameDesc.LengthInPixels];
//下記は人物領域を表示する際に使う
bodyIndexColorImage = new WriteableBitmap(bodyIndexFrameDesc.Width, bodyIndexFrameDesc.Height, 96, 96, PixelFormats.Bgra32, null);
bodyIndexColorRect = new Int32Rect(0, 0, bodyIndexFrameDesc.Width, bodyIndexFrameDesc.Height);
bodyIndexColorStride = (int)(bodyIndexFrameDesc.Width * bodyIndexColorBytesPerPixel);
bodyIndexColorBuffer = new byte[bodyIndexFrameDesc.LengthInPixels * bodyIndexColorBytesPerPixel];
//
bodyIndexFrameReader = kinect.BodyIndexFrameSource.OpenReader();
//フレーム到着時のイベント設定
bodyIndexFrameReader.FrameArrived += BodyIndexFrameReader_FrameArrived;
}
}
void BodyIndexFrameReader_FrameArrived(object sender, BodyIndexFrameArrivedEventArgs e){
using (var bodyIndexFrame = e.FrameReference.AcquireFrame()){
if (bodyIndexFrame == null){
return;
}
// ボディインデックスデータをバイト配列に格納する
bodyIndexFrame.CopyFrameDataToArray(bodyIndexBuffer);
for (int i = 0; i < bodyIndexBuffer.Length; i++){
//人物領域のインデックス番号を取得
var index = bodyIndexBuffer[i];
//非人物領域は255
if (index != 255){
/** 人物領域に対して何かする
}
}
}


2015-02-16

kinect v2セットアップ ~PCが対応しているか確認しよう~

ずいぶんネタが古くなりましたがKinect v2のセットアップについてです。製品版がでてずいぶん時間も経ったので、インストールも楽になったかな~とかよくわからん期待をしたのですが甘かったです。。。かなり手間取りました。以下、注意事項です。

マシンの準備
下記のスペックのPCが必要です。
  • Windows8.1以上
  • CPU:2.66 GHz 以上のデュアルコア、64 ビット (x64) プロセッサ
  • GPU:DirectX 11 対応グラフィックス カード
  • 接続ポート:USB 3.0
  • メモリ:2GB RAM
メモリとCPUのスペックはα版と比べると下がりました。しかし、問題は残る2つ。USB3.0と:DirectX 11 対応グラフィックス カードが厄介でした。

マシンスペックの確認方法
USB3.0というのは、USBの口が青色になっていると思います。これで確認できます。しかし、DirectX 11 対応グラフィックス カードというのがわからない。。。これを確認するには、

  1. Kinect v2 SDKをインストール
  2. SDK Browser2.0を起動(SDKに同梱されインストールされてます)
  3. Kinect Configuration Verifier を起動する
というように、まずはSDKをインストールし、Kinect Configuration Verifier で確認するのが一番です。


Browserの最初のメニューにあります。


チェックがすべて入っていればOK(KinectをつなげてないのでConnectedは×でOK)。
ここでよく、USBとかGraphic Processorが×になるんですよね~。そうなったら残念。ボードを追加購入しましょう。

P.S
なお、上記がクリアしていても、Face系のプログラムが動かない事象が起きました。その際は、Graphic カードのドライバを最新にして解決しました。


2015-02-11

Kinect v2にてRGBカメラを表示する

先行して入手したものの、全く手をつけていなかったKinect v2での開発をはじめました。とりあえずRGBカメラの表示です。噂通り、書き方が変わっているとことが多いですね。ただ、最終的にbyte[]に格納してWriteablebitmapにすればいいというのは従来通りなので、全面修正にはならないでしょう。なお、RGBカメラを表示後、数秒後にプログラムが落ちる事象が置きましたが、win8.1のバグのようです。とりあえず、ガーベージコレクションを強制実行することで回避できます。

WriteableBitmap colorBitmap;
byte[] ColorImagePixelData ;
Int32Rect colorImageBitmapRect;
FrameDescription myColorFrameDescripton;
public MainWindow(){
InitializeComponent();
KinectSensor kinect = KinectSensor.GetDefault();
if (kinect != null){
ColorFrameReader colorframereader = kinect.ColorFrameSource.OpenReader();
myColorFrameDescripton = kinect.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
ColorImagePixelData = new byte[myColorFrameDescripton.Width * myColorFrameDescripton.Height * myColorFrameDescripton.BytesPerPixel];
colorBitmap = new WriteableBitmap(myColorFrameDescripton.Width, myColorFrameDescripton.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
colorframereader.FrameArrived+=colorframereader_FrameArrived;
kinect.Open();
}
}
void colorframereader_FrameArrived(object sender, ColorFrameArrivedEventArgs e){
using( ColorFrame myColorFrame= e.FrameReference.AcquireFrame()){
if(myColorFrame!=null){
myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra);
colorImageBitmapRect = new Int32Rect(0, 0, myColorFrameDescripton.Width, myColorFrameDescripton.Height);
image1.Source = BitmapSource.Create(myColorFrameDescripton.Width, myColorFrameDescripton.Height, 96, 96,PixelFormats.Bgra32, null, ColorImagePixelData, myColorFrameDescripton.Width * (int)myColorFrameDescripton.BytesPerPixel);
}
GC.Collect(); //Win8.1のバグ?らしいのでこのおまじないを書いておくこと }
}


2015-02-02

OpenCVSharpにてテンプレートマッチングを行う

OpenCVSharpにて、テンプレートマッチングを行う方法です。Mat形式に対応しています。

try {
Mat result = new Mat(mat.Height - matTemplate.Height + 1, mat.Width - matTemplate.Width + 1, MatType.CV_8UC1);
Cv2.MatchTemplate(mat, matTemplate, result, MatchTemplateMethod.CCoeff);
OpenCvSharp.CPlusPlus.Point minPoint = new OpenCvSharp.CPlusPlus.Point();
OpenCvSharp.CPlusPlus.Point maxPoint = new OpenCvSharp.CPlusPlus.Point();
Cv2.MinMaxLoc(result, out minPoint, out maxPoint);
Mat img = mat.Clone();
Cv2.Rectangle(img, rect, new OpenCvSharp.CPlusPlus.Scalar(0, 0, 255), 2);
Cv2.Resize(img, img, new OpenCvSharp.CPlusPlus.Size(), 0.3, 0.3, Interpolation.Lanczos4);
Cv2.ImShow("result", img);
} catch (OpenCvSharp.OpenCVException ee) {
System.Diagnostics.Debug.WriteLine(ee.ErrMsg);
}