2013年6月27日木曜日

Node.jsからローカルのSQLServerに接続

最近はNode.jsとDB接続に関して色々調べています。
Node.jsと組み合わせるDBはNosql系のDBが多いですが、今回はSQLServerでやってみました。

MS純正のNode用ドライバは以前から提供されているのですが、日本語での情報がほとんどないため結構苦労しました。

今回はHyper-V上のWindows7にSQLServer2012ExpressとNode.jsをインストールしてみました。

環境:
・Windows7 Pro SP1 32bit
・SQLServer 2012 Express x86版
・Node.js v0.8.25 32bit

その他
・Express 3.3.0 + ejs

また node-sqlserverのコンパイルに必要なのが
・Visual C++ 2010 Express
・Python 2.7

となります。


導入手順

1.Node.jsのダウンロードとインストールをします。今回は0.8系の最新版を選択しました。
  (最新安定版の10.0系ではnode-sqlserverがコンパイルできませんでした。)

2.Visual C++ 2010 ExpressSQLServer2012Expressをダウンロードして、インストールします。
  SQLServerはネットワーク接続できるようにファイアウォール等の設定をしています。

3.Python2.7をダウンロードしてインストールします。

4.SQLServerに「test」データベースを作成し、「T_M商品」テーブルを作成します。
  内容は下の図を参照してください。データも適当に入れておきます。
  



5.C:\に「node」フォルダを作成し、この中にアプリケーションを配置するようにします。

6.Node.jsコマンドプロンプトを起動してからC:\nodeフォルダに移動します。

7.コマンドプロンプトでc:\node> npm install -g express と入力してExpressをインストールします。

8.c:\node> express -e test と入力してtestフォルダにアプリケーションの雛形を作成します。
  testフォルダには以下のように雛形が作成されます。
  

9.package.jsonファイルをエディタで以下のように編集します。

-------------------------------------------------------- 
{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.3.0",
    "ejs": "*",
    "node-sqlserver": "*" <------------赤字部分を追加
  }
}
--------------------------------------------------------
このときファイルの文字コードに気をつけましょう。UTF-8で保存しておかないと正常に動作しない可能性があります。以下すべてのファイルの文字コードがUTF-8になるようにしてください。

10.コマンドプロンプト上でtestフォルダに移動してから c:\node\test> npm install と入力する
   と先ほどのpackage.jsonの内容にしたがってインストールが行われます。このとき途中で
   黄色のワーニングメッセージが出るかもしれませんが、コンパイル環境が問題なければ
   そのまま問題なく終了します。

11.問題なくインストールができるとtestフォルダにはnode_modulesフォルダが追加されています。
   

12.node_modules>node-sqlserver>build>Releaseフォルダ内のsqlserver.nodeファイルを
   node_modules>node-sqlserver>libフォルダ内にコピーします。

13.testフォルダにあるapp.jsファイルを以下のように編集します。

途中から
----------------------------------

app.get('/', routes.index);
app.get('/users', user.list);
app.post('/',routes.index);  <-----赤字の部分を追加

----------------------------------
以下は変更なし


14.test>routesフォルダにあるindex.jsファイルを以下のように編集します。

-------------------------------------------------------------------------------
exports.index = function(req, res){
if (req.body.code) {
var sql=require('node-sqlserver');
var cn_str="Driver={SQL Server Native Client 11.0};Server=(local);Database=test;Uid=ユーザー名;Pwd=パスワード;";
sql.query(cn_str,"select * from T_M商品 where 商品コード='" + req.body.code + "'",function(err,rst) {
if (err) {
res.render('index', { title: 'ERROR' });
console.log(err);
}
res.render('index2',{ title: 'Result',
    rst: rst
});
});
}
else {
res.render('index', { title: '検索' });
}
};
-------------------------------------------------------------------------------


15.test>viewsフォルダにあるindex.ejsファイルを以下のように編集します。

-------------------------------------------------------------------------------
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>検索</h1>
      
      <form method="POST" action="/">
        コード検索: <input type="text" name="code" size="50">
        <input type="submit" value="検索実行">
      </form>
  </body>
</html>
-------------------------------------------------------------------------------


16.test>viewsフォルダにindex2.ejsファイルを以下の内容で追加します。

-------------------------------------------------------------------------------
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
 
    <h1>Data</h1>
 
<form method="POST" action="/">
        コード検索: <input type="text" name="code" size="50">
        <input type="submit" value="検索実行">
</form>

<P>

<table border="1">
 <tr>
<th>商品コード</th>
<th>商品名</th>
<th>標準価格</th>
 </tr>

 <% for(var i=0;i<rst.length;i++){ %>
<tr>
 <td> <%= rst[i]['商品コード'] %> </td>
 <td> <%= rst[i]['商品名'] %> </td>
 <td> <%= rst[i]['価格'] %> </td>
</tr>
 <% } %>

</table>
  </body>
</html>
-------------------------------------------------------------------------------


17.アプリケーションを動かしてみます。コマンドプロンプトでc:\node\testフォルダに移動して
   c:\node\test> node app.jsと入力します。
   問題がなければ「Express server listeng on port 3000」と表示されます。


18.ブラウザで「http://localhost:3000/」にアクセスすると以下のように表示されます。


19.試しにコードを入力して検索を実行すると以下のような結果になりました。



まだSelect文のテストしかしていませんが、このようにNode.js+SQLServerの組み合わせでアプリケーションが作成できました。

Node.jsはまだまだ勉強中なのでたいしたサンプルではないですが、少しでも参考になればと思います。


2013年6月26日水曜日

2013年2月14日木曜日

LocalDBをVBAから使ってみる

久しぶりの投稿です。

しばらくKinectさわっていません。
なぜかHoGの投稿に定期的にアクセスがあります。どうしてなのかな?

さて、今回はSQLServer2012から新たに追加になったLocalDBについてです。

SQL Server2012Expressもほとんど同じですが、スタンドアローン環境で使うならLocalDBの方が手軽に使えそうです。

ただ、色々なサイトで解説はあるんですが、VBAでの解説があまりないようです。

試しにExcel2013でADO+NativeClientで接続してみようとすると、最初はうまく接続できませんでした。


最初に書いたコードです。

-----------------------------------------------------------------------------------------------------------
Sub DB接続()

Dim cn As New ADODB.Connection

cn.ConnectionString = "provider=sqlncli11;server=(localdb)\v11.0;database=test;integrated security=true;DataTypeCompatibility=80;MARS Connection=True"

cn.Open

Dim rs As New ADODB.Recordset

rs.Open "select * from T_商品", cn, adOpenStatic, adLockReadOnly

If rs.BOF And rs.EOF Then

Else
Range("A1").Select
ActiveCell.CopyFromRecordset rs
End If

rs.Close
Set rs = Nothing

End Sub
-----------------------------------------------------------------------------------------------------------
(あらかじめ既定のインスタンスにtestデータベースを作成して、T_商品テーブルを追加しています。)

この場合コネクションを開いた時点でエラーが発生しました。

色々試した結果は

「integrated security=true」を「integrated security=SSPI」に変更すれば正常に動作しました。

通常TrueでもADO.NETなどは動くようなのですが・・・・

まぁ、これでEXCELやACCESSでもLocalDBが利用できそうです。

あとLocalDBはSQLOLEDBプロバイダは使えないみたいです。

2012年9月13日木曜日

KINECTサンプル(C#) HoGを使った人認識

今回はちょっと難しい(自分でも仕組みを全部理解できていません)サンプルです。
内容はSUBARUのEyeSightみたいに人物(EyeSightでは人物以外の物体も認識していますが)を認識するプログラムです。
もともとはFaceBookで知り合いが人認識できないかなという話題から始まって、たしかOpenCVにサンプルがあったことを思い出したので、それを参考に作ってみました。(最終的に参考にしたのはOpenCVSharpのサンプルプログラムですけど)

ではサンプルです。

まず、参照設定ですが、以前のOpenCVサンプルで追加した参照以外に今回は「OpenCvsharp.CPlusPlus」を追加してください。あと「OpenCvSharpExtern.dll」をプロジェクトにコピーして、コピーしたファイルプロパティ内の「出力ディレクトリにコピー」を「常にコピーする」に変更してください。


MainWindow.xaml
<Window x:Class="Kinect_HoG.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="519" Width="662">
    <Grid>
        <Image Height="480"  Name="image1" Stretch="Uniform"  Width="640" />
        <Canvas Height="480" HorizontalAlignment="Left" Name="canvas1" VerticalAlignment="Top" Width="640" />
    </Grid>
</Window>

イメージコントロールとキャンバスコントロールを重ねて配置しています。


MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using System.Drawing;
using Microsoft.Kinect;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using OpenCvSharp.CPlusPlus;
using CPP = OpenCvSharp.CPlusPlus;

namespace Kinect_HoG
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private KinectSensor kinect;
        private byte[] colorPixel;
        private IplImage CvImg;
        private WriteableBitmap srcImg;
        private Int32Rect bitmapRect;

        public MainWindow()
        {
            InitializeComponent();

            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTがみつかりません。");
                Close();
            }

            kinect = KinectSensor.KinectSensors[0];

            kinect.ColorStream.Enable();
            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(kinect_ColorFrameReady);

            kinect.Start();

            //カラー画像用
            srcImg=new WriteableBitmap(kinect.ColorStream.FrameWidth,kinect.ColorStream.FrameHeight,96,96,PixelFormats.Rgb24,null);
            bitmapRect =new Int32Rect(0,0,kinect.ColorStream.FrameWidth,kinect.ColorStream.FrameHeight);

        }

        void kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    colorPixel = new byte[colorFrame.PixelDataLength];
                    colorFrame.CopyPixelDataTo(colorPixel);

                    //カラーイメージ表示
                    srcImg.WritePixels(bitmapRect, CvtBGR32toRGB24(colorPixel),srcImg.BackBufferStride, 0);
                    image1.Source = srcImg;

                    //10フレームごとにHoG処理
                    if (colorFrame.FrameNumber % 10 == 0)
                    {
                        Hog(srcImg);
                    }
                }
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="srcImg"></param>
        private void Hog(WriteableBitmap srcImg)
        {
            //画像をMat配列に読み込み
            CPP.Mat CvImg = new CPP.Mat(srcImg.ToIplImage());
          
            //HoG検出器の準備
            CPP.HOGDescriptor hog = new CPP.HOGDescriptor();
            //人物検出用分類器の準備
            hog.SetSVMDetector(CPP.HOGDescriptor.GetDefaultPeopleDetector());
            //人物検出の実行(パラメーターは元のサンプルのまま)
            CvRect[] found = hog.DetectMultiScale(CvImg, 0, new CvSize(8, 8), new CvSize(24, 16), 1.05, 2);

            //人物を認識したときはキャンバスに矩形を表示する
            //キャンバスのクリア
            canvas1.Children.Clear();

            //検出時のみ矩形を描画
            if (found.Length !=0)
            {
                foreach (CvRect rect in found)
                {
                    canvas1.Children.Add(new System.Windows.Shapes.Rectangle()
                    {
                        Margin = new Thickness(rect.X + (int)Math.Round(rect.Width * 0.1), rect.Y + (int)Math.Round(rect.Height * 0.1), 0, 0),
                        Stroke = new SolidColorBrush(Colors.Red),
                        StrokeThickness = 3,
                        Width = (int)Math.Round(rect.Width * 0.8),
                        Height = (int)Math.Round(rect.Height * 0.8)
                    });
                }
            }
        }

        /// <summary>
        /// BGR32からRGB24に変換
        /// </summary>
        /// <param name="pixels"></param>
        /// <returns></returns>
        private byte[] CvtBGR32toRGB24(byte[] pixels)
        {
            var bytes = new byte[pixels.Length / 4 * 3];
            for (int i = 0; i < pixels.Length / 4; i++)
            {
                bytes[i * 3] = pixels[i * 4+2];
                bytes[i * 3 + 1] = pixels[i * 4+1];
                bytes[i * 3 + 2] = pixels[i * 4];
            }

            return bytes;
        }
    }
}
カラーイメージを表示している所はRGBサンプルとほぼ同じです。
Hog関数でカラーイメージをOpenCVを利用して処理しています。
カラーイメージ内で人を認識できた結果は矩形座標となるので、それを元にキャンバスコントロールに矩形を描画しています。
Hog関数自体はWritableBitmap形式のデータを与えれば動作するのでちょっと変更すればKINECT以外のデータ(静止画とかWEBカメラの映像イメージ)も処理できます。

人認識のアルゴリズムについては理解できていないところが多いですが、赤字の部分ですべての処理ができるようです。認識精度などはパラメーターを変更すればあげられるかもしれません。

HoGを使った処理ですがやはり相当重いようです。使っているPCはCorei7-2600Kですが、動作中はすべてのコアの使用率が軒並み50%以上になりました。
30FPSで処理するとまともに画像が表示されません。
C++でプログラムを記述するほうがいいのかもしれませんね。(HoG処理自体C++のインターフェイス向けなので)



2012年9月9日日曜日

KINECTサンプル(C#) OpenCV for SDK1.5

今日のサンプルはOpenCVを使っての初歩的な画像処理を行います。
KINECTそのものはあくまでもセンサーなので、受け取ったデータはPCで処理をしなければいけません。その中でメインはやはり画像処理になってくるのでしょうが、Windows自体は画像処理は得意な方ではありません。そこで外部ライブラリを利用することになります。よく使われているのがOpenCVというライブラリになります。
OpenCVはもともとC++およびC言語向けとしてプログラミングインターフェイスを公開しているので.NetFrameworkからの利用は難しくなります。そこでOpenCVSharpというラッパーライブラリを利用することにします。

まずはOpenCVのインストールです。

現在OpenCVの最新バージョンは2.4.2(2012/09/09現在)となりますが、少し前のバージョン2.3.1を使います。
http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.3.1/より「OpenCV-2.3.1-win-superpack.exe」をダウンロードしてください。
ダウンロードしたファイルを解凍すると、opencvフォルダができますので、好きな場所にコピーします。今回はC:\にコピーしました。
次にシステム環境変数のPathを設定をします。ここでは使っているOSの種類やOpenCVの種類によって指定するPathが変わるのですが、今回は32bit向けの設定にします。(OSが64ビットでも動きます。)
「コンピュータ」のプロパティを開き、「システムの詳細設定」>「詳細設定」タブ>「環境変数」ボタンを押します。システム環境変数の「Path」の選び編集ボタンを押します。変数値の一番最後に「c:\opencv\build\x86\vc10\bin;c:\opencv\build\common\tbb\ia32\vc10」と2つのパスを追加します。かならず現在の変数値の最後に追加するようにしてください。誤ってほかの箇所を変更してしまうと動かなくなるアプリケーションが出るかもしれません。また追加する際にパスの区切りである「;」(セミコロン)を忘れずにつけましょう。
以上でOpenCVの設定は終わりです。

続いてOpenCVSharpの設定です。
http://code.google.com/p/opencvsharp/の左メニューの「Downloads」から「OpenCvSharp-2.3.1-x86-20120519.zip」をダウンロードして適当な場所に解凍します。
このままでもいいのですが、解凍したフォルダ内のDLLと「XmlDoc-Japanese」内のファイルを同一フォルダにまとめておくと、プログラム入力中に日本語でツールチップが表示されるので便利です。

ではサンプルプログラムです。
サンプルではKINECTのカラーイメージとOpenCVでCannyを用いた2値化画像を同時に表示しています。

MainWindow.xaml
------------------------------------------------------------------------------

<Window x:Class="KinectOpenCV.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignWidth="1308" SizeToContent="WidthAndHeight" d:DesignHeight="519">
    <Grid>
        <Image Height="480" HorizontalAlignment="Left"  Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="640" />
        <Image Height="480" HorizontalAlignment="Left" Margin="646,0,0,0" Name="image2" Stretch="Fill" VerticalAlignment="Top" Width="640" />
    </Grid>
</Window>
------------------------------------------------------------------------------
イメージコントロールを2つ横に並べて配置しています。



参照設定がいくつか必要になります。
「参照設定」>「参照の追加」の「.NET」タブから「Microsoft.Kinect」と「System.Drawing」を追加してください。次に参照タブから先ほどOpenCVSharpを保存したフォルダを選択して、「OpenCvSharp.dll」と「OpenCvSharp.Extensions.dll」を選択してください。


MainWindow.xaml.cs
------------------------------------------------------------------------------

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

using System.Drawing;

using Microsoft.Kinect;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace KinectOpenCV
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private KinectSensor kinect;
        private WriteableBitmap srcImg;
        private WriteableBitmap distImg;
        private Int32Rect bitmapRect;
        private IplImage CvImg;
        private IplImage CvGrayImg;
        private IplImage CannyImg;

        /// <summary>
        ///
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTがみつかりません。");
                Close();
            }

            kinect = KinectSensor.KinectSensors[0];

            kinect.ColorStream.Enable();

            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(kinect_ColorFrameReady);

            kinect.Start();

            //OpenCV用
            srcImg=new WriteableBitmap(kinect.ColorStream.FrameWidth,kinect.ColorStream.FrameHeight,96,96,PixelFormats.Bgra32,null);
            //OpenCV処理後用
            distImg = new WriteableBitmap(kinect.ColorStream.FrameWidth, kinect.ColorStream.FrameHeight, 96, 96, PixelFormats.Bgr32, null);
            //画像のサイズ(640*480)
            bitmapRect=new Int32Rect(0,0,kinect.ColorStream.FrameWidth,kinect.ColorStream.FrameHeight);

            //OpenCV用画像
            CvImg = Cv.CreateImage(new CvSize(640, 480), BitDepth.U8, 3);
            //OpenCV用グレースケール画像
            CvGrayImg = new IplImage(CvImg.Size, BitDepth.U8, 1);
            //OpenCV用Canny処理画像
            CannyImg = new IplImage(CvImg.Size, BitDepth.U8, 1);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    //KINECTからのカラーイメージデータ
                    byte[] colorPixel = new byte[colorFrame.PixelDataLength];
                    colorFrame.CopyPixelDataTo(colorPixel);

                    //OpenCV向けWritablebitmapに書込み
                    srcImg.WritePixels(bitmapRect, colorPixel, colorFrame.Width * colorFrame.BytesPerPixel, 0);
                    //通常画像むけWritablebitmapに書込み
                    distImg.WritePixels(bitmapRect, colorPixel, colorFrame.Width * colorFrame.BytesPerPixel, 0);

                    //WritablebitmapをIplImageに変換
                    CvImg = srcImg.ToIplImage();
                 
                    //グレースケール処理
                    Cv.CvtColor(CvImg, CvGrayImg, ColorConversion.BgrToGray);
                    //Canny処理(2値化)
                    Cv.Canny(CvGrayImg, CannyImg, 50, 200);

                    //通常画像を表示
                    image1.Source = distImg;
                    //Canny処理後の画像を変換して表示
                    image2.Source = CannyImg.ToWriteableBitmap();

                }
            }                
        }
    }
}
------------------------------------------------------------------------------


以前のRGBカメラサンプルではイメージコントロールにBitmapSourceを使っていましたが、今回はWritableBitmapを使っています。
OpenCVでは画像処理形式としてIplImageというデータ形式を使っています。IplImageではBGR32データは受け取れないのでRGB24形式に変換するプログラムを書くか、BGRA32形式のデータを使うかしなければいけません。
今回はBGRA32形式のWritabebitmapを変換してOpenCVに渡すようにしています。



2012年9月8日土曜日

KINECTサンプル(C#) Speech2 for SDK1.5

前回の音声認識サンプルではプログラム内で認識したい言葉を記述していましたが、SpeechPlatform自体はSRGS(Speech Recognition Grammar Specification)形式でのGrammar設定もできるようになっています。SRGSはxmlですので決められたタグを用いて、柔軟に認識させたい言葉、文章を記述することができます。

まずはGrammarファイルです。今回は2つ用意しました。

greeting.xml
------------------------------------------------------------------------------

<?xml version="1.0" encoding="utf-8" ?>
<grammar xml:lang="ja-JP" version="1.0"
xmlns="http://www.w3.org/2001/06/grammar"
tag-format="semantics/1.0" root="greeting">

  <rule id="greeting">
    <one-of>
      <item>おはよう</item>
      <item>こんにちは</item>
      <item>こんばんは</item>
    </one-of>
  </rule>

</grammar>
------------------------------------------------------------------------------
前半はほぼ固定された内容になります。rootエレメントは自由に記述できます。
ruleタグのidエレメントも自由に記述することができます。
itemタグで認識させたい内容を記述するのですが、one-ofタグがない場合には連続した言葉として登録されます。one-ofタグでくくることによりitemタグ毎の言葉として登録することができるようになります。

次は文章を表すSRGSの記述方法です。

main.xml
------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<grammar xml:lang="ja-JP" version="1.0" 
xmlns="http://www.w3.org/2001/06/grammar"
tag-format="semantics/1.0" root="main">

  <rule id="main">
    <item>
      <ruleref uri="#fruits" />
      を
      <ruleref uri="#verb" />
    </item>
  </rule>

  <rule id="fruits" scope="public">
      <one-of>
        <item>みかん</item>
        <item>りんご</item>
        <item>すいか</item>
        <item>なし</item>
        <item>ぶどう</item>
      </one-of>
  </rule>

  <rule id="verb" scope="public">
      <one-of>
        <item>とる</item>
        <item>かう</item>
        <item>むく</item>
        <item>たべる</item>
      </one-of>
  </rule>

</grammar>
------------------------------------------------------------------------------
rulerefタグを使うことで別に記述したruleタグの内容を当てはめることができるようになります。
このファイルの場合mainのところで「fruitsの内のどれか1つ」 + 「を」 + 「verb」の内のどれか一つという文章を定義しています。
フルーツ5種類×動詞4種類=20種類の文章を定義していることになります。
rulerefタグで参照されるruleタグではscopeエレメントにpublicを指定してください。

以上のファイルをUTF-8形式で保存してください。

プロジェクト>追加>既存の項目で2つのファイルを追加してください。

画面設定です。
MainWindows.xaml
------------------------------------------------------------------------------
<Window x:Class="KinectSpeech2forSDK15.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Closed="Window_Closed">
    <Grid>
        <TextBox Height="50" HorizontalAlignment="Left" Margin="12,90,0,0" Name="textBox1" VerticalAlignment="Top" Width="479" TextAlignment="Center" FontSize="36" Text="" />
    </Grid>
</Window>
------------------------------------------------------------------------------
テキストボックスを1つ配置しています。

メインプログラムです。
MainWindows.xaml.cs
------------------------------------------------------------------------------
using System;
using System.Windows;

using Microsoft.Kinect;
using Microsoft.Speech.AudioFormat;
using Microsoft.Speech.Recognition;
using System.IO;

namespace KinectSpeech2forSDK15
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private KinectSensor kinect;
        private KinectAudioSource audio;
        private SpeechRecognitionEngine sre;

        //日本語音声認識エンジンの名前
        const string sreName = "SR_MS_ja-JP_Kinect_11.0";

        /// <summary>
        /// 
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTがみつかりません。");
                Close();
            }

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //KINECTの初期化
            kinect = KinectSensor.KinectSensors[0];

            //音声認識エンジンの初期化
            sre = new SpeechRecognitionEngine(sreName);

            //Grammarファイルを読み込む(SRGS形式)
            var greet = new Grammar("../../greeting.xml");
            var ma = new Grammar("../../main.xml");

            //認識エンジンにグラマーを登録
            sre.LoadGrammar(greet);
            sre.LoadGrammar(ma);

            //イベントの登録
            sre.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(sre_SpeechRecognized);
            sre.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(sre_SpeechRecognitionRejected);

            //KINECTのスタート
            kinect.Start();

            //KINECTのマイク入力
            audio = kinect.AudioSource;
            audio.AutomaticGainControlEnabled = false;
            audio.EchoCancellationMode = EchoCancellationMode.None;

            //マイク入力開始
            Stream s = audio.Start();

            //オーディオフォーマットの設定
            var speechAudioFormat = new SpeechAudioFormatInfo(EncodingFormat.Pcm,
                                                                16000,
                                                                16,
                                                                1,
                                                                32000,
                                                                2,
                                                                null);

            //認識エンジンに入力ストリームとフォーマットを指定
            sre.SetInputToAudioStream(s, speechAudioFormat);

            //認識開始(非同期、複数認識を有効にする。) 
            //※認識が可能になるのが数秒かかる
            sre.RecognizeAsync(RecognizeMode.Multiple);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            textBox1.Text = "認識できません。"; 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            //認識信頼度が0.7以上のときに認識したことにする 
            //(認識信頼度 -1<0<1 -1が低信頼度 0が標準 1が高信頼度 数字が大きいほど認識率が厳しくなる) 
            if (e.Result.Confidence >= 0.7)
            {
                //認識した単語の表示
                textBox1.Text = e.Result.Text;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closed(object sender, EventArgs e)
        {
            if (kinect != null)
            {
                if (kinect.IsRunning == true)
                {
                    kinect.AudioSource.Stop();
                    kinect.Stop();
                    sre.RecognizeAsyncStop();
                }
            }
        }

    }
}
------------------------------------------------------------------------------
プログラムの基本的な部分は以前のサンプルとほぼ一緒です。
Grammarを指定する部分でSRGS形式で記述したxmlファイルを読み込んでいます。

KINECTにおける音声認識の目的はPCを音声でコントロールすることがメインのようです。
ただ、SpeechPlatformは現在LyncServerにも含まれていますので、コミュニケーションアイテムとしての可能性もあるのではないかと思います。

参考としてKINECTを使ったこんなプロジェクトもあるようです。



2012年9月4日火曜日

KINECTサンプル(VB) Speech for SDK1.5

音声認識サンプルのVB版になります。
基本的にC#版と同じですが、チルト制御の代わりに音声合成ができるようにしてみました。

音声合成のために「http://www.microsoft.com/en-us/download/details.aspx?id=27224」から「MSSpeech_TTS_ja-JP_Haruka.msi」をダウンロードしてインストールしてください。

続いてサンプルプログラムです。


MainWindow.xaml
------------------------------------------------------------------------------
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Height="66" HorizontalAlignment="Left" Margin="12,94,0,0" Name="textBox1" VerticalAlignment="Top" Width="479" FontSize="40" Text="" TextAlignment="Center" />
        <TextBox Height="24" HorizontalAlignment="Left" Margin="148,193,0,0" Name="textBox2" VerticalAlignment="Top" Width="195" TextAlignment="Center" />      
    </Grid>
</Window>


------------------------------------------------------------------------------
C#版と同じ内容です。テキストボックスを2つ配置しています。



MainWindow.xaml.vb
------------------------------------------------------------------------------


Imports Microsoft.Kinect
Imports Microsoft.Speech.AudioFormat
Imports Microsoft.Speech.Recognition
Imports Microsoft.Speech.Synthesis
Imports System.IO
Imports System.Media


Class MainWindow
    Inherits Window

    Private kinect As KinectSensor
    Private audio As KinectAudioSource
    Private sre As SpeechRecognitionEngine
    Private voice As SpeechSynthesizer
    Private player As SoundPlayer

    Const sreName As String = "SR_MS_ja-JP_Kinect_11.0"

    ''' <summary>
    '''
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        If KinectSensor.KinectSensors.Count = 0 Then
            MessageBox.Show("KINECTが見つかりません。")
            Exit Sub
        End If
    End Sub

    ''' <summary>
    '''
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        ''KINECTの初期化
        kinect = KinectSensor.KinectSensors(0)

        ''認識エンジンの初期化
        sre = New SpeechRecognitionEngine(sreName)

        ''音声合成エンジンの初期化
        voice = New SpeechSynthesizer

        ''音声再生用
        player = New SoundPlayer

        ''認識させたい単語
        Dim word As Choices = New Choices

        With word
            .Add("おはよう")
            .Add("こんにちは")
            .Add("こんばんは")
            .Add("キネクト")
            .Add("終わり")
            .Add("STOP")
            .Add("START")
        End With

        ''グラマービルダーの設定
        Dim gb As GrammarBuilder = New GrammarBuilder
        ''言語を認識エンジンに合わせる
        gb.Culture = sre.RecognizerInfo.Culture

        ''単語を登録
        gb.Append(word)

        ''グラマーの準備
        Dim g As Grammar = New Grammar(gb)

        ''認識エンジンにグラマーを登録
        sre.LoadGrammar(g)

        ''イベントの登録
        ''音声認識用
        AddHandler sre.SpeechRecognized, AddressOf sre_SpeechRecognized
        AddHandler sre.SpeechRecognitionRejected, AddressOf sre_SpeechRecognitionRejected

        ''音声合成用
        AddHandler voice.SpeakCompleted, AddressOf voice_SpeakCompleted

        ''KINECTの開始
        kinect.Start()

        ''KINECTのマイク設定
        audio = kinect.AudioSource
        audio.AutomaticGainControlEnabled = False
        audio.EchoCancellationMode = EchoCancellationMode.None

        ''音声入力の開始
        Dim s As Stream = audio.Start()
        ''入力フォーマットの設定
        Dim speechAudioFormat As SpeechAudioFormatInfo = New SpeechAudioFormatInfo(EncodingFormat.Pcm,
                                                                                 16000,
                                                                                 16,
                                                                                 1,
                                                                                 32000,
                                                                                 2,
                                                                                 Nothing)

        ''認識エンジンに入力ストリームとフォーマットを指定
        sre.SetInputToAudioStream(s, speechAudioFormat)

        ''音声認識開始(非同期、複数認識で)
        sre.RecognizeAsync(RecognizeMode.Multiple)

    End Sub

    Sub sre_SpeechRecognitionRejected(ByVal sender As Object, ByVal e As SpeechRecognitionRejectedEventArgs)

        textBox1.Text = "認識できません。"

    End Sub

    Sub sre_SpeechRecognized(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)

        ''認識信頼度が0.7以上の時認識したと判断する
        If e.Result.Confidence >= 0.7 Then

            ''音声合成の準備
            player.Stream = New MemoryStream()
            voice.SetOutputToWaveStream(player.Stream)

            ''音声の合成(内部でWAVデータとしている)
            voice.SpeakAsync(e.Result.Text & " を認識しました")

            ''結果の表示
            textBox1.Text = e.Result.Text
            textBox2.Text = e.Result.Confidence.ToString()

        End If
    End Sub

    Sub voice_SpeakCompleted(ByVal sender As Object, ByVal e As SpeakCompletedEventArgs)

        ''WAVデータを最初から再生
        player.Stream.Position = 0
        player.Play()

    End Sub

    Private Sub Window_Closed(sender As System.Object, e As System.EventArgs) Handles MyBase.Closed

        If kinect Is Nothing = False Then
            If kinect.IsRunning = True Then
                kinect.Stop()
                sre.RecognizeAsyncStop()
                kinect.Dispose()
            End If
        End If
    End Sub
End Class
------------------------------------------------------------------------------

赤字の部分は音声合成を利用するための記述になります。
音声認識の部分はC#版と同じです。コメントを読めば何をしているのか理解できるかと思います。

認識できた言葉に応じて自動応答ができるようにもなりますね。