【参考書籍】KINECT for Windows SDK プログラミング C#編

2012年2月の初旬に公開されたKinect for WindowsのSDKですが、もうすでにこのSDKの書籍が発刊されました。

 

著者はKinect + OpenNIの本(KINECTセンサープログラミング)を書いた中村薫さんほか。

仕事が早い!!!

 

 

Kinect for Windos SDKにはC++とC#のサンプルがあるのですが、今回はそのC#版について。

 

C#版のSDKは良く出来ていて、カラー画像、深度データ、スケルトンがそれぞれイベントで取得できるので、非常に簡単にデータが取得できます。

この本ではKinectの概要からインストール方法、応用へと、この一冊でほぼ網羅されているのではないでしょうか?

サンプルプログラムもVisual C# 2010 Express版で公開されているので、役にたつと思います。

どこでもタッチスクリーンというサンプルも面白そう。

 

ただ、WPFをやった事の無い私にとって、その部分がちょっと引っかかるのですが、ソースを見た限りだと、そんなにも難しくないかも?

と思っていたら、ちゃんとWPFを使わないFormを使った説明もありました。

 

このFormを使った方法については、私も以前、作った事があるので、下記のページ

 

Kinect for Windows SDK C#サンプルプログラム

 

も参考にして頂けると幸いです。

(深度データをBitmapへ渡す部分が本のサンプルとちょっと違います。)

 

また、OpenCVやOpenGLを使った例が載っていますが、それぞれ.NETのラッパーライブラリを使ったものなので、少しは簡単?だと思われます。(まだ未評価なもので。)

 

目次

1.導入

1.1 Kinectの概要
1.2 ライセンス
1.3 セットアップ
1.4 プロジェクトの作成

2.基本機能

2.1 Kinect for Windowsの概要
2.2 RGBカメラ
2.3 距離カメラ
2.4 プレイヤーの認識
2.5 スケルトンの認識
2.6 WindowsFormsを利用した実装
2.7 音声の取得
2.8 延元後方の取得
2.9 チルトモーター
2.10 Kinectの挿抜検出
2.11 ここまでの全プログラム

3.応用編

3.1 OpenCVを利用した顔認識
3.2 身長を測る
3.3 どこでもタッチスクリーン
3.4 背景マスク
3.5 光学迷彩
3.6 ポーズを認識する
3.7 ロボットを操作する
3.8 Kinectをマウス代わりにする
3.9 音声を認識する
3.10 音源方向のプレイヤーを特定する
3.11 OpenGLを利用した点群の表示

4.便利なライブラリ

4.1 Coding4Fun Kiect Toolkit
4.2 Kinect Toolbox

5.APIリファレンス

5.1 Kinect制御関連APIリファレンス
5.2 RGBカメラ関連APIリファレンス
5.3 距離カメラ関連APIリファレンス
5.4 骨格関連APIリファレンス
5.5 音声関連APIリファレンス

6.ユーザビリティ

6.1 ユーザビリティとは
6.2 良いデザイン
6.3 NUI(ナチュラルユーザーインターフェース)
6.4 Kinectを利用したインターフェース
6.5 最後に

補遺
A StreamingWavePlayer
B SendInput

 

【参考書籍】C#.NETアプリケーション開発 徹底攻略 C#3.0/.NET Framework3.5対応

この本はたまたま本屋で見つけた本なのですが、よくあるTipsやリファレンス系の参考書籍とは違い、実際のプログラムでどのようにすべきか?みたいな事が書かれています。

 

.NETのプログラムをしていると、結果は同じ様になる事でも幾つかのメソッドが用意されているため、これで本当にいいのか?.NETを使っていると処理が遅くないか?ガーベージコレクションはどうなってるのか?というようなモヤモヤ感が残る場合があります

これらの事が理論的に書かれているので、とても参考になりました。

 

あまり初心者向けな本ではありませんが、C#である程度プログラムできるようになった人が、読むと良いと思います。

 

 

目次

Chapter 01 導入:.NET Frameworkと開発環境

1.1 本書の目的

1.2 対象とする読者

1.3 本書の構成

1.4 .NET Framework概要

1.5 .NET Frameworkの現在

1.6 開発環境

1.7 コードサポート

Chapter 02 .NET Frameworkアプリケーション設計

2.1 設計概要

2.2 イベント/デリゲートをベースとしたイベント駆動型設計

2.3 型セーフな設計

2.4 Windows Formsアプリケーション設計

2.5 マルチスレッド/非同期制御

2.6 例外設計

2.7 データ型

2.8 リフレクション

2.9 ネイティブアプリケーション層の利用

Chapter 03 チューニング

3.1 .NET Frameworkの性能

3.2 チューニングポイント

3.3 メモリー管理/メモリチューニング

3.4 パフォーマンスプロファイリング

3.5 最初の.NET Frameworkチューニング

Chapter 04 リリース管理/セキュリティ

4.1 .NET Frameworkの実行環境

4.2 ClickOnce

4.3 ソースコードの保護

Chapter 05 COMアプリケーション連携

5.1 .NET FrameworkとCOM

5.2 レジストリ登録不要なCOM

5.3 .NET Frameworkを使用したCOMコンポーネント

Chapter 06 新しい.NET Framework/Silverlight

6.1 最新の.NET Framework

6.2 C# 3.0

6.3 Silverlight

6.4 Silverlightアプリケーションの作成

 

 

Kinect for Windows SDK C#サンプルプログラム

先日公開されたKinect for Windowsと、そのSDKですが、これまでKinectは研究用途で黙認状態でしたが、このKinect for Windows(Kinect本体)を使う事で商用が可能となるインパクトは大きく、これからもKinectを使ったアプリもどんどん出て来ると思います。

 

しかし、SDKはC#版とC++とがあり、C#なら簡単に出来るかな~?!と思ってもKinect for WindowsのSDKではC#とWPFを使うので、WPFをやった事がないと少し分かりづらいと思います。

 

そんなWPFなんて分からない!という人(私)向けにC#だけサンプルプログラムを作ってみました。

 

基本はC#+WPFのKinect Explorerのサンプルをベースにして、分かり易さ重視?!で音声部分や必要の無さそうな部分は削除しました。(エラー処理もあまり考えていません...)

 

作成したプログラムはこんな感じ↓

 

サンプルプログラムはこちら↓よりダウンロードして下さい。

Kinect for Windows SDK C#サンプル (Visual Studio 2010 C#)

 

このサンプルを実行するには別途、Kinect for WindowsのSDKをインストールしておく必要があります。

SDKはこちら↓のページよりダウンロード可能です。

http://www.microsoft.com/en-us/kinectforwindows/develop/overview.aspx

 

インストール方法については、他の人のページですが、このへん↓

 

Kinect3 -Kinect for Windows SDK

 

を参考にしてみて下さい。

 

ちなみに、このサンプルプログラムを作るのには、Kinect for Windows SDKのヘルプファイルのHow Tosの部分がともて参考になりました。

 

英語ですが一度、目を通して見てみて下さい。

 

n点からなる多角形の面積を求める

前回、3点からなる三角形の面積外積を用いて求めました。

これを多角形へ応用したいと思います。

 

まず、外積のおさらいから。

 

Z成分が0(ゼロ)の2つのベクトル

 

 

の外積は

 

 

となり、Z成分の大きさが2つのベクトルのなす平行四辺形の面積となり、三角形の面積はこの半分(1/2)となります。

 

さらに、ベクトルa から ベクトルb への向きが反時計方向の場合
ベクトルa と ベクトルb の外積のZ成分の値はとなり、

 

 

逆に時計方向の場合、Z成分はとなります。

 

 

これを踏まえて、3点からなる三角形の面積を求めるの時は三角形の辺上にベクトルを取りましたが、今回は原点と多角形の頂点の座標とで成すベクトルとします。

 

ここで、多角形の頂点の座標を~Pのように反時計方向に定義します。

ただし、Z座標は0(ゼロ)とします。

 

 

ベクトル→P と ベクトル→P の外積のZ成分の値は時計方向なので、となります。

 

 

同様に、ベクトル→P と ベクトル→P の外積のZ成分の値は反時計方向なので、となります。

 

 

ベクトル→P と ベクトル→P の外積のZ成分の値も反時計方向なので、となります。

 

 

これらの外積の結果のZ成分を足して1/2にすると、求めたい三角形の面積が求まります。

 

 

この事をn点からなる多角形へ応用すると、下図のような図形の場合、

 

 

~Pまでは時計方向となるので、外積のZ成分はとなります。

 

 

~P、Pまでは反時計方向となるので、外積のZ成分はとなります。

 

 

これら全ての外積のZ成分を足し、1/2にすると多角形の面積が求まります。

 

この事を一般式で書くと、頂点の座標をPi (xi,  yi) とすると

 

 

となります。
i は i = 1, 2, 3・・・nのインデックス番号、
|  | は絶対値です。

ただし、i = n のとき、n+1 = 1 とします。

 

また、絶対値を取っているのは、頂点の座標が時計方向へ割り振られた場合にも対応できるようにしています。

 

使える数学へ戻る

 

3点からなる三角形の面積を求める

外積を用いて三角形の面積を求める方法を紹介します。

 

まず、外積のおさらいですが、三次元ベクトルにおいて2つのベクトルの外積の大きさが2つのベクトルからなる平行四辺形の大きさに一致する特徴がありました。

 

この2つのベクトルのZ成分を0(ゼロ)にして二次元座標へ応用します。

2つのベクトルを

 

 

とすると、2つのベクトルの外積は、x成分とy成分は0(ゼロ)となり、z成分の大きさが平行四辺形の面積の大きさとなる事から、3点からなる三角形の面積は平行四辺形の半分の大きさとなり、

 

 

となります。

 

例題

3点、A(1, 3), B(3, 4), A(2, 6)からなる三角形の面積を求めよ。

 

解)

 

使える数学へ戻る

 

平面の方程式

下図のように点(x0, y0, z0を通り、法線ベクトルが

 

 

の平面の方程式は

 

 a(x-x0)+b(y-y0)+c(z-z0)=0

 

となり、一般に

 

 ax+by+cz+d=0

 

と表します。

 

 

 

なぜそうなるのか?というと、平面に垂直な法線ベクトルと、平面上の任意の2点からなるベクトルとは常に垂直である事から、法線ベクトルと、平面上の2点からなるベクトルとの内積の結果は常にとなります。

 

つまり、法線ベクトル(a, b, c)と平面上の2点のベクトル(x-x0, y-y0, z-z0の内積が0となるので、

 

 a(x-x0)+b(y-y0)+c(z-z0)=0

 

となり、これを展開したのが、平面の方程式

 

 ax+by+cz+d=0

 

となります。

 

平面は点が3つあれば求まるのですが、3点から平面の式を求めるには外積を用います。

 

外積では2つのベクトルの外積を求めると、2つのベクトルと外積の結果とは直交するという特徴があるので、下図のように

 

 

平面上の3点P0, P1, P2から、P0→P1P0→P2の2つのベクトルを作り、

 

 (x1-x0, y1-y0, z1-z0

 (x2-x0, y2-y0, z2-z0

 

外積を計算すると、法線ベクトルの各成分(a, b, c)

 

 a=(y1-y0)×(z2-z0)-(y2-y0)×(z1-z0)

 b=(z1-z0)×(x2-x0)-(z2-z0)×(x1-x0)

 c=(x1-x0)×(y2-y0)-(x2-x0)×(y1-y0)

 

となり、法線ベクトルの要素のa, b, cが求まるので、平面の方程式に3点P0, P1, P2のどれかを代入すると平面の方程式が求まります。

 

使える数学へ戻る

 

正規直交基底

正規直交基底はあまり馴染が無いように思いますが、フーリエ変換や主成分分析の理解をするには必要となってきます。

 

【定義】

ベクトルの大きさが1となり、互いのベクトル(任意の2つのベクトル)が
直交するベクトルの組合せ

 

となります。

 

ここで、ベクトルの大きさ(ノルム)がという事は、そのベクトルは単位ベクトルであり、
ベクトルが直交するということは、ベクトルの内積が0となる事を意味しています。

 

もっとも簡単な例として、二次元ベクトルの場合

 

 

上図のように、e1, e2

 

 

としたとき、この e1, e2 は正規直交基底である事は分かると思います。

 

ここで大事なのが、任意ベクトルe1 方向の大きさを, e2 方向の大きさをとすると、

 

各ベクトルの方向の大きさは内積で求まる!

 

という特徴があります。

 

上記の例では

 

e1方向の大きさ

 

a = e1 = X  × 1 + Y × 0= X

 

e2方向の大きさ

 

b = e2 = X  × 0 + Y × 1= Y 

 

となります。この処理を斜影と言います。

 

逆に

 

任意ベクトルは正規直交基底と各大きさを用いて表す事ができる!

 

という特徴もあります。

 

任意ベクトルを求めるには正規直交基底の各ベクトルとその大きさをかけて、ベクトルを足し合わせると求まります。

 

上記の例では

 

  任意ベクトル  = a  × e1 + b × e2
           = a × (1, 0)+ b × (0, 1)
           =  (a, b)

となりますが、この例はあまりにも単純な例なので、もう少しだけ具体的にして、ベクトルを

 

 = (4, 6)

 

正規直交基底を

 

 

とします。

 

 

このとき e1, e2 が正規直交基底であるかどうか?は、それぞれのベクトルの大きさと、内積を計算すると確認する事が出来ます。

 

 

また、このとき、

 

e1方向の大きさ

a = V ・e1 =

 

e2方向の大きさbは

b = V ・e2 =

 

となります。
逆にベクトルVを正規直交基底の e1,e2 とそれぞれの向きの大きさを用いて計算すると

 

 

となり、確かに正規直交基底を用いると任意ベクトルを表すことができそうです。

 

このことをもう少し一般化して、正規直交基底 e1,e2

 

 

としても、任意ベクトル を表すことはできます。

 

 

これをさらに三次元の場合でも、任意ベクトル を表すことができます。

 

 

このノリでさらにn次元の場合でも同様に正規直交基底をe1,e2・・・,eとしても、任意n次元ベクトル を表すことができます。

ということで、クドいですが、正規直交基底には

 

任意ベクトルを正規直交基底と各大きさを用いて表す事ができる!

 

という特徴があります。

 

それって、もうほとんどフーリエ変換の説明になっているのですが、お気づきでしょうか?
フーリエ変換についてはいづれ記事にしたいと思います。

 

外積

外積内積ほどは応用する事は出来ないのですが、外積を用いる事で、平面の向きの計算(ポリゴンの法線ベクトルの計算)や、2つのベクトルのなす平行四辺形の面積の計算、2つのベクトルのなす角度の計算などに応用できます。
2つのベクトルのなす角度については、内積でも計算できますが、外積を使うと、2つのベクトルの位置関係により、角度の値の+、-を使い分けることが可能になります。

 

内積の定義は以下の通りです。

 

三次元空間における2つのベクトル

 

 

において、ベクトルa とベクトルb の外積は、以下のようになります。

 

 

この外積の計算は少し覚えづらいのですが、ベクトルa とベクトルbの成分を上下に並べて、X成分を求める時はX成分を隠して、残りの4つの成分で下図のように斜めに掛けて引く、いわゆるたすき掛けという計算を行います。(と言っておきながら、私は覚えてないので、毎回調べてます...)

 

 

また、内積の計算結果はただの値(スカラー)でしたが、外積の結果はベクトルとなります。

 

ベクトルなので、外積の結果は向きと大きさを持ち、外積の向きは右ねじの方向となります。

(右ねじの回転方向は外積の掛ける順番となります。)

 

さらに外積の大きさ(ノルム)は2つのベクトルでなす平行四辺形の面積と一致します。

 

 

また、2つのベクトルが三次元の場合と言いましたが、二次元のベクトルであってもベクトルのZ成分を0(ゼロ)にする事で外積の特徴を応用する事も可能です。

 

使える数学へ戻る

 

Word/Excelの数式で分母分子にΣの上下に文字が書けない

Word/Excelの数式エディタで分母、分子にΣ(シグマ)を書くと、このように添え字部分がズレてしまいます。

これをズレないように表示する方法をいろいろ探してみたのですが、正式な方法は見つからなかったのですが、下図のように、それらしく表示する方法を紹介します。

 

Office(Word/Excel)で数式を書く場合、挿入 → 記号と特殊文字 → 数式 の π(パイ) の部分をクリックします。

すると、ここに数式を入力します。 と表示されます。

この状態で、Σの数式を書く場合は、大型演算子総和(上下端値あり)をクリックします。

すると、Σの部分だけは表示され、添え字の部分は □ で表示されます。

この □ の部分に必要な文字を書くと、このように↓なります。

と、ここまではいいのですが、Σを分数に書くと、添え字の位置がズレてしまいます。

そこで、以下の手順でそれらしく表示するようにします。

まず、分数ではなく、行列の2x1行列を追加します。

この状態で、分母分子にΣを書くと、添え字がズレる事なく、表示されます。
しかしながら、分数の線が無い状態です。

分数の線を書くのに、オーバーライン/アンダーラインを流用します。
まず、分母分子の文字が長い方の右端(もしくは左端)をカーソルで選択します。

次にアクセントのアンダーライン(分子の文字が長い場合は、オーバーライン)をクリックします。

すると、アンダーライン付きの □ が表示されます。

この□の部分に、Σの部分をカットし、ペーストすると、下図のようになります。

これで、分数の分母/分子にΣの上下に添え字付きの数式のように見えますでしょ?!

内積

内積は計算そのものは簡単な割にはとても応用範囲が広いので、私の好きな処理の一つなのです。

 

内積の定義は以下の通りです。

 

上図のようにベクトルaとベクトルbの成分を以下のように表すと

 

 

2つのベクトルの内積は

 

 

であらわされます。

 

ただし、ベクトルの大きさは、ノルムと呼ばれ、以下のように計算します。

 

 

さらに一般的にn次元ベクトルの場合、2つのベクトルを

 

a=(a1,a2,a3,・・・,an)

b=(b1,b2,b3,・・・,bn)

 

とすると(添え字の無いは太字で表します)、内積の計算は

 

 

となります。

 

ここまでが、普通に学校で習う内積なのですが、この内積の式をいろいろ変形させて使う事で、応用例が広がります。

 

例えば内積の式を cosθ= の式に変形して

 

 

とすると、定式で求めたcosθのアークコサインを計算すると、2つのベクトルのなす角を求める事ができます。

 

さらにcosθをそのまま用いて、cosθが1の時は2つのベクトルが向きが一致し、cosθが-1の時は2つのベクトルが向きが逆向きとなる事から2つのベクトルの大きさに関係なく、2つのベクトルがどれだけ似ているか?の指標に使われる場合があります。例えば、画像処理では正規化相関が、まさにそのものとなります。

 

また、内積の式を

 

 

のように変形すると、ベクトルbの成分の内、ベクトルaの方向にどれだけの成分があるか?の計算をする事ができます。

 

 

この処理は、いづれ出てくるであろう正規直行規定への斜影の処理と同じです。

 

さらに言うとフーリエ変換の一部とも考える事ができます。

 

と言う事で、内積そのものの計算は同じ成分同士を掛けて足し合わせだけなので簡単なのですが、応用範囲が広いので好きなのです。

 

内積はニュアンス的には、どれだけ似ているか? もしくは 似ている成分を抽出する手法として用いる事ができます。

 

例えば3×3フィルタの一つのソーベルフィルタも、

 

X方向へは

-1 0 1
-2 0 2
-1 0 1

 

Y方向へは

-1 -2 -1
0 0 0
1 2 1

 

と表せれますが、これは一般的には画像を微分している!という捉え方が多いですが、9次元ベクトルの内積を計算している!とも考えられます。

 

そう考えると、ソーベルフィルタの結果は、左から右(上から下)方法へ向かって暗から明へ変化する場合は値が正となり、明から暗へ変化する場合は負となるのも納得できます。

 

さらにエッジの強さが強い時は値が大きくなるのも内積の特性と一致します。

 

と、無理やり内積をこじつける必要もありませんが、正規化相関やフーリエ変換は内積と同じ!と思えると、一見難しそうなアルゴリズムでも、少し簡単に見えてくると思います。
 

使える数学へ戻る

 

ベクトルの引き算

ベクトルaからベクトルbを引く場合、

 

上図のように引く側のベクトルの終点から、引かれる側の終点へ向かうベクトルが引き算の結果となります。

 

といっても覚えづらいので、引く側のベクトルを負にして、向きを逆にし、ベクトルの足し算として捉えた方が覚えやすいと思います。

 

 

ベクトルの成分であらわすと、

 

 

となります。

学校で、このように答えると×をもらうかも?しれませんが、ベクトルは向きと大きさしか持たず、位置の情報は無いので、大人になってから覚えるベクトルの引き算はこれでOKです。

 

使える数学へ戻る

 

ベクトルの足し算

ベクトルaとベクトルbを足す場合、

 

上図のように始点⇒終点⇒始点⇒終点とつなき合わせていき、最初のベクトルの始点から最後のベクトルの終点へ向かうベクトルが足し算の結果となります。

 

 

ベクトルの成分で表すと

 

 

となります。

足す順番を入れ替えても結果は同じです。

 

 

使える数学へ戻る

 

OpenCVをスタティックリンクライブラリでビルドする方法

スタティックリンクライブラリを使うと他のPCへ作成した実行ファイルを移植する時にexeファイルをコピーすればOpenCVをインストールする事なく実行できるので、メリットはあるので、使ってみたいのですが、これが、なかなか分かりづらい。

 

OpenCV2.3.1ではファイル(OpenCV-2.3.1-win-superpack.exe)をダウンロードし、解凍するとスタティックリンクライブラリらしきフォルダ(staticlib)があるのですが、*.libファイルが不足しているらしく、未解決のシンボルのエラーが出て使う事が出来なさそうです。

 

そのため、OpenCV-2.3.1-win-superpack.exeのソースからCMakeを使ってスタティックリンクライブラリをビルドしてみました。

 

CMakeでビルドする方法はOpenCV2.3の入手、ダウンロード、インストール、環境設定のページを参考にして頂きたいのですが、上記のページから異なるポイントを示したいと思います。

 

今回OpenCV-2.3.1-win-superpack.exeを c:\ に解凍している事を想定しています。

 

まずCMakeで作成するプロジェクトの保存先のフォルダを作成しておきます。

 

今回は C:\opencv\userbuild というフォルダを作成するとします。

 

CMakeを起動し

 

Where is the source codeに C:/opencv

Where is the source codeに C:/opencv/userbuid

 

を指定します。

 

 

次にConfigureボタンをクリックします。

すると下図のようなウィンドウが開くので、使用するVisual Studioのバージョンを選択します。

 

 

Finishボタンをクリックすると下図のように表示されるので、BUILD_SHARED_LIBSのチェックを外します。CUDAに対応していないPCの場合はWHITH_CUDAのチェックも外して下さい。

 

 

次にConfigureボタンをクリックするとBUILD_WITH_STATIC_CRTという項目が表示されるので、チェックを入れたまま、Configureボタンをクリックします。

 

 

すると赤く表示された部分が無くなるので、Generateボタンをクリックします。

 

 

するとWhere is the source codeで指定したフォルダ(\userbuild)にソリューションファイル(OpenCV.sln)が作成されるので、このファイルをダブルクリックし、VisualStudioを開きます。

 

開いたVisualStudioのメニューからビルド→構成マネージャーを選択します。

 

次にINSTALLの項目にあるビルドの部分にチェックを入れます。

左上のアクティブソリューション構成の部分のDebugReleaseを選択しそれぞれにチェックを入れます。

 

この状態で、Visual Studioのメニューのビルド→ソリューションのビルドを選択し、OpenCVをビルドします。このビルドには、かなり時間がかかりますが、ReleaseDebugの両方でビルドを行って下さい。

 

これでWhere is the source codeで指定したフォルダ(\userbuild)内に必要なヘッダファイルとライブラリファイルが作成されます。

 

スタティックリンクライブラリを使用する方法

まず、Visual Studioを起動し、ファイル⇒新規作成と選択し、Visual C++⇒Win32内のWin32コンソールアプリケーションを選択し、ウィンドウの下の方にある名前をプロジェクトを作成する場所を指定します。

 

次に表示されたウィンドウで完了をクリックするとスケルトンプログラムが作成されます。

 

次にVisual Studioのメニューのプロジェクト⇒(プロジェクト名)のプロパティを選択し、構成のプロパティ⇒C/C++⇒全般と選択し、追加のインクルードディレクトリの部分に先程作成したOpenCVのopencv2のあるフォルダを指定します。(右上の構成の部分でDebugとReleaseを切り替えて同じ設定をして下さい。)

C:\opencv\userbuild\install\include

 

同じウィンドウで構成のプロパティ⇒リンカー⇒入力と選択し特性の指定のライブラリの無視の部分で

 

(Debugの場合)

LIBCMTD.lib;msvcprtd.lib

(Releaseの場合)

LIBCMT.lib;msvcprt.lib

 

を指定します。

 

これで、ソースコード上に下記のようにヘッダファイル(*.hpp)とライブラリファイル(*.lib)の設定を行うと、OpenCVをスタティックリンクライブラリとして使用する事が可能になります。

 

下記はWebカメラを撮影する簡単なコードです。

 

// OpenCVStaticSample.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

//*******************************************************************************
// プロジェクトの設定
// ①プロジェクトのプロパティ⇒C/C++⇒全般 の追加のインクルードディレクトリに
//      C:\opencv\userbuild\install\include
//   を追加
// ②プロジェクトのプロパティ⇒リンカー⇒入力 の特定の規定のライブラリの無視に
//    Debugのとき
//        LIBCMTD.lib;msvcprtd.lib
//    Releaseのとき
//        LIBCMT.lib;msvcprt.lib
//    を追加
//*******************************************************************************

#include "opencv2\\opencv.hpp"

#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"vfw32.lib")	// Video for Windows

#ifdef _DEBUG
    //Debugモードの場合
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_core231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_imgproc231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_highgui231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_objdetect231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_contrib231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_features2d231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_flann231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_gpu231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_legacy231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_ts231d.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_video231d.lib")

    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\zlibd.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libtiffd.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libpngd.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libjpegd.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libjasperd.lib")

#else
    //Releaseモードの場合
	#pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_core231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_imgproc231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_highgui231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_objdetect231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_contrib231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_features2d231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_flann231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_gpu231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_legacy231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_ts231.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\lib\\opencv_video231.lib")

    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\zlib.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libtiff.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libpng.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libjpeg.lib")
    #pragma comment(lib,"C:\\opencv\\userbuild\\install\\share\\OpenCV\\3rdparty\\lib\\libjasper.lib")

#endif

int _tmain(int argc, _TCHAR* argv[])
{

	// カメラオープン
	cv::VideoCapture cap(0);

	// カメラがオープンできたかの確認
	if(!cap.isOpened()) return -1;

	cv::namedWindow("Capture", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
	while(1) {
		cv::Mat frame;
		cap >> frame;  // キャプチャ
		// 様々な処理
		// ...
		cv::imshow("Capture", frame); // 表示
		if(cv::waitKey(30) >= 0)
		{
			cv::imwrite("cap.png", frame);
			break;
		}
	}

	return 0;
}

※実際に開発したPCとは別のPCへ実行ファイル(*.exe)を移植する場合、別途、C++のランタイムが必要となります。

 

移植先のPCに開発したPCで使用したVisual Studioと同じバージョンがインストールされていない場合、C++の再頒布パッケージというものをインストールします。

 

Visual Studio 2010 C++(32bit)の場合、以下の場所よりダウンロードして下さい。

Microsoft Visual C++ 2010 SP1 再頒布可能パッケージ (x86)

 

これで、OpenCVをスタティックリンクライブラリで使えていると思うのですが、この特定のライブラリの無視する部分と、comctl32.libとvfw32.libを追加しないといけない部分が分かりづらかった...

ただ、warning LNK4049のワーニングが幾つか出てしまい、いまいち、このwarningの消し方は分かりませんでした...

 

OpenCVへ戻る

 

ベクトルの基礎

ベクトルは向き大きさをもった量を表します。

向きが逆の場合、ベクトルは負となります。

 

ベクトルを座標で表すと以下のようになります。

 

ベクトルの大きさは三平方の定理より、以下のようになり、この大きさをノルムと言います。

 

三次元の場合も同様に点P(X,Y,Z)から点P(X,Y,Z)へ向かうベクトルの場合は

 

となり、ノルムも

となります。

 

ここまでは、ベクトルを矢印で表す事のできるベクトルで幾何ベクトルと言います。

 

画像処理においては、より一般的にn個の数の組み合わせからなるn次元ベクトルとして扱う場合があります。

 

表記方法は一般に文字を太字にして

 

 

のように書きます。

 

こうなると、矢印で表す事ができなく、数ベクトルと言います。

 

画像処理的には、例えば、輝度値の平均、最小値、最大値、分散を使った

 

  a=(平均、最小値、最大値、分散)

 

のような4次ベクトル!みたいな扱いをしたりします。(かなりいいかげんな例ですが。)

 

最初はなんでこんな難しそうに聞こえる(頭が良さそうに聞こえる)表現をするんだろうな~と思っていましたが、ベクトルとして扱う事で、内積などのベクトルの演算が使えたり、行列としても扱えたりするので、それなりのメリットも出てきます。

 

使える数学へ戻る

 

奇関数・偶関数の積分

奇関数・偶関数でも説明したように、

関数f(x)が奇関数の場合、-a~aの範囲での積分は

 

関数f(x)が偶関数の場合、-a~aの範囲での積分は

となります。

 

一般的な式では奇関数と偶関数に分けて積分を行います。

(計算例)

となります。

こうする事で計算量を格段に減らす事ができます。

 

現実的には積分の範囲が-a~aになる事はまれで、普通はa~bのような任意範囲で積分する場合が多いかと思います。

そこで、グラフ(関数)全体をabの中心[(a+b) / 2]が原点位置に来るように平行移動を行い、積分範囲が原点に対し対称になるように調整します。

(この処理を行っても積分の結果には影響はありません。)

 

 

こうする事で、一般的な積分においても、奇関数・偶関数の特徴を用いる事が可能となります。

 

なぜ、わざわざそんな事をするかと言うと、積分の部分をfor文に置き換えて関数の合計を計算するプログラムを考えると、この奇関数・偶関数の特徴を用いると計算量が、

 

奇関数の部分で0へ

偶関数の部分で半分に

 

減らせる可能性があるので、トータルで1/4に計算量を減らせるかも?しれないので、その分、処理が高速になります。

 

その例を最小二乗法の最適化で紹介しています。

 

使える数学へ戻る

 

C#(.NET)からOpenCVを使う方法、OpenCvSharpのインストール方法

OpenCVはシンプルな画像表示用のウィンドウも用意されているので、簡単に画像処理を試したい場合には非常に良いのですが、少し凝ったウィンドウを作成しようとすると、やっぱり.NETからOpenCVを触りたくなります。

 

.NETの言語(VB.NET、C#、C++/CLI)からOpenCVを使う方法は、だいたい以下の通り

  • .NETのラッパーライブラリを使う
  • 自作でラッパーライブラリを作成する
  • C++/CLIから直接使う

となりますが、実質的にはOpenCvSharpを使う事になると思います。

 

OpenCvSharpのインストール方法は、現在ではNuGetによりプロジェクトごとにインストールします。

 

OpenCvSharpのインストール方法

まず、インストールするC#プロジェクトを用意します。

新規でC#プロジェクトを作成する場合は、次のように行います。

Visual Studio を起動後、新しいプロジェクトの作成をクリックします。

次に Windowsフォームアプリケーション(.NET FRamework)を選択し、次へをクリックします。

プロジェクト名、場所を指定し、作成をクリックします。

これで、以下のようにフォームが表示されたらベースとなるC#プロジェクトが作成されています。

 

次に、このC#プロジェクトにNuGetでOpenCvSharpをインストールします。

メニューのプロジェクト→NuGetパッケージの管理をクリックします。

表示された画面で、 参照 を選択し、その下のテキストボックスに OpenCvSharp と入力すると、OpenCvSharpの一覧が表示されるので、この中から OpenCvSharp.Windows を選択します。

OpenCvSharp.Windows を選択すると、右側に インストール ボタンが表示されるので、これをクリックします。

しばらくすると、インストールが完了します。

OpenCvSharpがインストールされたか?確認するには、プロジェクトの参照の部分の表示を展開すると、OpenCvSharpの名前空間が表示されている事を確認します。

簡単にOpenCvSharpの動作を確認します。

ツールボックスの中から Button を選択し、フォーム上にドラッグ&ドロップします。

ボタンをダブルクリックし、C#コードを表示し、上の方に、

using OpenCvSharp;

と入力し、ボタンイベントの部分に以下のように記載します。

private void button1_Click(object sender, EventArgs e)
{
    var img = new Mat(new OpenCvSharp.Size(256, 256), MatType.CV_8UC3, new Scalar(35, 123, 254));

    Cv2.ImShow("Image", img);
}

参考までに、Formの全コードを示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using OpenCvSharp;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var img = new Mat(new OpenCvSharp.Size(256, 256), MatType.CV_8UC3, new Scalar(35, 123, 254));
            Cv2.ImShow("Image", img);
        }
    }
}

この状態で、▶開始 ボタンをクリックし、以下のように表示されれば OpenCvSharp のインストールは成功しています。

 

OpenCvSharpを使うポイント

2021年現在、OpenCVの情報はPythonであふれているので、OpenCvSharpの情報を探すのは難しくなってきています。

OpenCvSharpの情報を入手するには、少し古くなりましたが、作者であるSchimaさんのページを参照することをお勧めします。

http://schima.hatenablog.com/archive/category/OpenCvSharp

リファレンスは英語になりますが、こちらです。

http://shimat.github.io/opencvsharp/api/OpenCvSharp.html

 

あとは、OpenCvSharpは基本的にOpenCVのC++版のラッパーライブラリであるため、OpenCVのC++の情報を検索し、OpenCvSharpでは、どうするのか?を推測するのもイイかと思います。

 

参考

https://github.com/shimat/opencvsharp

http://shimat.github.io/opencvsharp/api/OpenCvSharp.html

OpenCVへ戻る