Quantcast
Channel: 自習室
Viewing all 50 articles
Browse latest View live

openFrameworks の Shaderチュートリアル "09 gaussianBlur"のバグ

$
0
0

はじめに

こちらの記事を読んで自分で試していたら、バグ(?)を見つけたので報告

http://www.openframeworks.cc/tutorials/graphics/shaders.html

配布されているコードをそのまま実行すると、ピクセルごとのcolorが不正な値で初期化されて、非常に出来の悪いグリッチになる。こんな感じ。

f:id:AMANE:20141009000608p:plain

環境

すごく、環境依存な気がします。

結論

配布されている shaderBlurX.frag, shaderBlurY.frag の両方で、`vec4 color'をちゃんと0で初期化する。

void main()
{
  vec4 color = vec4(0); // ここを追加// 以下略 他は全部配布されているままでOK

正しくブラー出来ています

f:id:AMANE:20141009001159p:plain

再現方法

コードの入手

当該記事で扱っているサンプルのコードは、公式で配布されている.zip には含まれていないので、githubから落としてきます

コードの在処はこちら

https://github.com/openframeworks/openFrameworks/tree/master/tutorials/shader

ビルド(Mac + Xcodeの場合)

プロジェクトジェネレータで空のプロジェクトを作成した後、src と bin(shaderのコードを含む) を配布されている物に置き換えます

f:id:AMANE:20141009001833p:plain

上図のbin と srcを、新しくつくったプロジェクトのbin と src につっこみます。

これでXcodeからビルドできる、はず。

さいごに

チュートリアルはすごく役に立ちました。最後の最後に変なバグを踏んだので驚きましたが、それ以外は非常に勉強になりました。ここからがんばりたいっす。


openFrameworks, Three.js, Processing のGLSL バージョン対応状況調査

$
0
0

はじめに

openFrameworksのセミナーでShaderに触れた

この週末、合宿で行われた openFrameworks のセミナーに参加してきました。

セミナー本体の紹介は @yumu19さんが現場の雰囲気なども伝わってくる素敵な記事を書いて下さっています。

講義内容の紹介は、 @shu223さんのブログが充実しています

このイベントについて、このほかにも計5本もの記事を書かれていますスゴイ!

このセミナーの中で、FrameBufferObjectの使い方、PostProcessのためのaddonの使い方など、Shaderに関わる話がたくさん出てきました。

Shader言語のバージョン対応状況について気になった

最近仕事でもThree.jsをつかったり、趣味でoFやProcessingを触っていたので、各開発環境ごとにびみょーに異なるGLの対応状況をまとめて置きたくなりました。それぞれ、

環境 GLのライブラリ プログラミング言語
Three.js WebGLJavascript
openFrameworks OpenGL C(C++)
Processing JOGL Java

という感じで、同じOpenGLではあるのですが、それぞれ違う言語ですし、さらにそれぞれのラッパでくるまれた状態になっています。 しかし、そのなかで実行時に解釈されるglslについては、おなじバージョンでさえあればほぼ同じ書き方で行けます。

これまでShaderにまじめに取り組んで来なかったので、これを機に勉強してみようかな、と思ったのですが、実は各環境ごとにどうもGLの対応状況が異なるようです。

上記3環境についてGLの対応状況を調査し、自分がどのバージョンでglslを書けば良いか判断するのが、本記事の主な目的になります。もちろん最終的には、やりたい表現や案件次第で選ぶことになりますが、手始めに手をつけて勉強するためのバージョンを選ぶ、という感じです。

前提知識

GL, GL ES, のバージョンの前後関係や glsl のバージョンとの対応は こちらのサイト様に綺麗にまとまっていましたので、参考にさせていただいております。

また、最新までは更新されていませんが、バージョンごとにどのような機能が実装されてきたか、について、こちらのサイト様が端的にまとめて下さっています。

このあたりを参考にしながら本記事を書きました。

環境

  • MacBook Air 2012 Mid
  • Xcode 6.0.1
  • openFrameworks v.0.8.4
  • Three.js r68
  • Processing 3.0a4

oF, Three, Processing については、本記事執筆時の最新リリースを利用しています。

openFrameworks v.0.8.4

glInfoExample

公式のサンプルにglのバージョンを確認する exaples/gl/glInfoExampleというプロジェクトがあります。実行した後の画面はこんな感じ

f:id:AMANE:20141013205911p:plain

メインウィンドウの一番上に "opengl version: 2.1"と出ていますが、これは「このプロジェクトが」2.1で動かされました、と言う意味で、ハードウェアやライブラリの対応状況を表した物ではありません。

隣には、出力されたtxtが開かれています。これは GL の拡張機能をロードするヘルパライブラリのglew が、「私ここまでなら行けますよ」と言っている物で、このoFに含まれて居るglew的には 4.1 まではいける、ということらしいと分かります。

実際に作ってみる: 素のプロジェクトの場合

ofのプロジェクトに、以下のコードを足して、GLの対応状況を出力させます。たとえば、main.cpp でOpenGLをセットアップした後に入れると良いと思います。

// main.cpp
ofSetupOpenGL(1024,768, OF_WINDOW);   

cout << "Vendor :"<< glGetString(GL_VENDOR) << '\n';
cout << "GPU : "<< glGetString(GL_RENDERER) << '\n';
cout << "OpenGL ver. "<< glGetString(GL_VERSION) << '\n';
cout << "GLSL ver. "<< glGetString(GL_SHADING_LANGUAGE_VERSION) << '\n';

この書き方については、こちらのサイトを参考にさせていただき、最後の SHADING_LANGUAGE_VERSOINを追加しています。

実装しているGPUのOpenGLのバージョンを調べる

ProjectGeneratorで出力した素のプロジェクトでこれをやると、以下の様な出力になります

Vendor :Intel Inc.
GPU : Intel HD Graphics 4000 OpenGL Engine
OpenGL ver. 2.1 INTEL-8.28.32
GLSL ver. 1.20

これは、glInfoExample が出力しているのと同じですね。

PCごとの最新GLを利用する

マシンが使っているGPUと、oFのバージョンによって、利用できるGLのバージョンが変わります。openFrameworksで最新のGLを使える様にするには、以下のコードを加えます

#include "ofGLProgrammableRenderer.h"int main( ){
    ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);
    ofSetupOpenGL(1024,768, OF_WINDOW);   

これで新しいGLに対応したレンダラーを利用するようになります。この書き方については、oF公式のShaderチュートリアルが参考になります

こうした後に、先ほどと同様にGLのバージョンを確認すると、このような出力になります。

Vendor :Intel Inc.
GPU : Intel HD Graphics 4000 OpenGL Engine
OpenGL ver. 4.1 INTEL-8.28.32
GLSL ver. 4.10

注意点としては、GL3.0 以上を使う場合、 GL2系で使われていた varying などの記述が使えなくなり、実行時にエラーが出ます。(glslコードのコンパイル時にエラーが出ます) 多くのサンプルプログラムが動かなくなります。

oFの場合、最新を使うべきか、GL2系にとどまるべきか

oFでシェーダを活かしたナイスなAddonに ofxPostGlith や ofxPostEffect を、参加したOFセミナーで教えていただきました。これらは共に GL2系のglsl で書かれています。

oF公式のShaderチュートリアルでは、GL2、GL3、ES2 がすべて添付されて、実行環境ごとに最適な物に切り替えられるようサンプルが作られています。

常に最新についていった方が将来幸せですし、最近話題のMRTを使ったDeferred Renderingなんかも視野に入れると、早めにGL4.0な書き方に移行していくのが望ましいのですが、学習中の身としては、サンプルの多いGL2.0系が捨てがたいです。

Three.js r68

WebGLOpenGL ES 2.0 をベースにしています。GL ES 2.0 はOpenGL本筋で言うと GL2.0 相当なので、2004年リリースと、結構古いです。OpenGLの歴史についてはWikipedia参照。

OpenGL - Wikipedia

このことは以下の様な手順で確認出来ます

  1. Three.js のサンプルから適当なページを開いて
  2. Developer Tools を開き
  3. rendererの初期化後の箇所にブレイクポイントをはってリロードして止めて、
  4. Consoleで以下の様なコマンドを叩くことで確認出来ます
_gl = renderer.context; // WebGLのコンテキストを取得する//WebGLRenderingContext {drawingBufferHeight: 150, drawingBufferWidth: 300, canvas: canvas, activeTexture: function, attachShader: function…}

_gl.getParameter(_gl.VERSION); // WebGLのバージョンを確認する//"WebGL 1.0 (OpenGL ES 2.0 Chromium)"

_gl.getParameter(_gl.SHADING_LANGUAGE_VERSION); //シェーディング言語のバージョンを確認する//"WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)"

実際にやるときはこんな画面です

f:id:AMANE:20141013214708p:plain

ちなみに、上記のやりかたを見つける上で、この資料が役に立ちました。WebGLで利用できる関数や定数が一覧になっています。

WebGLリファレンス(PDF)

WebGLでは今のところ選択肢無し

WebGL 2.0 で GLES 3.0 相当になる、と言うのが、ドラフトで発表されていますが、それも今年8月の話なので、(少なくともThree.jsは) しばらくはWebGL 1 (つまりES2.0相当) のつもりでいれば良いかな、という認識です。

WebGL 2 Specification

Three.js のシェーダのサンプルが非常に充実している件

Three.js のShaderをつかったサンプルは、ただシェーディングだけでは無く、gpgpu的な使い方をした物もあり、非常に参考になります。これらを教材(やパクリ元)として使わない手は無いので、その点で ES2.0 にとどまる大きなメリットがあると言えます。

three.js - examples

Processing 3.0a4

Processing follows the specification set by OpenGL ES,

公式にはこのように書いてあります。 Processing 3.0 として配布されているサンプルをいくつか覗いてみたところ、varying や texture2D といった記述があるところから、 たしかにES 2.0 つまり glsl 1.0 相当であることが確認出来ます。

ただし、GL3.0 以降に対応していないと言うわけではなさそうです。

Processing で GL3.0 以降を使ってみる

このフォーラムが参考になりました

このフォーラム下の方に記載されているサンプルは、そのままでは動きません。PJOGLのプロファイル(詰まり、利用するGLのバージョン)を切り替える必要があって、そのためには、以下のコードが必要です。

// glsl150test.pde import javax.media.opengl.GL3;
{PJOGL.PROFILE = 3; } // PJOGL内部でProfile=3と指定すると、GLES3.0が利用される

Pshader shader;

voidsetup()
{
// 以下略

グラデーション出塗りつぶすだけの超簡単な物ですが、実働するサンプルを githubに上げました。

f:id:AMANE:20141014230157p:plain

izmhr/processingGLSL150test

ナイスな作例

こちらで実際にgithubに上げられている作例は非常に良い感じです。

  • ジオメトリシェーダで分割をするサンプル

このあたりは、ES 3.0 を利用して実現しているようです。

しかしやはりES2.0がまだまだ隆盛

とまぁProcessingでも ES3.0 が使えることは確認出来たのですが、公式のサンプルや下記のイケてるチュートリアルも ES 2.0 系で書かれているので、 3.0以降に移行するメリットは今のところ(僕には)少なさそう、という印象。

Geometry, Textures & Shaders with Processing – Tutorial

おまけのAndroid

実際にAndroidでGLばりばりな開発をしているわけでは無いのではっきりとしたことは言えませんが、Androidの次のバージョン Android L で、OpenGL ES 3.1 をサポートすることになっているようです。 OpenGL ES 3.1 は、本家OpenGL出言うと OpenGL 4.4 / GLSL 4.4. 相当のようです。

iOSはよくわからないっす

まとめ

結論としては、私は暫く、GL 2.1 / glsl #version 120 な書き方をしようと決めました。理由は、多くのサンプル・公開されている作品が、未だGL 2.1 , ES 2.0 系なシェーダ言語で書かれているからです。しかし一方で、あれこれ読んでみた結果、多少の接頭辞を変換すれば 3.0 以上へ対応するのも、めちゃくちゃ大変というわけではなさそうな印象を持ちました。

まずは、Vertex Shader, Fragment Shaderの基本を、2.1系で学び、MRTやテッセレーションなどの技術が必要になったら、改めて 3.0 以上に移行していこうと思います。

CreateJSで 2D 線分の交差判定

$
0
0

はじめに

2Dにおける物体どうしの衝突判定アルゴリズム、またはその一部として、線分同士の交差判定が必要になりました。

f:id:AMANE:20141028222308p:plain

アルゴリズム

今回は、こちらの記事を忠実に実装させていただきました

2D衝突編 その10 線分と線分の衝突

線分ですので、

  • 始点 + ベクトル(長さを持つ)
  • 始点 + 終点

のいずれかが分かっていれば良いのでお気楽です。数回の外積計算でフィニッシュです

実装

コードはgithubにあげました

izmhr/lineCrossing

izmhr/lineCrossing · GitHub

使ってるライブラリ

EaselはCanvasを使いやすくラップしてくれているライブラリです。愛しています。

Victorは、2Dのベクトル関連計算のライブラリで、長さを求めたり、内積外積を計算したり、回転指せたりお手の物です。それにベクトルを「定数倍」する関数が無かったので、足した、気がします。

staticな関数もあるvector2dの決まり手的ライブラリってどれなんだろう…教えてエロイひと

ポイントだけ

side.js (辺、の意のつもり) line15 が、公差判定の関数です

Side.prototype.crossing = function(_start, _end)
{// http://marupeke296.com/COL_2D_No10_SegmentAndSegment.htmlvar v = this.start.clone().subtract(_start);
  var v1 = _end.clone().subtract(_start);
  var v2 = this.end.clone().subtract(this.start);

  if(v1.cross(v2) == 0) returnfalse;

  var t2 = v.cross(v1) / v1.cross(v2);
  var t1 = v.cross(v2) / v1.cross(v2);

  if( 0 <= t2 && t2 <= 1 && 0 <= t1 && t1 <= 1)
  {// crossing pointvar cp = _start.clone().add(v1.scalarMultiply(t1));
    this.color = '#f33';
    return{point: cp, distance: t1};
  }else{this.color = '#fff';
    returnfalse;
  }}

_start_endは、交差する候補の線分の始点終点です。

変数名は、元記事様の変数名と合わせてあります。

線分同士が交差していたら、その {交点と、始点から交点までの距離} を返します。交差していなかったらfalseを返します。

サンプルプログラム

サンプルでは、三つの線分と回転し長さを変えられる線分を用意し、回転する線分の始点から見て、線分との交点の中で最も近い点を検出する、ような物にしてみました。

複数物体や複雑形状への衝突判定に利用するイメージです。

いじょうでふ

改善版 reverse_iterator 使用中のerase()の仕方

$
0
0

2010年5月の記事にコメントいただいた

reverse_iterator使用時のerase()の仕方 - 自習室

reverse_iterator使用時のerase()の仕方 - 自習室

この記事に、メモリ衝突が起きるよ、というコメントをいただきました。

自分がこの記事を書く際に使ったコードが見当たらなかったので、改めてそれらしく書いてみました。確かに、イテレータの進め方など結構気を遣わないと、直ぐ見つからないところを叩いたりしてしまうクソコードでした。

不理解だったところ

reverse_iteratorが、通常の iteratorのアダプター(特定の目的のためにラップして使いやすくする)オブジェクトだ、ということを理解しておりませんでした。

このページの一番上の図と説明が分かりやすい。

std::reverse_iterator - cppreference.com

Reverse iterator stores an iterator to the next element than the one it actually refers to
リバースイテレータは、そのリバースイテレータが指している要素の(正順での)一個先を指している(正順)イテレータを保持している

と書いてある。関係性を式で表すとこうなる

&*r == &*(i-1)

そうすると確かに、eraseのために、現在見ている reverse_iteratorに対応する iteratorを取得しようと思ったら、 base()で対応するイテレータを取得した後、一個戻す、が仕様上正しい操作だ、という気がしてきます。

hogelist.erase(--(hoge_ri.base()));

ここまでの内容を図解したのが下の図。

f:id:AMANE:20141102174443p:plain

標準iteratorとしてerase()したあと、リバースイテレータはどこを指しているのか?

この点は自分もいろいろ混乱したので、図解します。

f:id:AMANE:20141102174454p:plain

上でも書いたように、リバースイテレータは通常のイテレータのアダプタというかラッパなので、本体であるイテレータが指すものから上記関係式で導き出される対象を指しています。erase()した結果、通常イテレータの場所は変化していませんが、それに対応するリバースイテレータが、リスト上では一個前に進んだことになります。

従って、ri++で(逆向きに)進んでいたとしたら、erase()した時には、riは自動的に次の要素を指しているので、ri++は不要、と言うことになります。

サンプルコード

charとint をメンバに持つクラスHogeのlistを作り、その中からユーザのキーボード入力で指定されたintの値を持つhogeを一個ずつ消していく、という内容です。このサンプルでは、特にリバースである必然性はありません。

そもそも2010年の元記事でリバースイテレータを使った理由は、OpenGLで描画をしながら、不要になったオブジェクトを消す、と言う操作を、1回の反復操作で行いたい、というものでした。OpenGLでは後から描いた物が先に描いた物の手前に上書きされるので、リストの作り方次第では、逆順に描画をコールしたいケースが発生します。

全文はこちら

リバースイテレータでリストを回しながら、 時折 erase を行う

大事なとこだけ抜粋します

while(hoge_ri != hogelist.rend())
        {
            if(hoge_ri->check(value)) //当該Hogeインスタンスが value と同値のメンバを持っていたら
            {
                hogelist.erase(--(hoge_ri.base())); // 消す(と同時に進んでいる)
                cout << "###erase### "<< value << endl;
            }
            else
            {
                hoge_ri->print(); // 持ってなかったら標準出力して
                hoge_ri++;  //進める
            }
        }

先述の注意点の通り、消したときは、hoge_ri を ++ しておりません。

最後に

そもそもリバースイテレータを必要としない構造で書いた方が、可読性も上がるし良いよなーと思いました。

JavaScriptでニュートン法を用いて三次方程式を解いて、ついでにグラフも描く

$
0
0

初めに

完成品

ここで動きます

動機

そもそもの目的は、楕円の法線を求めるために四次方程式を解くことだったのですが、まずは手始めに三次方程式を解くことにしました。結果、高校時代に勉強した内容を思い出して、懐かしいような気分に浸れて、変な楽しさがありました(笑)

解の公式を使えば良いのでは?

三次方程式も四次方程式も解の公式が知られていますが、たとえば三次方程式を解く「カルダノの方法」だと、

{ \displaystyle
B = x^{3} - 15x - 4
}

という式を解いて x = 4 を算出することが出来ないなど、汎用性の乏しさが知られています。

三次方程式 - Wikipedia

ニュートン法を使う

この手の計算では一般的に使われているらしいニュートン法を利用する事にしました。

Newton 法による方程式の近似解法

三次方程式は実数解を最低ひとつは持つことが明かですので、まずはニュートン法で実数解をひとつ求めて、残りの解(虚数解も含む)を求めるような関数を作ります。

コード

コードはこちらに上げてあります。

izmhr/newtonCubicEquation

izmhr/newtonCubicEquation · GitHub

場合分け

ポイントだけ解説します

計算をやりやすくするために、特徴的な係数や特徴的な解が得られる場合をあらかじめ場合分けします。やり方にはいろいろあると思いますが、今回のプログラムで採用している場合分けについて紹介します。

{
f(x) = ax^{3} + bx^{2} + cx + d = 0
}

を解きます。

解に0 が含まれる場合

言い換えると、定数項 {d=0}の場合。

{ \displaystyle
f(x) = ax(x^{2} + \frac{b}{a}x + \frac{c}{a}) = 0
}

を解くことになります。 これは一般的な二次方程式の判別式を用いて、残りの2解がどうなるかを場合分けします

{
D = b^{2} - 4ac
}

とすると、

  • { D \gt 0}なら、0に加えて異なる実数解が2つ
  • { D = 0}なら、0に加えて、実数の重解1組
  • { D \lt 0}なら、0に加えて、共役虚数解1組

がそれぞれ存在します。

解に0が含まれない場合は、ニュートン法を用いて、1つ目の実数解を求める

が、そこであたえた近似開始値が解そのものだった場合

ニュートン法の近似開始値{x_k}に対して

{
ax_k^{3} + bx_k^{2} + cx_k + d = 0
}

この{x_k}をそのまま解の1つ目の実数解として利用する

近似開始値が、極値をとるxであった場合

この場合、ニュートン法が収束しなくなるので、別の近似開始値{x_k}を使うよううながす。私のプログラムでは0.1加えるようにしているが、万能ではないのでご注意です。

ニュートン法で1つ目の実数解が求まった後

ここでも判別式を利用する。ここで利用する解のパタンを判別する式については、こちらのサイトが詳しいです

http://www2.odn.ne.jp/~aai55890/donnwa2/sanzihannbetu.htm

 {
D_1 = b^{2} - 3ac
}

 {
D_2 = 27a^{2}b^{2} - 18abcd - b^{2}c^{2} + 4b^{3}d + 4ac^{3}
}

  • { D_1}は、{ f^{'}(x)}の判別式。グラフの形状の把握に使う。
  • { D_2}は、{f(x)}極値{f(\alpha), f(\beta)}に対して、{f(\alpha)f(\beta)}で算出される値で、これも判別式として利用する。x軸との交差回数の判定のために使います

詳細は先ほどのサイトに。

{ D_1 \gt 0}かつ { D_2 \lt 0}のとき

ことなる実数解3つが存在する。1つ目の実数解{x_0}を用いると、解きたい方程式は

{
f(x) = ax^{3} + bx^{2} + cx + d = ax(x - x_0)(x^{2} + Ax + B) = 0
}

と書き直すことが出来、二次方程式を解けば良いことになる。

{ D_1 \gt 0}かつ { D_2 = 0}のとき

このとき、異なる実数解2つで片方は重解になる。 ここで、先のニュートン法で求まった実数解が重解の一部である場合と、独立した解である場合の2通りがあり得る。

ここで、{ x^{2} + Ax + B = 0}が、重解を持てば、{x_0}は単独の解であったということになりますが、{x_0}ニュートン法で求めた解であるため、導き出されるAやBも、誤差を含む値になります。従って、 { x^{2} + Ax + B = 0}が重解を持つかどうかの判別は、

{ A^{2} - 4B = 0}

ではなく

{|A^{2} - 4B| \lt Thresh}

(ここで Threshは、十分に小さい値) という形で行うことになります。 これが満たされれば、{ x^{2} + Ax + B = 0}は重解を持ち、元の{x_0}に加えてもう1解算出すれば良いです。

満たされていない場合は、

{
f(x) = ax^{3} + bx^{2} + cx + d = ax(x - x_0)^{2}(x - x_1) = 0
}
{ x_1 = -\frac{d}{x_0^{2}a}}

が、もう一つの解になります。

それ以外の場合

実数解は初めの1つだけで、残りは共役な虚数解を持つことになります

ウェブアプリとして仕上げる

機能

機能として、以下の様な物を実装しています

  • 主要機能
  • 可視化関連の機能
    • 与えられた三次関数のグラフを描画
    • 実数解をプロット
    • グラフのズームの調整
  • (おまけ) 手っ取り早く試せるよう、サンプルの関数を5つプリセット

CreateJS を利用

グラフの描画は、Canvasに対してCreajteJSを使って行っています。D3などの利用も考えましたが、最近よく使っていて手が慣れてたのでCreateJSを利用しました。

さいごに

  • 算術
  • Canvasの描画
  • ツールとして機能を設計してまとめ上げる
  • htmlのインプットタグなどを使いこなす

など、結構やることが多くて、勉強になりました。インプットタグを使うのが意外としんどかったです。

実際は虚数解が必要になるようなケースはあまりないので、正しい制約下で必要な実数解を最短で算出することが求められるようなことの方が多いでしょう。まだほとんど知らないのですが、次は非線形最適化のツールなど使ってみようと思っています。

 {
Y(n) = a_nX(n) + a_{n-1}X(n-1)
}

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows)

$
0
0

はじめに

顔認識させつつ、ビデオスルーが遅れていないことを示そうとしたら、思いがけずEXILEっぽくなりました。こんばんは。

動機

OVRVISIONをしばらく前に手に入れて放置していたのですが、何か遊ぼうと思い、OpenCVを使ってみたくなりました。カメラ画にエフェクトかけてみたり。

@hecomi 先生のこれがど直球。これこれ。

Ovrvision で色んなエフェクト試してみた - 凹みTips

Ovrvision で色んなエフェクト試してみた - 凹みTips

下調べ

最終的にOculus Riftとつなぎたいので、Unityでやります。 UnityでOpenCVを使う口のすてきな紹介記事様がこちら

UnityでOpenCVまとめ - 株式会社CFlatの明後日スタイルのブログ

UnityでOpenCVまとめ - 株式会社CFlatの明後日スタイルのブログ

  • OpenCVSharpが使いやすそう。こまめにアップデートされてるので安心感もある

  • しかしパフォーマンス落ちそうな気がするのとOpenCVならC++で書きたい、ってのとで、Unityのnative plugin化して使うのも押さえておきたい

というわけで二方向からトライすることにしました。今回はOpenCVSharpを使ってみます。

環境

ソフト
ハード

3年前のミドルエンド、のつもりデスクトップです。

基本をやってみる

まずは @kaorun55 先生

UnityでOpenCVを使う(Windowsアプリ)

UnityでOpenCVを使う(Windowsアプリ)

これでとりあえずOpenCVSharpでカメラ画像を撮ってきてUnityで表示するとこまでできました

からの @kaorun55 先生!

せっかくだから顔認識とかしたいです。ここも @kaorun55 先生です。

OpenCVで顔検出した場所にUnityのGameObujectを追従させる

OpenCVで顔検出した場所にUnityのGameObujectを追従させる

ありがとうございます、できました。

しかし、私の環境では 5~6 fpsしか出ませんでした。これはつらいです。

顔認識のマルチスレッド化

認識に足を引っ張られて動画がかくかくなのはかっこわるいので、撮ってきた画像を表示しつつUnityのオブジェクトを描画するスレッドと、顔認識をするスレッドを分けましょう。

お勉強

C#のマルチスレッドの書き方を全く知らなかったのでそこの勉強からです

lockステートメントが大変便利ってことがわかった!

やってみる(本記事のメイン)

Post Position 【Unity】 スレッドを使う記事様のやり方で二つスレッドをたて、 OpenCVで顔検出した場所にUnityのGameObujectを追従させる記事様でやっているカメラ画像の取得と顔認識の処理をそれぞれのスレッドでやる、という方針です。

詳細はこのあたりのコードをご覧ください

UnityOpenCVSharp/FaceDetectThreaded.cs at master · izmhr/UnityOpenCVSharp · GitHub

一考

結局顔認識が 5~7 fpsなのは変わっていません。

ビデオスルーがなめらかになったのは良かったのですが、顔認識が遅れているので、顔とは異なる場所にCubeが表示されてしまいます。「顔を隠す」などアプリ次第では、ビデオスルーを遅くしてでも顔認識と画像が同期している方が適切な場合もあるかもしれません。

逆に、遅い顔認識の結果を補間(予測)して使う、という方向性もあるかと思いますが、難しそうなのでまたいつか。

(おまけ) カメラ画像が崩れているのを修正

@kaorun55 さんの記事では、CVのカメラで撮ってきた画像をUnityのオブジェクトに貼り付ける際に、bmpにしたところで画像が乱れていました。これはOpenCVSharpのバグなのでしょうか…*1

f:id:AMANE:20141206230112j:plain

試行錯誤の結果なので最適とはいえませんが、修正の仕方を見つけたので報告いたします。

Jpegを経由する

実際はばらばらの場所で行っていますが、行った処理だけ抜粋します

// カメラ画像取得// static Mat capImage;
video.Read (capImage );

// jpegのバイナリに変換// static byte[] cvtImageJpeg;
cvtImageJpeg = capImage.ImEncode(".jpg");

// テクスチャデータとする
texture.LoadImage(cvtImageJpeg);
texture.Apply();

これでテクスチャ内での画像ずれが無くなりました

さいごに

今回のコードはGitHubにあげてあります。

izmhr/UnityOpenCVSharp

izmhr/UnityOpenCVSharp · GitHub

OpenCVSharp/OpenCVの dll のたぐいは @kaorun55 さんの記事 UnityでOpenCVを使う(Windowsアプリ)を参考に入れ直してください。

*1:ちょうど最新のリリースで Mat -> Bitmap 変換のバグの修正が入ったようなのですが、これが関係しているのでしょうか…? Release 2.4.10 (11 Nov., 2014) · shimat/opencvsharp · GitHub

UnityでOpenCVを Native Plugin にして利用する (Windows)

$
0
0

はじめに

UnityでOpenCVを使いたい動機と下調べについては前回の記事に書きました

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows) - 自習室

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows) - 自習室

今回は、OpenCVを native plugin 化して使う方法についてまとめます、というか、 @hecomi 先生のをなぞった時に出た問題点をまとめておきます

環境

参考にした記事

基本(ただしMac)

この記事で、@hecomi 先生が OpenCVを native plugin 化して使う方法についてまとめてくださっています。基本はこれですが、内容がMacでbundleな感じです。

Unity で OpenCV で作成したテクスチャをネイティブプラグイン経由で利用してみた - 凹みTips

Unity で OpenCV で作成したテクスチャをネイティブプラグイン経由で利用してみた - 凹みTips

公式の基本(ただし英語)

Windowsでのやり方は、公式のLive Trainingで簡潔に説明されていました。前半はC#でManagedなpluginの説明で、23分あたりから、C++で作る Nativeなプラグインの説明になっています。ランダム関数を回して適当に数値を返すだけのプラグインを例にしているので、英語ですがわかりやすいと思います。

Live Training: Introduction to Plugins - YouTube

dllを作ること自体は Visual Studio Expressでもできますが、作った native Pluginを使うことは、Unity Proでないとできません。このあたりはUnityの厳しいところですね。

応用 Windows8.1 で、DllNotFoundException への対処付き

また、 @hecomi 先生が別の記事で、OpenCVのスタティックライブラリをラップしたdllにする方法についてもまとめくださっています。この記事で通常のlibを使ってdllにするとDllNotFoundException が出る、と報告されていますが、私のところでは解消できましたので後ほど紹介します。

Unity と OpenCV を組み合わせて現実・仮想双方を加工した AR な世界を Oculus Rift 越しに覗いてみた - 凹みTips

Unity と OpenCV を組み合わせて現実・仮想双方を加工した AR な世界を Oculus Rift 越しに覗いてみた - 凹みTips

やること

ここでは試しに、先述の Windows8.1 の環境下で、@hecomi さんの一つ目の記事でやられていた、 OpenCVでカメラキャプチャーしてウィンドウを開いて表示しつつ、Unity内でテクスチャとして利用する、をやってみようと思います。

手順

プロジェクトの作成

このあたりは、Unity - Writing Pluginsを参考に。

  • Visual Studio
  • VC++ / Win32 Application を
  • Application type: DLL
  • Additional Options: EmptyProject でつくる

f:id:AMANE:20141212212952j:plain

OpenCV周りのプロジェクト設定をする

PROJECT > Properties からいろいろ下記のような設定します

追加のインクルードディレクトリ

OpenCV関連のヘッダを読めるようにします。適宜OpenCVをインストールした場所に読み替えてください

f:id:AMANE:20141208233647j:plain

OpenCVのスタティックリンクライブラリを利用する

OpenCVをせっかくdllとしてラップするので、別途 OpenCVのdll群を使わなくてもよいようにしたいです。ユーザにOpenCVをインストールさせたり、完成したアプリのフォルダ内にdllをたくさん含んだ状態で配布するのはちょっといけてない感じです。

そこで、OpenCVからリリースされている <OPENCV_ROOT>\build\x86\staticlib.libファイルたちを利用するように指定します。これを使って以下ので順でdllを作成すると、すべての .libファイルが一つのdllに固められて、そのdllだけをユーザに渡せばいい状態になります。

f:id:AMANE:20141212213158j:plain

ランタイムライブラリをマルチスレッド(/MT)に変更

ここは @hecomi さんの受け売りです。

f:id:AMANE:20141212212939j:plain

DLL化のためのおきまりのコードを書く

#include <iostream>#define DLLExport __declspec (dllexport)extern"C"
{
    DLLExport int GetRandom()
    {
        return rand();
    }
}

先ほど動画を貼ったLive Trainingでは、上記のようなコードで ランダムな数値をはき出すだけの機能を dll 化しています。同様の手法で@hecomiさんのこちらの記事では、OpenCVを使ってカメラをたたいたり、別ウィンドウで表示したり、Unityのテクスチャとして使えるようにしています。コードは @hecomiさんの記事を参考にされてください

DLL化のために必要なスタティックライブラリをリンクする

私の環境ですと、 @hecomiさんの記事 の通りだとライブラリが不足しているようで、unresolved external symbolエラーが大量発生します。エラーは下記のようなものたちで、多くはOpenCVのDLL本体に含まれているもののようです。これらもリンクするようにして、最終的には以下のような感じになります。

f:id:AMANE:20141212213644j:plain

このあたりは、こちらの記事様で勉強させていただきました

ビルド→Unityで使う

BUILD -> BUILD <Project Name>

で、ビルドされ、ReleaseなりDebugなりのフォルダに .dllファイルが生成されます。

これを、Unityで Assets/Plugins/hoge.dllの位置に置きます

dllで定義された関数をUnityで利用する際は、以下のようにDllをインポートし関数を宣言するコードを用意し、オブジェクトにアタッチして使います。これは先述のUnity公式Live Trainingでの例です。

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

publicclass TestNative : MonoBehaviour
{
    [DllImport("RandomNumberDLL")]
    privatestaticexternint GetRandom();

    // Use this for initializationvoid Start ()
    {
        print("Native Random Number: " + GetRandom());
    }

}

同様に @hecomi さんの記事を参考に、dllに定義したOpenCVを使った関数を呼び出してください

その2:スタティックライブラリを使わない場合

先述の Unity公式 live Trainingと同じやり方になります。

通常のライブラリファイルをリンクする

ProjectのPropertiesで staticlibフォルダを参照するように指定している追加のライブラリディレクトリを、 libフォルダを参照するように書き換えます。

f:id:AMANE:20141212220007j:plain

ランタイムライブラリを /MD にする

f:id:AMANE:20141212220134j:plain

システム環境変数OpenCVのDLLのありかを通す

Pathに以下の二つを記入します (F:\develop\opencv\の部分は、ご自身の環境に合わせてください)

F:\develop\opencv\build\x64\vc12\bin; 
F:\develop\opencv\build\x86\vc12\bin;

はじめ x64のものだけを追加していたのですが、 dll を 32bit でビルドしてたため、DllNotFoundException が発生しました。 x86のbinもPathに通したら、エラーがなくなりました。

ビルドなど以下略

ここから先は、staticlibを使う場合と同じです

最後に

これで、 @hecomi さんの記事のように、カメラ画像がテクスチャに貼れて、同時に別ウィンドウが開きカメラ画像が見られたらOKです。

@hecomi さんありがとうございました。

Unity + Visual Studio で、Managed Plugin をデバッグする (Windows)

$
0
0

はじめに

前回、OpenCVを 必要な分だけ Native Plugin の DLL としてまとめて利用する方法について書きました。

UnityでOpenCVを Native Plugin にして利用する (Windows) - 自習室

C++のライブラリを使ってC++のコードを書いて、Native Plugin として利用できるのは良いのですが、Unity Editor での実行中に、C++側のデバッグができるんかい?という疑問がわきました。

今回はそのあたりを調べてみました。ついでにManaged Pluginのデバッグの仕方についても調べたのですが、分量の関係で Managed/Nativeで2回に分けることにしました。

環境

今回もがっつり Windows + Unity Pro 限定な内容になっておりますがご容赦ください。

題材

今回の記事は、Live Training "WRITING PLUGINS"の作例に対してデバッグできるよう改変を加えています。プロジェクトの作り方、コードの書き方、ビルドの仕方はこちらを参考。

Unity - Writing Plugins

GitHubにあげました

記事はmanaged/nativeで2回に分けましたが、プロジェクトは一つにまとめてあります。

izmhr/WritingPlugin

まずは Managed Plugin から

UnityVSでできるんじゃないか?と天啓を受けて調べてみたら、確かにありました。

UnityVS の使用 - Visual Studio Tools for Unity | MSDN

Managed(C#) Plugin は上記事に書いてあるとおりでできますが、目立ったところだけこちらにメモっておきます。ちなみに、最後のデバッグの開始部分は、上のリンクと少し異なることをしています。上のリンクの仕方でもできますが、本記事のやり方の方が少し楽なので紹介いたします。

Target Framework: .NET Framework 3.5

Unity の Mono が .NETで言うところの 3.5 相当らしいので、そうしておきます。これをやらなくてもDLLのビルドはできるのですが、プロセスにアタッチしようとした際にエラーが出て止まります。

厳密には Unity 3.5 .net SubsetBase Class Librariesを選ぶのが正しいようです。.NET と Mono は微妙に異なる部分もあるようですし。

PROJECT > PROPERTIES > Application > Target frameworks:

f:id:AMANE:20141215213807j:plain

出力先を Assets/Plugins にする

いつも通りの $(SolutionDir)\(Configuration)\な場所に出力したdllらをあとから Assets/Pluginsにコピーすればいいかと思ったら、VSプロジェクトでのファイル構造などデバッグに必要な情報が、DLLファイルと一緒に書き出される .pdbファイルに含まれているようで、ビルド→出力 の時点で、利用する場所に書き出される必要があるようです。

PROJECT > PROPERTIES > Build > (下の方)Output > Output path

f:id:AMANE:20141215214510j:plain

ブレイクポイントを使ったデバッグ

あらかじめ Solutionの Properties から、現在選択しているプロジェクトが実行されるようにしておくのがおすすめです。

f:id:AMANE:20141215214829j:plain

Unity Editorも起動した状態で、VSの方で今回デバッグしたいManaged Plugin のプロジェクトを選択し DEBUG > Attach Unity Debuggerを実行すると、下のようなウィンドウが開きます。もしここが空欄だった場合は、一度 Unity の方で Play しておくと、出るかもしれません。

f:id:AMANE:20141215215355j:plain

これで該当の Unity の Project 名を選択すると、Unityに対してVSのデバッガがアタッチされ、待機状態になります。この状態でブレイクポイントを張って、Unity Editor に戻って Play します。確かに DLL 化された部分のコードでブレイクできています。

f:id:AMANE:20141215215826j:plain

つづきます

と、Managed な Plugin のデバッグ法について整理してみましたが、実際にManaged Plugin を作るシーンが余り思いつかないので、今回は助走です。

本命の Native Plugin のデバッグは次回の記事で扱います。


Unity + Visual Studio で、Native Plugin をデバッグする (Windows)

$
0
0

つづき

前回、 Visual Studioを使って Managed(C#)なPluginを作ってUnityVSを使ってデバッグする方法について書きました。

Unity + Visual Studio で、Managed Plugin をデバッグする (Windows) - 自習室

今回はその続きで、Native(C++) な Plugin をつくってデバッグする方法について書きます。そもそもOpenCVを使いたくてプラグイン化をしているので、今回が本命です。

環境

GitHubにあげました

記事はmanaged/nativeで2回に分けましたが、プロジェクトは一つにまとめてあります。

izmhr/WritingPlugin

Native Plugin の場合

UnityVS/MS 公式によれば、 UnityVSとしてはサポートしていないことになっています。

今回 Unity 向けに調べるまでは知らなかったのですが、もともとVisual Studioには、Windows上で実行中のプロセスにアタッチしてデバッグを行う機能があります。

やってみます。

実行中のプロセスにアタッチ

デバッグしたい Native Plugin のプロジェクトを選択した状態で、

DEBUG > Attach to Process...

と選び、開いたウィンドウで、 Unity.exe を選択します

f:id:AMANE:20141215223451j:plain

その状態でブレイクしたい箇所にポイントを張って、 Unity Editor から Play すれば、ブレイクしてくれます。

f:id:AMANE:20141215224559j:plain

コールスタックを見ると、 Unity.exe!MonoBehaviour::Update()からDLLの GetRandom()関数が呼び出されていることがわかっておもしろいです。

ブレイクされないときがあった

私のリポジトリからCloneしたもので、正しくブレイクに引っかかったくれなかった場合は、一度Unityを閉じてから、Visual Studioの方で Plugin をビルドし直し、Unityの Assets/Plugins のdllを上書きしてから再度実行すると、引っかかるようになります。

最後に

これで Native Plugin もデバッグができるようになりました。前々回の記事OpenCVを Native Plugin 化しましたが、こちらの場合でもちゃんとブレイクできることを確認しています。

UnityでOpenCVを どう使うか - OpenCVSharp vs OpenCV dllを使う環境 vs スタティックライブラリ

$
0
0

はじめに

最近何編かにわたって、Unityで OpenCVを使う方法についてまとめてきました。

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows) - 自習室

UnityでOpenCVを Native Plugin にして利用する (Windows) - 自習室

扱った手法は大きく分けて三つあります

  1. OpenCVSharp を使う
  2. OpenCVのDLLを使う前提で、必要な関数をラップした Native Pluginを作る
  3. OpenCVの staticlib を必要な分だけ取り込んだ Native Plugin を作る

どの手法を使うか、ちょっと考えてみました

それぞれの特徴

1. OpenCVSharp

長所

  • C#だけですんで楽
  • DLLのビルドとかない

短所

  • C++OpenCVに慣れているとちょいちょい混乱する。ちまたのリファレンスが基本 C++なだけに。
  • C++のライブラリを全部ぶっ込み、OpenCVSharp の DLLもぶっこみ、とする必要があるのでオーバーヘッド大。特に配布を考えると。
  • あくまで有志の方が作った物で、公式の最新について行けるとは限らない

2. OpenCVのDLLを使う前提で、必要な関数をラップした Native Pluginを作る

長所

  • (OpenCVが事前にインストールしてある人にとっては) 配布物が最小になる
  • 標準の書き方 = C++で書ける
  • 公式の最新をそのまま使える

短所

  • 利用者がOpenCVをインストールするか、配布物一式にOpenCVのDLLを同封する必要がある
  • ビルドの設定がちょっと複雑
  • デバッグが面倒

3. OpenCVの staticlib を必要な分だけ取り込んだ Native Plugin を作る

長所

  • OpenCVのDLLを使う必要が無いことまで加味すると、Native Plugin の容量が最小になる
  • そのため、おそらく起動も速い
  • 標準の書き方 = C++で書ける
  • 公式の最新をそのまま使える

短所

どう使うか?

こう考えました。

  • OpenCVのたくさんあるリファレンスなどを生かせるので、標準の書き方(C++)にしておきたい
  • いろいろ取り込んでアプリが肥大化するのはかっこよくない

短所については

  • ビルドの複雑さは慣れでカバー

というわけで、 3. staticlib を使ってDLLを作るが良いと考えました。

デバッグが面倒、という件も

  • 一応前回の記事でクリアできたと思っている
  • そもそもDLLにする主旨は、役割の分担を明確にし極力疎結合にすることです。データの受け渡しなど界面をしっかりと設計し、OpenCVで行う画像処理などは C++単体でテストしておいて、使えることを確認した後Unityで使うようにすべきでしょう。つまりデバッグは普通にC++で完結して行う。

という感じの進め方で良いと思っています。

(前回の記事)

Unity + Visual Studio で、Native Plugin をデバッグする (Windows) - 自習室

(タブレットで) 鏡餅を光らせて新年を迎えましょう

$
0
0

この記事は おうちハック Advent Calendar 2014 25日目(なんと最終日!)の記事です。 前日は @K-A-Z さんの 「Arduino+Raspberrypi+GoBotで恋人たちの聖夜を支援する - Qiita」 でした。

ベッドイン検知、まじめなライフログとして王道な利用法も出来る気がします。わくわくしますね。

はじめに

f:id:AMANE:20141224220523j:plain

今年は業務でウェブのクライアント…特にUI周りを作る機会が多かったのですが、自分でサーバサイドから通信そしてUIまでアプリを全部作りきる、ということをやったことが無かったので、アドベントカレンダー締切ドリブンでやってみようと決めました。

正直、アドベントカレンダーだったら何でも良かったのですが、リストをざーっと見てみると、どうも敷居が高い感じでちょいと難しい。そんななか「おうちハック」という響きの緩さに「これならいけるんちゃうか…」とつられてみたところです。ネタはそこから考えました

おうちハック Advent Calendarさん、登録した時点で最終日しか空きがなかったので、クリスマスは終わったことにして日本人らしくお正月ネタにしよう、おもちじゃん、光ったら素敵じゃん、やったー!\(^_^)/

というわけで、おもちを光らせることにしました。

できたものの紹介

使い方を動画で紹介します。

※注記: OMOCHI 単体でも、じんわりと色と背景が変わっていくオートモードでお楽しみいただけます!

公開してます

PCからももちろん利用できます。ノートPCならお餅をのっけるのも可能ですね!

負荷とかセキュリティとかはわかりません!重かったり落ちてたらすみません。

OMOCHI HACK

システム構成

構成は下図のようになっています。OMOCHI側、CONTROLLER側のUI、ブラウザでそれぞれのアドレスにアクセスするとウェブアプリとして表示されその場で使用できます。OMOCHI側は新規作成時に固有の名前をつける必要があります。

f:id:AMANE:20141225104949p:plain

上の動画にもありましたとおり、コントローラからおもちの光らせ方をコントロールできます。この用法だと 「明らかにWebRTCだろ」というおしかりを受けそうですが、甘んじて受け入れます。WebRTCに一瞬トライしたのですが、 難しそうだったのでパスしました。来年頑張ります!

ソースコード

あげてあります。

izmhr/omochi_hack

使った鏡餅

厳密にはこれではないのですが、10インチiPadには「5号」サイズの鏡餅が良かったです!この大きさになると台座も付いてくるので、トップの写真のようにグッと雰囲気が増します。

一応まじめらしい背景

今回のプロジェクトの背景として「おうちハック」の視点から見て2点、抜き出してまとめてみました。

余ったスマホ活用

ここ数年で一気にタブレットスマートフォンが普及し、世代交代も速いため、1人1台や2台にとどまらず、古くなって引出にしまっている端末もたくさん持っている様な状況が(一部のギークの間では)普通になってきたように思います。

Arduinoなどを使うと従来より非常に簡単にフィジカルな入出力が可能で、しかもネットにつながったツールを作り出すことが出来ますが、入出力の自由度を下げてタッチや液晶表示などに限定して良いケースなら、余剰のスマホや利用頻度のひくいタブレット超高性能なネットワークのノードになります。そしてソフトウェアのコーディングだけで済むので、敷居もグッと下がります。

こういったムーブメントは既にかなり広がってきていて、余ったスマホを監視カメラ代わりに利用するのは非常にメジャーです。また、高性能なプロセッサを小型な信号処理部として活用することで、筋電義手を材料費3万円ほどで作ろう、というプロジェクトも動いています。

余ったスマホ、スゴイです。専用のデバイスを買わなくても、家に有るもので皆さん楽しめます。

つながり感通信

おうちをハックするので、ハックして/されて嬉しいのが自分だけじゃつまらないです。家には自分の家族も居ますし、また、遠く離れた生まれ故郷の実家には、自分の両親もいます。そんな 「おうち」どうしをつなげるような道具が欲しいなぁ、と思い、今回ネットワーク越しのコントローラ機能を実装しました。

似たようなプロジェクトで有名どころだと、NTT研究所の一連の研究があります。

また、商品として出ている物もあります。

今回の実装はセキュリティ的にアレゲな感じもしますが、勘弁して下さい。

手軽にパーソナルなクラウド

つながり感通信に関してもう一歩踏み込んでみます。

おうちハック的なプロジェクトは(そんな中から大当たりする物も出てくると信じていますが)、2014年現在は、デバイスやネットワークと使いこなす技術がこなれてきたことによって、多少なりとも技術が使える人が、個人の小さな満足を満たす仕組みを作りやすくなったことから発生している物が多いように思います。俗に言うMAKERSですね。

そういうパーソナルで小規模なサービスをIoTとしてネットワーク上で利用しようと思うと、気軽にクラウドのサーバを利用できることは非常に便利です。今回はさくらのVPSで運用していますが、heroku 的なものも便利だと思います。

実装の話 / さいごに

ざっくり言うと上の図に書いたようなシステムで動いているのですが、自分の技術まとめとして書きます。

ですが、今回は既に記事が長くなってしまっているので、次回に持ち越させてください。

Advent Calendar的にはこんな終わらせ方で良いのかな?? それではみなさん、メリークリスマス & 良いお年を~

(タブレットで) 鏡餅を光らせて新年を迎えましょう | 実装編

$
0
0

はじめに

(タブレットで) 鏡餅を光らせて新年を迎えましょう - 自習室

前回は、おうちハック Advent Calendar 2014 向けとして記事を書きました。そちらでは全体の紹介と、取り組んだ背景みたいなところにフォーカスして書いたので、今回は自分向けに実装で手こずったところ等をメモしていきます。自分用のメモなので雑多でごめんなさい。

目次

  • socket.io でルーム管理。おもち側が閉じたら、繋いでいるコントローラに伝達する仕組みなど
  • 様々なブラウザ・解像度への対応 (軽めに…
  • さくらのVPSに Node.js アプリをデプロイする際のTips
  • そのほか細かい技

おさらいのコード

izmhr/omochi_hack

記事中にコードを展開していくとバカ長くなりそうなので、言及場所にリンクを貼るスタイル。

おさらいの動画

おさらいのシステム図

f:id:AMANE:20141225104949p:plain

socket.io でルーム管理。おもち側が閉じたら、繋いでいるコントローラに伝達する仕組みなど

前回の記事でもちらっと書きましたが、今回の案件、本来なら(おそらく) WebRTC を使ってやるべき案件です。光る端末に対し、リモコンが直接指示を出します。基本は1対1で、始まった後は間にサーバが挟まっている必要はありません。

しかし今回は、自分の不勉強のため短いスパンで WebRTC を使いこなせそうになかったので、使ったことのあるsocket.io を使い、間にサーバが挟まるシステムにしました。そのため、利用者が増えると明らかに不利です。アドベントカレンダー向けのネタアプリですので勘弁してください。

そんな中でも一応こだわって頑張った辺りについてメモしておきます。

room名によるおもちの重複防止

おもちとコントローラの対応付けは、socket.ioが備えているroomの仕組みを使って行っています。roomは一般的なチャットルームを実装するための基本機能なのですが、

  • 存在しないルーム名でjoinしたら、新たにルームが作られる
  • 既存のルーム名でjoinしたら、既存のルームに入る

という動作になっております。

OMOCHI HACK ではこの仕組みを利用しつつ「おもちは必ずオリジナルな名前のルームとして作って、そこにコントローラが名指しでjoinする」仕組みとし、おもちの名前は重複を許さないことにしました。

  • おもち側で存在しないルーム名で入ろうとしたら、joinする → 新たにルームが作られる
  • おもち側で既存のルーム名で入ろうとしたら、既に使われている名前であると警告を出し、再入力を促す

この辺りの処理は、 server.js L62 - L112 あたりにコーディングしてあります。socket.ioのルーム管理とは別に、独自に現存するおもちのリストを管理することで実現しています。

おもち死亡のおしらせをコントローラ側に通知する

通常利用だと、おもち側が閉じるケースとして以下の様な物があります

  • ページをリロードする
  • ブラウザの戻るボタンを利用するなどページ遷移を行う
  • タブを閉じる
  • スマホを放置してしまい画面がロックされる
  • スマホで別のアプリを開く
  • 別の名前のおもちを作り直す

これらを検出したうえで、以下の事をやらなければなりません

  • ルーム(おもち)をリストから削除する(利用された名前がたまってしまわないよう)
  • おもちが消えたことをコントローラに通知する
window.onpagehide を利用する
  • ページをリロードする
  • ブラウザの戻るボタンを利用するなどページ遷移を行う
  • タブを閉じる

この3パタンについては、window.onpagehideで検出できます。はじめ window.onbeforeunloadで書いていたのですが、Safari@iOS8 ではこのイベントが使われなくなって居ることを知り、pagehide に書き換えています。

この辺りの処理は、light.js L133 あたりにコーディングしてあります

socket.io の disconnect イベントを検出する
  • スマホを放置してしまい画面がロックされる
  • スマホで別のアプリを開く

この2パタンの場合、私が調べた限りではウェブアプリがそれを検出して何かする、というのが出来ませんでした。しかし、socket.io の方で、クライアント(ここではおもち)が不活性な状態を検出してdisconnect イベントとして処理する仕組みがあるようで、それを利用する事にしました。

具体的には、disconnectイベントを送ってきたsocketのidを調べて、それがおもちリスト(コード内では lightlist )に存在するか調べ、していたら削除する、と言う物です

この辺りの処理は server.js L49 - L55あたりにコーディングしています

イベントを拾えるケース
  • 別の名前のおもちを作り直す

最後のパタンは、サーバ側で処理しています。自分が既におもちとしてroom名を持っていて、それと同じ名前で作ろうとした場合は、何もせず既存のroomを利用します。新しい名前を指定した場合は、さっきまで使っていたroomを破棄し、新しいroomを作ります。

この辺りの処理は、 server.js L105 - L109あたりでコーディングしています。

おもちが消えたことをコントローラに通知する

上記パタンでおもちが消えたとき、コントローラ側は、カラーコントロールのUIがdisableされ、再度おもちの名前入力を要求される画面になります。これで、接続が切れたことをコントローラ側からも認識出来ます。この辺りの処理は sever.js L138controller.js L123にコーディングしてあります。

f:id:AMANE:20141226202130p:plain

様々なブラウザ・解像度への対応 (軽めに…

ちまたのウェブデザイナ、ウェブコーダ様方にあたられましては、日々多様化するディスプレイの解像度や、ブラウザごとの微妙に異なるCSSの解釈に日々頭を悩ませていることと存じ上げますが、私も今回のアプリを作り上げるに当たりまして、「出来る範囲で・時間が許す範囲で」広めに対応を取ってみたところです

動作確認しているのは以下の環境

です。すべて最新の物です。

レスポンシブ的CSS切り分け

  • @media screen and (min-width: 320px) and (max-width: 480px)的な物を使う

vendor prefix

-webkit-transform-moz-transformとか。

ブラウザごとの対応状況を調べられる。おなじ webkitでも、Chromeではつかえて、 safari@iOSじゃ使えない、とかかなりよくある。

Chrome for Androidborder-radiusが微妙に効かない件

コントローラの円形のカラーピッカーを描くのに <div>に対して四隅50% でradiusをかけようとしたが、Androidでだけうまくいかない。

f:id:AMANE:20141225220038j:plain

ここを参考に修正

.selector{/* だめ */border-radius: 50%;

/* だめ */border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
border-bottom-right-radius: 50%;

/* OK */border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
border-bottom-right-radius: 49.9%; /* ここがポイント *//* これでもOK */border-radius: 50%50%50%49.9%;
}

この記事では Galaxy S4 で、 と言っている。私の場合は Nexus7 (2013)。機種依存かもしれない。

さくらのVPSに Node.js アプリをデプロイする際のTips

基本

forever さまさまです。

この記事では /etc/nginx/conf.d/内にリバースプロキシの設定を書いていますが、

  1. /etc/nginx/sites-available/内に今回のアプリ用の新しい設定ファイルを作っておき
  2. /etc/nginx/sites-enabled/シンボリックリンクしておくのがいまどき、なはず

linux - What is the different usages for sites-available vs the conf.d directory for nginx - Server Fault

自分が作ったサイトの設定ファイルはこんな感じ

# /etc/nginx/sites-available/omochi_hack

upstream omochi {
    server localhost:3000;}

server {
    listen 80; 
    server_name omochi.izmiz.me;

    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://omochi/;}}

VPSのポート設定

そういえば以前iptablesで厳しくポートを絞っていたのを忘れていました。express が ポート3000番でサーバをあげているので、あけてあげなくちゃいけません。

sudo ufw allow 3000/tcp

おなまえ.com のDNS設定

リバースプロキシに設定した omochi.izmiz.meがちゃんと解決出来るよう、DNSに覚えていただきます

おなまえ.com >ログイン >今回のドメイン> (タブ)ドメイン設定 >DNS関連機能設定 >今回のドメインを選んで「次へ進む」 >DNSレコード設定

ログインした状態で直リンク >https://www.onamae.com/domain/navi/dns_controll/input

普通にたどるととんでもない階層にいます。ほとんどここしか使わないのに…!

ここに、 nginx の sites-availabe に設定した server_name を登録します。

以上

以上で、 http://omochi.izmiz.meにアクセスすると、 さくらVPS内の expressが立てている 3000 番ポートで動いている OMOCHI HACK アプリにアクセス出来るようになりました。

そのほか細かい技

今回のアプリで参考にさせていただいたその他のノウハウをまとめておきます

Canvas + image でカラーピッカー

letter-spacingしたテキストをセンタリングする

index.html L25 - L32

letter-spacing: 1emすると、文末にも1文字スペースが空いてしまうので、その分文末に負のマージンを与えるか、文の頭に正のマージンを与える

ブラウザの「ホーム画面に追加」を利用する

これをしてホーム画面からアイコンタップで起動すると、全画面でアプリが開きます。ここで登録されるアイコンについての覚え書き

log4js でログ取り

ロギングのセッティングを jsonで外部化出来るのが素敵。

内で1行のテキストを垂直方向にセンタリング
.selector{height: 100px;
  line-height: 100px; // heightline-heightに同じ値を指定する
}

JavaScriptHSV ->RGB変換

jQuery.delay()が便利

jQuery.val()で form の値を取得

jQueryセレクターを取得

$something.selectorで取得 出来るのだけど、 deprecated. どうしましょう。今回使ってしまいました。

カラーホイールの絵の描き方

さいごに

今回、Advent Calendar締切ドリブンで、UI、通信、サーバサイド、サーバへのアプリのデプロイ と1人で通貫でやってみました。できあがった物はまぁしょぼいのですが、個人的には非常に大変でした。良い経験になりました。

FFmpegで WebM の半透過動画を作成し、Chromeで再生する

$
0
0

はじめに

f:id:AMANE:20141216172917j:plain

ウェブアプリで画面全体にわたるようなリッチなエフェクトを掛ける手段のひとつとして、デザイナさんに作ってもらう動画(たとえばAfter Effectsで)をそのまま使う、なんてことは出来ないかと考えてトライしてみました。

HTML要素の上に半透過の動画を <video>要素で置くことで、もとのHTMLを動画で演出、みたいなことができています。

f:id:AMANE:20141216134814p:plain

できあがった物はこちらで確認出来ます

ブラウザは Chromeしか対応しておりません!ご注意。

環境

ちなみに、WebM を透過して表示できるのは、PC/MacChromeだけのようです。悪しからず。

Firefox@Macだと、アルファチャンネルが捨てられて、全画面カラフルに塗りつぶされます

Safari@Macだと、そもそも再生されません

元ネタ

今回の記事は、こちらの記事を足がかりに、追加でいろいろ調べてまとめた物になります。

Alpha transparency in Chrome video - HTML5 Rocks

動画の作り方

普段からデザイナさんに After Effectsで動画を作ってもらっているので、この記事では After Effectsを使ってにアルファ付き WebM 動画を作ってみます。

もしかしたら最新の After Effectsでは既にアルファ付き WebM の書き出しに対応しているかもしれませんが、私が使える 5.5 では出来なかったので、エンコードには FFmpegに梱包されている vp8 (libvpx) を利用します。

f:id:AMANE:20141216152454p:plain

After Effectsコンポジション作成

新規プロジェクトから普通にコンポジションを作成し、そこに要素・アニメーションを加えていきます。半透過のテストをしたかったので、アルファが変わったり、淡いグラデーションがかかっているような動画を作ろうと思い、今回はこちらの記事を参考にサンプルを作ってみました

WebM は 60fps にも対応しているので、コンポジションのフレームレート設定を 60fpsにしました。

背景はデフォルトの黒です。

f:id:AMANE:20141216173304j:plain

After Effectsでアルファ付き QuickTime Movie 書き出し

FFmpegでWebMにエンコードする元になる、アルファ付きの動画を出力します。AVI と QuickTime形式がアルファ付きに対応しているようですが、AVIだと尋常じゃない容量になるので、QuickTimeで書き出しますことにします。

対象のコンポジションを選択した状態で コンポジション > レンダーキューに追加を選ぶと、レンダーキューウィンドウにひとつ、レンダリング処理が追加されます。

そのレンダーキューの "出力モジュール"を選択して、下記のような設定にします。ポイントは以下の3点です

  • 形式: QuickTime
  • チャンネル: RGB + アルファ
  • カラー: ストレート(マットなし)

f:id:AMANE:20141216142307j:plain

カラーを「合成チャンネル(マットあり)」 にすると、アルファチャンネルだけで無く、RGBのレイヤーも調整された動画が描き出されます。 出力された MOV ファイル単体を QuickTimeで再生するときはこれで良いのですが、WebM にエンコードして他の画面に合成した際に、色味が暗い感じになってしまいます。

ストレートアルファとプリマルチプライド・アルファ(合成チャンネル)の違いは、こちらのページが詳しいです

あとは、出力先で適当に場所を決め、ファイル名を決めてレンダリングを行います。

FFmpegで WebM にエンコード

インストール

FFmpegは別途インストールしておいてください。 Windowsの場合は、binaryをダウンロードしてきて、どこか適当な場所に解凍し、システム環境変数の path に、ffmpeg/binのパスを通すと、コマンドプロンプト/PowerShellからコマンドをたたけるようになります。

エンコード

先ほど出力した mov ファイルのあるディレクトリに移動後、以下のコマンドでエンコードを行います。

ffmpeg -i webmtest.mov -crf10-b:v 1M webmtest.webm

オプションはいまいちよく理解出来ていないのですが、下記サイト様に説明が載っています。要は、オプション指定しないと結構画質が悪くなるので、VBR(可変ビットレート) の目標値 (1Mbits/s) と、VBRする際の最低品質保障 (4-63 での 10) を指定してね、という感じみたいです。

これでアルファ付きの WebM 動画ファイルが書き出されました。このファイルは、 Chromeにぽいっと投げ込むと、その場で再生してもらえます。が、背景がとくにないので真っ黒に表示され、このままでは透過できているのか分かりません。

f:id:AMANE:20141216173420j:plain

再生

というわけで、背景と適当なHTML要素を加えた上に透過動画をおいてみたのが、一番初めの作例になります。

再掲 → webm transparent test

画質優先で連番.tga を使う場合

AfterEffects から QuickTime(MOV) で書き出した時点で、圧縮率を最低にしたとしても、最終的なWebMにたどり着く前に何かしらの圧縮が入ってしまっていることになります。画質最高とは言えません。

そこで、一度無圧縮のアルファチャネル付き連番画像を書き出し、それから アルファ付き WebM をエンコードする、というパスを取ることもできます。

f:id:AMANE:20141216152504p:plain

連番 TGA 書き出し

新しいレンダリングキューを作成し、出力モジュールを以下の様に設定します。

  • 形式:Targa シーケンス
  • チャンネル: RGB + アルファ
  • カラー: ストレート(マットなし)
  • 形式オプション
    • 解像度 32bits/pixel (アルファチャネル付き)
    • 圧縮はなし!

その上でレンダリングすると、だだーっとTGAファイルが書き出されます。1920x1080、32bit ですと 1枚 8MB ほどもあるのでかなりつらい感じになります。。。

f:id:AMANE:20141216150852j:plain

連番 TGA から WebM にエンコードする

入力を、 MOV から 連番tga に変えるだけです。

ffmpeg -r60-i webmtest_%05d.tga -crf10-b:v 1M webmtest.webm

tga ファイルのサイズは膨大になりましたが、vp8 としては同じ圧縮を行うので、最終的に出てくる WebM ファイルの容量は、MOV を経由した場合と同程度になります。

さいごに

Chrome限定な上、 WebM ってぶっちゃけそんなに流行っている気配も無いので、この手法もこれといって使えるシーンが無い可能性は大きいと思います。

けどせっかくちゃんと出来るようになったので、まとめておきました。ちゃんちゃん。

ycapture で OpenCV での処理結果を Windows のビデオソースとしてブラウザに流し込む

$
0
0

はじめに

WebRTC を使ってビデオチャットアプリを作る際に、ビデオ画像にエフェクトをかけたくなりました。モザイクとか、ブラーとか、漫画カメラとか。

ブラウザ上でJavaScriptでごりごり画像処理をするのはさすがに厳しそうですので、画像処理を行うのは別のアプリケーションで行うことにしました。

最終的に WebRTC で MediaStream として扱うことを考えると、画像処理の結果が通常のWebカメラと同様に navigator.getUserMedia()できれば一番手っ取り早いんじゃないかなーと思っていろいろ手法を探してみました。

便利なソフトを教えていただいた

しかし調べれば調べるほど、Windows上だと DirectShowのお勉強しなきゃとかつらそうな気配が漂っていたのですが、Twitterに泣きついたところ、@jnakanoさんが ycapture(わいきゃぷちゃ)の存在を教えて下さいました。

ycapture(わいきゃぷちゃ)

説明から引用

ycaptureとは、WindowsのVideo Capture Sourceのような振る舞いをするDLL(の基本ソース)です。このDLLを使用すると、あたかもビデオキャプチャデバイスのように、任意のプログラムからビデオデータを供給することができます。

これだー!と言うことで、今回試してみました。開発者の谷沢さん、ありがとうございます。

開発の前に

今回やりたいこと

f:id:AMANE:20150111151631p:plain

  1. openFrameworks 上で、OpenCVを使ってカメラ画像を処理し、
  2. ycapture.dll からWindowsのビデオデバイスとして流します。
  3. ブラウザで navigator.getUserMedia()でストリームを取得します

注意

今回のアプローチがベストかどうかはケースバイケースだと思うので、手法の一つとしてご参考にしていただければと思います

環境

ycaptureのビルドは、

の2つの組み合わせで確認しています。openFrameworks に関しては、Visual Studio版が 2012(v110) にしか対応していないため、今回のシステム全体としては、Visual Studio 2012 を利用しています。

ycapture の準備

公式に載っている利用法に従って下さい。公式ページでは VS2008で、と書いてありますが上記の通りの環境でもビルド & 利用可能でした。以下、ポイントだけメモっておきます。

Release か Debug か。ビルドの種類とパスの設定に注意。

Visual Studioは ライブラリ類のパスを通すのが面倒なので、私は Release ビルドに統一してやっています。Visual Studioのプロパティをいじる際は、毎回 Configuration の表示に気をつけましょう。

f:id:AMANE:20150111092217p:plain

WindowsSDKを導入し、DirectShowの baseclasses をビルドして静的ライブラリを作る

Windows SDK アーカイブ – Windows デベロッパー センター

今回はこちらの Windows 7および .NET Framework 3.5 SP1 用 WindowsSDKを使っています。

baseclasses ライブラリのソリューションを Visual Studio 2012(2013) で開こうとすると、変換の際に大量の警告が出ますが、ビルドは出来ます。

配布されている ycapture プロジェクトのビルド準備

ycaptureプロジェクトのプロパティで、インクルードやリンクがうまくいくよう設定を変更します。先述の DirectShow/baseclasses の在処を教えてあげます(配布された状態だと、WindowsSDKのバージョンが違ったりしています)

私の場合は以下の通り

  • 追加のインクルードディレクトリ
    C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\multimedia\directshow\baseclasses;

  • 追加のライブラリディレクトリ
    C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\multimedia\directshow\baseclasses\Release;

これでビルドが出来ます。

ycaptureclient と testclienet のビルド

この二つは、配布状態のままでビルド可能です。

testclientは、ソリューション内でycaptureclientに対してプロジェクトの依存関係が組まれているので、特にライブラリの場所とか気にしなくて大丈夫なようです。

ycapture.dll の登録

regsvr32.exe を使ってdllを登録する際は、 powershell/cmd を管理者権限で立ち上げないと怒られます。

>regsvr32.exe ycapture.dll

サンプルを試す

ycapture で配布されている testclient で、以下の流れが確認出来ます。

  1. testclient を起動します。
  2. 受け側として、ブラウザで https://simpl.info/getusermedia/sources/を開きます。 navigator.getUserMediaのサンプルアプリです。
    受け側はSkypeなどのアプリでももちろん大丈夫です。
  3. 画面に、testclientが流している赤い帯が表示されれば成功です

f:id:AMANE:20150111151857p:plain

testclient が生成するカメラが見つからないときがある

ドライバの読み込み順の関係かキャッシュか正確なことは分かりませんが、作った仮想カメラがクライアントから見つからないことがあります。こういうときは、ページのリロードや、既に刺さっているウェブカムの抜き差しなどをすると、見つかるようになります。

ycapture を oF 内で利用する

ycapture を oF 内で利用する事で、oF での描画結果やCVを使った画像処理の結果を、仮想カメラデバイスとして流すことが出来るようになります。

プロジェクトの準備

ここでは Visual Studioでの oF プロジェクトの生成等については割愛いたします。

以下の点をプロジェクトのプロパティに設定していきます

  • baseclasses/ycapture のビルドにあわせて、configuration を Release にする
  • 追加のインクルードディレクトリに、ycaptureとycaptureclient のソースコードがある場所を追加する
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\ycaptureclient
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\ycapture
  • 追加のライブラリディレクトリに、ycapture/ycaptureclientのビルド結果がある場所を追加する
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\Release
  • ライブラリの入力に、以下の物を追加する
ycapture.lib
ycaptureclient.lib

コード

ycapture さんで配布されているtestclient を参考に書いていきます。

// ofApp.h// 前略#include "ofxCv.h"#include "CaptureSender.h"#include "ycapture.h"class ofApp : public ofBaseApp {

public:
  // 中略
  ofVideoGrabber cam;
  ofImage raw;
  ofImage blur;
  CaptureSender *sender;  // ycaptureのオブジェクト
};
// ofApp.cppint CAM_WIDTH = 640;
int CAM_HEIGHT = 480;
unsignedlong avgTimePF = 1000 / 30;    // 30fps ストリームのタイミングを作るのに使うらしいが詳細不明void ofApp:setup(){
  cam.initGrabber(CAM_WIDTH, CAM_HEIGHT); // カメラの初期化
  sender = new CaptureSender(CS_SHARED_PATH, CS_EVENT_WRITE, CS_EVENT_READ); // ycaptureのセットアップ// 後略
}

void ofApp::update(){
  cam.update();

  if(cam.isFrameNew()){
    raw.setFromPixels(cam.getPixels(), CAM_WIDTH, CAM_HEIGHT, OF_IMAGE_COLOR); // カメラ画像をコピー
    raw.mirror(1, 0); // そのまま送るとブラウザ側で垂直方向に反転する
  
    ofxCv::blur(raw, blur, 51); // ブラーをかけてみるテスト
    HRESULT hr = sender->Send(counter * avgTimePF, CAM_WIDTH, CAM_HEIGHT, blur.getPixels() ); //★★ここがポイント★★// 後略
  }
}

void ofApp::draw() {
  cam.draw(0, 0);
}

要するに、何かしらの方法で画像を作った後、 RGBの順の unsigned char配列にして、sender->Send()すれば良いようです。oFやCVには、RGBの順の unsigned char配列 への変換関数が用意されているので楽ちんです。

さいごに

ウェブブラウザ上で、oFで処理した結果の画像が見られれば完成です。oFのウィンドウに表示されているカメラのスルー画と並べて見ても、遅れは感じられません。良い感じ。

f:id:AMANE:20150111104337j:plain

次は、せっかくブラウザ上でやっているので、ブラウザでのユーザの入力を受け付けて、エフェクトを変更したりする仕組みを作ってみようと思います。

他プラットフォーム

Linuxの場合

余り詳しくないので間違いがあるといけないのですが、、Linux環境だと、gstreamer や V4L2loopback といったモジュールを使うと、割と簡単に動画ストリームをビデオデバイスとして取り扱うことが出来るようです。実際、openFrameworksの addons に arturoc/ofxGstV4L2Sink · GitHubと言う物があって、リポジトリのREADMEによれば、

Uses v4l2sink gst element to create a virtual device which can be used as a camera in any application that supports v4l2

とのことで、今回狙っていることが出来そうです。ただし私は試していません。

Mac OSX の場合

rsodre/ofxFakam · GitHubと言う物があり、これも

ofxFakam is an Open Frameworks addon that streams screen data to a fake camera driver.

ということで、狙っていることが出来そうです。ただし私は試していません。

html から node.js を介して oF の画像処理をコントロールし、ブラウザ上で閲覧する

$
0
0

はじめに

前回の記事で ycapture を使って、oF の描画内容を Windowsのビデオデバイスとして流すことで、ブラウザからも見ることが出来るようにする手法について紹介しました。

ycapture で OpenCV での処理結果を Windows のビデオソースとしてブラウザに流し込む - 自習室

前回やったことを図でまとめるとこんな感じ(再掲)

f:id:AMANE:20150111151631p:plain

ブラウザからoFアプリをコントロールする

今回はそれを発展させて、HTML側からカメラエフェクトを変更・調整できるようにしてみます。

できあがりはこんな感じ。ブラウザから、ネイティブアプリ(oF)に指令を送って、エフェクトを調整しています。

完成時のシステムは以下の様になります。

f:id:AMANE:20150112093523p:plain

ブラウザで選んだエフェクトの種類や強度の情報をWebSocket で Node.js にわたし、 Node.js からは OSCでリレーしてエフェクトの種類の情報をoFに渡します

環境とつかったもの

  • Windows 7
  • Visual Studio Express 2012
  • openFrameworks v0.8.4
    • ofxOSC
    • ofxCv
    • ofxOpenCV
    • ycapture.dll
  • node.js v0.10.29
    • node-osc
    • express
    • socket.io

あげてあります

今回のコードは、 node.js(およびhtml) の部分と、 oFの部分で二つに分けてアップしてあります。 oFのプロジェクトは ycapture の存在を前提にしているので、前回の記事を参考に導入してみてください。

izmhr/ycaptureInOF

izmhr/browserAndOF

ycapture に関しては前回記事参照

ycapture をつかって画像処理の結果を windwos のビデオデバイスとして流すやり方については、前回から変わっていません。今回は、三つの登場人物間で増えた通信部についてメモをしておきます。

html - node.js 側

  • NORMAL(エフェクトなし)
  • CANNY (エッジ抽出)
  • BLUR (ぼかし)

ラジオボタンを選択すると、どれが選ばれたかをNode.js 側に伝えます。

また、CANNY と BLURについては、その効果の効きをレンジスライダーで調整してNode.js側に伝えます。

これらの通信には、エフェクトの効きをリアルタイムに反映させたかったので、WebSocket(Socket.io) を利用しています。Socket.io の使い方については特殊なことはしていないので、ソースコードをご参考下さい。

要素使いこなし

<p><label>THRESH1<inputtype="range"name="canny_thresh1" min ="1" max="400"></label></p>
// 1~400 の間を、1刻みで選択出来る。

<p><label>SIZE<inputtype="range"name="blur_size" min="1" max="201" step="2"></label></p>
// 1~201 の間を、2刻みで選択出来る

後者が特徴的です。ofxCv::blurは内部的に cv::GaussianBlurを呼んでいて、ガウシアンカーネルサイズは奇数で無くてはいけません。そこで、上記のような指定にすることで、<input>の出力を奇数に限定しています。

また、<input type="range">要素は、value が string となっているため、Socket.io で送り込む際に、number要素に変換しておきます。

document.cv_effect.blur_size.oninput = function() {// ドラッグ中も数値を取りたかったら oninputを使う// リリース時のみ取りたかったら onchange
  socket.emit('blur size', parseInt(this.value));
}

node.js - oF 側

node.js 側

Socket.io でブラウザから送られてくるメッセージをoscに載せ替えて送り出しています

  socket.on('blur size', function(value){
    oscclient.send('/blursize', value);
  });

oF 側

OSCのメッセージを受け取って、CVのエフェクトを切り替えたり、効果の強さを調整したりします

// ofApp.cppwhile(oscReceiver.hasWaitingMessages()){
  ofxOscMessage m;
  oscReceiver.getNextMessage(&m);

  std::string oscaddress = m.getAddress();

  if(oscaddress == "/changeeffect"){
    std::string typeStr = m.getArgAsString(0);
    if(typeStr == "non") {
      effectType = EffectType::NONE;
    } elseif(typeStr == "canny" ) {
      effectType = EffectType::CANNY;
    } elseif(typeStr == "blur" ) {
      effectType = EffectType::BLUR;
    } else {

    }
  } /*中略*/elseif(oscaddress == "/blursize") {
    blurSize = m.getArgAsInt32(0);
  }

  // このあと effectType や blurSize を使う
}

追記

本記事の投稿後、 凹先生から助言をいただきました。

ofxLibWebsockets 試してみたところ確かにお手軽に oF 上で WebSocket が扱えて、Node.js が不要になるので良いと思いました!

最後に

WebRTC を使ってビデオチャットにする

今回は扱っていませんが、今回の物に PeerJS (WebRTC)を加えると、画面エフェクトが可能なビデオチャットシステムが完成しますね。

他プラットフォーム

前回ご紹介した内容は、デバイスやOSの仕組みが関わるところだったので Windows限定でしたが、今回ご紹介した内容は node.js と oFのaddonで出来るので、すべてのプラットフォームで実現可能です。 前回の記事で言う ycapture の仕事を linuxやMac OSX でやる手法についても、前回の記事の最後に調査だけしてあるので、それと組み合わせることで、他のプラットフォームでも同様の機能を実現できるのではと思います。


CreateJS で背景前景ともに動かしながら曇りガラス的表現をする

$
0
0

はじめに

磨りガラスってこんなかんじ。

f:id:AMANE:20150113153912j:plain

photo by Johnny Jet

友人氏がそういうのをやりたい、と言っていたのを思い出してやってみました。

完成品はこちら

コード

あげてあります

izmhr/dynamicBlurMask

環境

  • EaselJS 0.8.0

参考にしたもの

Cacheについて

DisplayObject.cache()は、オフスクリーンレンダリング用に document.createElement('canvas')して、そこにデータを書き込む操作で、そこに書き込んだ物をなんども使い回したり、できあがった画像全体にポストエフェクトを掛けたりするのに使います。

上記ブログでは、DisplayObject.cacheCanvasでオフスクリーンレンダされている画像にアクセスできることが説明されています。スーパーナイスです。

blurのかけ方、マスクの仕方

上で先に書いちゃいましたが、.cache()関数でオフスクリーンレンダした結果に対して、ブラーをかけたりできます。

このサンプルではDisplayObject.maskcreatejs.Shapeのオブジェクトを登録することで、Shapeの形状に切り抜いています。graphics.drawHOGE()で描ける単純な形状で抜きたい場合はこちら。

こちらの AlphaMaskFilterでは、 フィルタになるアルファを持った絵を作り(最終的にcacheCanvasを入力に使うので、Shape等にかぎらない)、そのアルファチャネルを使って対象のDisplayObjectにマスクをかけます。アルファを持つ画像等をもとに複雑なマスキングをしたい場合はこちら。

最後に

今回やっていること図示するとこんな感じです。詳しくはコードをご参照ください。

f:id:AMANE:20150117214412p:plain

ブラー元の画像を作って cacheCanvas で引っこ抜くために 1キャッシュ, ブラーをかけてマスクで抜くためにもう1キャッシュ、計2キャッシュ使いそれらを毎フレーム更新するのでやや重いのが問題です。

どうにか改善したいのですが…

マイク入力を WebAudio で加工して、ビデオと合流させた後 WebRTC で使う

$
0
0

はじめに

前の2記事ほど、ウェブカメラの映像を openFrameworks で加工してビデオデバイスに再度流し込むことで、WebRTC などで扱えるようにする方法について調査してきました。

ycapture で OpenCV での処理結果を Windows のビデオソースとしてブラウザに流し込む - 自習室

html から node.js を介して oF の画像処理をコントロールし、ブラウザ上で閲覧する - 自習室

音声も同様に加工して WebRTCで扱えるようにしたいなーと思いました。

完成品

f:id:AMANE:20150118110301p:plain

こちらで動かしています ->http://www.izmiz.me/mediaStreamMerging/

簡単に使い方
  • ウェブカムとマイクを持っている二台のPCで上記サイトにアクセスします
  • カメラとマイクの利用の許諾を問われるので、許可してください。
  • どちらかのPCで、相手の画面に表示されているIDを打ち込んで call すると、ウェブチャットが開始されます
  • Filter on にチェックして、 Frequency や Q値 を動かすと、相手側に伝える音声にローパスがかかります
  • ハウリング注意。

検討した2手法

仮想サウンドドライバを使ってOSに流し込む方法 (不採用)

ycapture と同じ考え方で、作り上げた音声をOSの音声デバイスに再度流し込む手法を初めは検討しました。ドライバ相当のものを自力で書くのは面倒なので、有り物の組み合わせで何とか行きたいです。

と思って調べていたところ、ニコニコとかで実況をする方々が、自分の音声と音楽やら動画やらの音声を混ぜるのにOSのソフトウェアミキサー(Windowsのステレオミキサー)を使っていることを知りました。さらにその流れで、NETDUETTO というソフトに同梱されている仮想サウンドドライバを使うことで、コンピュータで再生している音声を音声デバイスとして再入力出来ることが分かりました。

となれば、oF なり Pure data なりで音声を加工してこの仕組みで音声デバイスに戻せば、WebRTCでも使えそうです。

f:id:AMANE:20150118104431p:plain

WebAudio と WebRTC を組み合わせる方法 (採用☆)

一方で、WebAudio APIを使えば、jsの簡単なコードで音声にエフェクトを掛けられることも分かりました。ブラウザ内で完結するのもgoodです。

  • WebAudio APIの入力をマイクにする
  • WebAudio APIの出力を、mediaStream のビデオに合流させる

この2つが出来れば、目的は果たせます。そのためにちょいと調査をしました

こちらの記事様の時点では、AudioDestinationNodeから mediaStreamを引っこ抜くのは実装が不完全そう、という結果になっていました。しかし希望を持ったのでもう少し調べて見たところ、w3cの公式で「まさに」な内容が紹介されていました

The following examples illustrate WebRTC integration with the Web Audio API.

とのことです。このページの Example5 が、まさに今回の内容と同じになっています。図示すると下のような感じになります。これでいけそうです。

f:id:AMANE:20150118104440p:plain

今回は

ウェブカム映像へのエフェクトについては、パフォーマンスの観点から別アプリとの連携という形にしましたが、ちょっとWebAudio APIを使ってみたところ、シンプルなフィルタリング等ならパフォーマンスに問題はなさそうでした。

システム構成もシンプルに出来るので、音声に関しては後者、ブラウザ内ですべてやる方式でトライしてみます。

音質

NETDUETTO の仮想デバイスをまたいで入ってきた音の音質が悪い印象もありました。これはもしかしたら私の設定の問題かもしれないのでここでは断言はしませんが、今のところ音質良くできている Web Audio APIを利用する方向で行きます。

実装

映像のストリームも加える

最終的に「映像・音声共にエフェクトの掛けられるウェブチャットシステム」としたいので、上のExample 5に加えて、カメラ映像もmediaStreamに合流させる必要があります。

試行錯誤した結果、映像・音声で別々の mediaStream を作ったあと、片方をもう片方にマージ出来ることが分かりました。

// videoStream 映像のMediaStream// audioDestNode WebAudio API の AudioDestinationNode

videoStream.addTrack(audioDestNode.stream.getAudioTracks()[0]);

// できあがったstream を、peerjs で使う

先の構成図にこの処理を加えて、最終的にはこんな感じになります

f:id:AMANE:20150118175140p:plain

完成品

今回は、下記二つのコードを合体させています

これに、上で述べた映像のストリームを追加する方法を加えて、音声加工可能なビデオチャットシステムとしています。

初めにも書きましたが、完成品はこちらで動いています。http://www.izmiz.me/mediaStreamMerging/

SkyWay サービス利用の注意点

上がっているコードには、SkyWayのAPI key が直打ちされています。この API key は私のドメイン(www.izmiz.me)からしか使えない物になっているので、ご自身で試される場合は、ご自身でSkyWayのアカウントを作成し、ご自身のドメインを適用して API key を取得してください。

さいごに

今回はWebRTC との組み合わせにフォーカスしてまとめました。

次はWebAudio APIにフォーカスして、エフェクトの作り込みにトライしてみたいです。

Web Audio API の勉強 - グラフィックイコライザーを作る

$
0
0

はじめに

前回の記事で「Web Audio APIはシンプルで使いやすいしパフォーマンスも問題なさそう」という予感を得たので、少し勉強してみることにしました。まずは基本的な使い方を勉強して、それから練習問題として、グラフィックイコライザーを作ってみます。

グラフィックイコライザー

iTunesでいうこいつ。ベースを聞きたいから低い周波数を強める(相対的に中高音を抑える)とか、シンバルの響きを感じたいから中高音を上げる(相対的に定温を抑える)とかするのに使うやつ。(俺氏曰く)

f:id:AMANE:20150124182347p:plain

完成品

今回は効果を分かりやすくするために「すべての周波数で同じ強度」となるホワイトノイズを生成し、それに対して周波数ごとの強弱をつけられるようなサンプルになっています。

使い方

  • Play でホワイトノイズが鳴ります(ボリューム注意!)
  • バーを動かすことで、指定周波数周辺を増減させます
  • グラフの下の"Log""Linear"ボタンを押すと、グラフのx軸(音の周波数)を対数表示に切り替えられます

別ページで開く場合はこちらから >Web Audio Graphical Equalizer

このプログラムは g200kg.com さまの下記記事をベースに改変して作成いたしました。

基礎のお勉強

まずはWeb Audio APIの基本を勉強しました。参考にさせていただいた主なサイトは以下。

Getting Started with Web Audio API - HTML5 Rocks

"Web Audio API"でググるとトップに出るので、まずはここから。Googleのエンジニアによる記事。短い文量でWeb Audio APIの概要をつかむことが出来ました。

(電子書籍) O'Reilly Japan - Web Audio API

上の記事著者の著作、の邦訳。実質上の公式入門書。上の記事を拡張したような内容。この本のサポートページとして作られているサンプル集が非常に良い感じです。

また、上記サンプル集自体が、webaudioapi.comと言うサイトに含まれていて、ここから仕様書だったり、一般の方が作られている作例集に飛べたりします。

Web Audio API 解説 - 01.前説 | g200kg Music & Software

結論としては、このサイトだけで良かったです。Web Audio APIの基本から、細かい各ノードの使い方、それらの背景にあるデジタル音楽の理論まで、一通り学ぶことが出来ます。今回作成したグライコも、ここの記事中のコードをフォークして作らせていただきました。

Web Audio API (日本語訳)

上記サイトの方が、W3Cの公式文書を邦訳してくださっています。ありがたすぎました。完璧でした。 Published Versionとしてはいまのところ W3C Working Draft 10 October 2013 が最新のようなので、邦訳も最新、と言うことになります。

Editors Draft としては、2015/1/6 に最新のものが提示されていました。

イコライザの実装

BiquadFilter "peaking"のチェーン

Web Audio APIでは sourceNode (音の発生源または音声データ)から destinationNode(最終的な出力先。端末のサウンドデバイスなど) までの間に、ゲイン調整や周波数領域でのフィルタリング、パンニングなどの効果をつけるノードを複数挟むことが出来ます。

ターゲット周波数の異なる複数ピーキングフィルタを通すことで、グライコ的な物が作れるだろうと予測をつけて調べて見たところ、似たようなやりとりがされているのを見つけました。これで行けそうな気がします。

操作する周波数は、冒頭にキャプチャを貼った iTunesのイコライザを参考に、 32kHz から 2倍ずつ上がっていく物にしました。

ホワイトノイズの発生と、可視化

この辺りは、参考にさせていただいた元記事様を参考になさってください

グラフのx軸を対数にする

イコライザーのバーは対数で並べているのに対し結果のグラフがリニアで表示されていると、低い周波数の左側の辺りが過密になって見にくかったので、x軸を対数表示と切り替えられるようにしました。

できあがりのルーティング

f:id:AMANE:20150124214154p:plain

(細かいところ)

縦向きのスライダーバーの作り方

さいごに

実装の詳細はコードをご覧下さい。

Web Audio APIを使ってリッチな楽器を作っている作例なども勉強中に見かけました。自分もトライしてみたいですが、大変そうな予感。

前回今回試したように、入ってくる音に対してフィルタリングするような用途には、Web Audio APIはかなり答えてくれている印象を持ちました。今回も BiquadFilter を多段で挟んでも、特にパフォーマンスが悪くなったりはしていません。コードもかなりスッキリ書けるので良いですね。

積極的に使っていこうと思います。

読書感想:融けるデザイン

$
0
0

はじめに

講演会や研究発表の場などで(一方的に)非常に注目しお世話になっている、インタラクション研究者、渡邊恵太先生の著作が出たので、発売日に買って読みました。

あまりに「はまった」ので、2周読んだところで読書感想ブログします。

融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論

融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論

渡邊恵太先生

の研究については、彼のホームページにきれいにまとめてあるので、そちらに目を通してから本を読まれると、より理解が進むかと思います。

サイト上で試すことのできる Visual Haptics や 味ペン は是非体験してみてください。

また、本書の中でも繰り返されている自己帰属感について、iPhoneを事例に紹介されている記事があり、わかりやすいので、本を読む前に読んでみると良いかと思います。

感動した一節集 兼 ざっくり要約

自分のためのメモと本書のイメージ紹介として、私が「なるほどー」とか「そうだ、その表現だ!」とか「この考え方は使える」と膝を打った文章を一部引用させていただきます。

この記事を書く前、2周目を読んでいるときに作ったメモは、この記事の10倍くらいあるのですが、何とか選抜して減らしてみました。(そのくらい、読み応えがあります!)

正しい切り出し方ができていなかったら渡邊先生に非常に申し訳ないので、少しでもご興味もたれた方は是非本を読んでください(^^;)

インターフェイス/インタラクションデザインとは

インターフェイスのデザインとは、コンピュータと人との関係性を設計し、人の行動や活動を作ること

コンピュータとインターネットで、なにやる?って考えたときに、ついうっかりスマートテレビとか作ってしまうと、思考の広がって無さが露呈して非常に残念な感じになるので、いま人は、何をするか何が起こるのか何を得て何を感じるのか、もっと自由にデザインしなければいけない。  

インターフェイスデザインとは、可能のデザイン。環境から人が何を知覚し、どんな行為を生むかをデザインすること。

現象レイヤの体験と自己帰属感

現象レイヤの体験(人の認知や心理な観点で見た人の知覚と行為)をデザインすることがいかに大切であるか、についての説明。

会社では当然「高いクオリティ」や「美しいビジュアル・アニメーション」を求めるけど、その具体的な評価指標を考える上で非常に参考になると思いました。

インターフェイス石器時代のような道具のあり方、原因と結果が直接的な関係になることを一つの目標とする。ハンマーという道具自体を意識せず、釘を打つこと(対象)に集中できるようなあり方が、道具が透明である、ということ。

パソコン操作中にカーソルを意識しないことや、iPhoneの体験の良さを例に、自己帰属感が説明されます。iPhoneを操作しているのではなく、その先の情報に直接触れているような感覚を得られるようになる。

(iPhoneが非常になめらかにさくさく動く意味は→) 指とグラフィックとの高い動きの連動性が道具的存在となり、自己帰属感をもたらす。そしてその結果、道具としての透明性を得る。

ユビキタスコンピューティングから、環境と知覚、ギブソンの話

人間と環境の間に、行為だけでなく、行為を拡張する道具が介入すれば、別の次元の「可能」を知覚し、また行為へつながる。良い道具は、特にこの可能の知覚が優れている。そして、環境と接続する知覚と行為は途切れることなく循環している。それが「体験」の正体であると思う

私がいすや丈夫な台を見れば「座れる」と思うのと同じ透明感で、コンピュータが人とインタラクションし機能する世界、ということか。

情報技術を中心としたインタラクションデザインの目標は、ユビキタスコンピューティングの流れをくめば、もはやパソコンやスマートフォンを使っていると言う意識がないまま直接コンピュータやインターネットの恩恵を受ける透明性をどうやって実現するか、ということなのだ

環境と知覚、という考え方からインタラクションを考えると

インタラクションは既にある人間の知覚行為を支えている環境の仕組みを活かしながら、コンピュータという異物をうまく馴染ませる。自然回帰ではなく、世界を拡張するために。

人と世界の拡張、については説明が繰り返されます

なぜ自己帰属感が大事か

目的行為への集中だけではなく、、、

自己帰属した道具は透明化し、意識されなくなる。すると何も感じない世界があるのだろうか。(中略) 自己帰属がもたらすのは、そこにある新しい知覚世界だ。(中略)道具はあなたを変えながら世界との接点を変える。自己が拡張される。

最近はやりの「拡張人間」も、ロボティクスとかセンシングとかV/M/A/R的な派手な側面ばかりではなく、渡邊先生の研究のように日々の体験を静かに変えるような側面からも考えて取り組んでいきたいです。

自己帰属感が高いと、自己感や「私が感」が生まれて「自分の体験」が立ち上がってくる。この体験こそが生きている実感、あるいは愉しさや喜びとも言える。生きている実感のようなものを、その道具/サービスを使う中で感じられる

ここまで来ると会社では説明しづらいですが(笑) 個人的には納得いったし、こういった観念を常に持って取り組んでいきたいです。

デザインへの取り組み方。体験の設計方法の具体的取り組み。意識すべきこと

これからのデザイン。画面のデザイン、モノの形のデザインにとどまらない。

インターネット + コンピュータのメタメディアの持つ、(既存のメタファに縛られない)表現の自由度と柔軟性の高さを最大限に生かし、新しい価値を生み出す

20世紀の技術は、人がこれまでやってきたことを効率よく代行するものであった。これからは知的創造行為も含まれる。本書が目指すのは、個人の能力拡張とそのデザインである

メタメディアのインターフェイスデザインの実例

実世界へ直接働きかけるインターフェイス。情報の道具化、情報自体を道具として利用する。人々が利用する道具自体にウェブ上のデータを結びつけ、物理的に制約を与えて、人の行動を直接的に支援する

それらの実例が、smoon, integlass, length printerなどのプロジェクト。

パラレルインタラクションのすすめ

ユーザーインターフェイスの常識とは、「システムを使いたくて使っている人」や「目の前に居る人」を暗黙の内に前提としている。そのため操作を提供するデザインを「ユーザーインターフェイス」と呼んでいる。暗黙的にインタラクションの高速を前提に設計してしまっている 「私のシステムを使っている限り、私のシステムは使いやすい」

パラレルインタラクション。マルチデバイスの時代。「あなたのサービスはユーザーの生活のごく一部でしかない」

  • 文脈はデバイスから生活へ
  • 拘束性は配慮へ
  • 利用タイミングは集中から分散へ

(やや禁則事項ですが) これは、会社の上の人ほど逃れられない呪縛みたいになっているのをひしひしと感じています。「パラレルになるとしたら、プロダクト/コンテンツの価値が低い証拠だ」とか言われかねない勢いです。そういった文化を背景にビジネスをやってきた会社ですからそう考えてしまうのも仕方ないかもしれませんが、自分が関わるプロジェクトはそういうところを少しずつ変えていきたいと思っています。

さいごに

研究者の方の著作なのに、実際の生活に具体的な提案をしていかなければいけないメーカーの人間(私)に、かなりダイレクトに響く内容でした。

自己帰属感の話、iPhoneの例は非常にわかりやすく「そこのクオリティ上げたら、商品売れるの?」「それより機能を増やすべきじゃないの?」という「あるある」問答集に対する明確な答えになっており、これから積極的に同僚内で布教していきたいと考えています。

まずは、理解のありそうなデザイナさんやエンジニアさんに本書を布教して、こういったとこ大事にして企画とかインターフェイスデザインとかしていこうぜ!という雰囲気を作り出していきたいです。

openFrameworks で Kinect for Windows SDK 2.0 をまるっと利用する

$
0
0

はじめに

f:id:AMANE:20150201220035j:plain

この記事では、 ラッパなどを挟まず、 Kinect for WindowsSDK 2.0 のフル機能を oF 内で直接利用する方法について調べた内容をまとめます。ラッパを利用しないのは、MSDNの公式リファレンスが非常にしっかりしているからです。ネットに転がっているKinect v2 がらみの情報も公式 SDKを直接たたくものが多いので、いまのとこは素で使った方がなにかと幸せな予感がしています。

oF 内で利用することで様々な機能をひっつけやすくなるので、アプリ全体としての構築も楽になると考えています。

環境

Visual Studioは Proの方が幸せですが、ここではExpressの前提ですすめます。

Visual Studio Community 2013 じゃだめか?

個人のデベロッパだと、Visual Studio Community 2013 を使ってアドオンうはうはしたいところです。しかし、公式には openFrameworks は、vs2013 をサポートしていません。そこで片手落ちではありますが以下の手順で ビルド環境としては2012ですが、エディタとしては VS Community 2013 を使って openFrameworks の開発を行えるようになります。

  • VS Community 2013 とは別に VS2012 Express を入れておくと、VS2012 (v110) のビルドツールが使えるようになります。
  • oF の Project Generator でプロジェクトを作る
  • VS Community 2013 で開くと、通常だとソリューションのコンバートを勧められますが、これをキャンセルします

VS の Solution Explorer で下図のように表示されていたらできていると思います。

f:id:AMANE:20150127133522p:plain

このあたりは、@selflash氏が説明してくださっているのでご参照ください。

使い方

プロジェクト設定

@kaorun55 先生の記事ではウィンドウズアプリの前提で説明されていますが、プロジェクト設定はoFでも同じです

Kinect for Windows SDK v2.0 で開発する環境を整える(C++編)

  • of の Project Generator でプロジェクトをじぇねれーーとする
  • 追加のインクルードディレクトリを設定する
    C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\inc
  • 追加のライブラリディレクトリを設定する
    C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Lib\x86
  • 追加の依存ファイルに Kinect20.lib を設定する

シンプルにカラー画像の表示だけ

簡単な作例として、SDKをインストールしたらついてくる公式サンプル Color Basics-D2D をベースに、oFで動かしてみました。Kinect v2 からカラーのイメージをとってきて描画するだけ。

f:id:AMANE:20150201223037j:plain

ofImage か ofTexture か

oF 使い的にはきっと基本的すぎてあれですが、動画をoFで描画する際にどっちを使うといいのかわかりませんでした。

調べてみたところ、下記フォーラムで同様の質問がなされていました。

ofImage は ofTexture を内部で使っていて、メモリの確保なども含めてラップしているクラスなので、描画部分に関しては差はない、とのこと。今回のような Kinectとの連携だと、ofTexture を使う場合でも、ColorFrame からpixel配列をいったん引っこ抜いてからそれを ofTextureにloadData する必要があるので、確保するメモリ量的にも差がなさそうです。

コードは #ifdefして両方試しています

あげてあります

izmhr/KinectV2Sample

Face Tracking も試してみた

つづけて、FaceBasics-D2D というサンプルから、顔認識に関する最低限野部分をoF向けに移植してみました。

f:id:AMANE:20150201223113j:plain

顔出しツラいっすね。写真は悪用厳禁っす。

一生懸命口角を上げたおかげで笑顔判定がYESなのと、(普段かけない)めがね判定がYESなのが確認できると思います。(^^;)

Kinect v2 はボーンやデプスも使って顔認識とトラッキングを行うので、かなりロバストです。本当は顔出し恥ずかしいですが、写真の印刷だとほとんど判定しないのですすすs… Kinect v2 すごいっす。

コード

追加のインポート

FaceTracking の機能は Kinect20.Face.lib という別のライブラリにまとめられているので、プロジェクトの設定でそれも追加する必要があります

  • Kinect.face.h を必要なコードでインクルードする
  • Project Properties 追加の依存ファイルに Kinect20.Face.lib を設定する
(追記しました) ポストビルドコマンドで、dll等必要なファイルを持ってくる

また、oFやKinectwindowsアプリは、VSのビルドコマンド内で、必要なdllなどのファイルをoFやKinectSDKのインストールディレクトリから自分の実行ディレクトリ(exeを出力するところ)にコピーしてきて、それを使ってexeを実行しています。

たとえば Kinect for WindowsSDK 2.0 のサンプル FaceBasics-D2D では、下図のような指定で必要なdllなどを取ってきています。

f:id:AMANE:20150212081206p:plain

Visual Studioで oFアプリをビルドする場合は更に、oFアプリの実行に必要なdll等一式も持ってくる必要がありますが、これは、Visual Studio向けのProject Generator でアプリを作成すれば、自動的にコマンドがセットされています。正確には、oFのインストールディレクトリ中に定義されている、デフォルトのプロパティーシートを見ています。

(下図のプロパティシートは、 VIEW > OTHER WINDOW > PROPERTY MANAGER で開きます)

f:id:AMANE:20150212083706p:plain

したがって、今回のケースで言うと、 oF のデフォルトのポストビルドコマンドと、Kinect20.Face.dll 関連のポストビルドコマンドを同居させてあげる必要があります。

プロパティシートがプロジェクトに登録してあったら、その内容は継承されるのかと思ったのですが、どうもプロジェクト固有のプロパティに書いた内容で上書きされる仕様なようですので、すべて記入されてある必要があります。できあがりはこんな感じ。

xcopy /e /i /y "$(ProjectDir)..\..\..\export\vs\*.dll" "$(ProjectDir)bin"
xcopy "$(KINECTSDK20_DIR)Redist\Face\x86\NuiDatabase" "$(TargetDir)NuiDatabase" /e /y /i /r
xcopy "$(KINECTSDK20_DIR)Redist\Face\x86\Kinect20.Face.dll" "$(TargetDir)" /c /y

この状態でビルドすると、ビルド結果の出力で、exeがはき出された後にいろいろコピーしているのがわかると思います。

1>  KinectV2Sample.vcxproj -> F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\bin\KinectV2Sample_debug.exe
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\Assimp32.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\fmodex.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\fmodexL.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\FreeImage.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\FreeType-6.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\glut32.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\libeay32.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\ssleay32.dll1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\Zlib.dll1>9個のファイルをコピーしました
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignment.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignmentColor.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignmentColor27.bin

中略。この辺りは、顔発見のための辞書データなどをコピーしている

1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\left.p.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\right.mod.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\right.p.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\WholeHeadModel\FullHeadMaskVertexCorrespondence.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\WholeHeadModel\fullMeanHead60_tri.ply
1>57個のファイルをコピーしました
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\Kinect20.Face.dll
1>1個のファイルをコピーしました

これで実行可能です。

一応あげてあります

コードはかなりやっつけな感じで書いたので、一応上げますが、あまり参考にはされない方が良いかと思います(>_<)

先ほどのリポジトリにブランチとしてぶら下げています。

そのほかのアプローチ

以上のように使えることの確認をしましたが、ここに至る前に、いろいろ Kinect for WindowsSDK 2.0 と oF のつなぎ方を調査したので、それもまとめておきます。

Kinect Common Bridge / ofxKinectv2

Kinect Common Bridge は、MSOpenTech コミュニティで開発されている Kinect for WindowsSDKのラッパで、そのブランチとして 2.0 向けが開発されています。CinderやoFなどのクリエイティブコーダー向けに使いやすくするのが主目的のようです。

これを使ってoF向けにさらにラップしたのが ofxKinectv2 という addon です。これはまだ Face Tracking のフィーチャをサポートしていません。Color, Depth, Infrared, Body あたりの機能を簡単に使う分にはこれでも良さそうです。

Windows Store 向け

Channel9 (MSのデベロッパー向け広報ブログ) で、 Windows Store App 版での oF + Kinect v2 の記事が紹介されていました。この記事中で、MSOpenTech が Windows Store 向けアプリを生成する変更を加えた Project Generator 込みの oF Fork を紹介しています。もし必要があれば。

Mac

Mac + oF + Kinect v2 をやる場合は、 Theo 先生のこれが使えそうですが、試してはいません。名前かぶってますね。

Unity 使おうぜ Unity

このブログで過去に取り上げましたが、Unity Pro をお持ちならKinect v2 用の公式 UnityPackage がありますので、こちらを使うと楽ちんです。が、SDK 2.0 のフル機能を使えるわけではなさそうです(要調査) *1

Kinect for Windows SDK 2.0 Unity Pro Add-in で シンプルなデプス画像を表示する - 自習室

さいごに

使えるようになったので、使っていきます。

*1:kaorun55 先生資料によると、FaceやSpeech、Gestureなど結構な部分が使えないようです http://www.slideshare.net/kaorun55/kinect-for-windows-v2-39610207

Viewing all 50 articles
Browse latest View live