Pipe Renderでタグ「ARToolKitの物体認識」が付けられているもの
パブリックドメインソースを公開したので、次にプログラムをまとめたものを公開します。
FingerDetect1.0.zip
-- < プログラムの使い方 > ---
0.Webカメラが2つあることが最低条件です。
ちなみに僕のは"Qcam Pro for Notebooks"。他のカメラでは試していないので、動くかどうかはわからないです。
あと、2つのカメラの設定を同じにしてください。
1.2つのカメラの向きを平行にして、まっすぐに並べる。
2.緑色のキャップのようなもの(作者は風船を使用)を用意し、それを親指に付けます。
3.TwoViewに関する説明(http://render.s73.xrea.com/pipe_render/2008/05/artoolkittwoview.html)を読み、"WDM_camera_flipV_01.xml"、"WDM_camera_flipV_02.xml"を作成し、Dataフォルダに入れる。
4.マーカーと手を表示し、マーカーと指の距離が表示されることを確認します。
5.親指と人差し指を近づけて、カーソルがクリック状態になるかどうか(2つの指の間の線が赤くなる)を確認します。
6.マーカー上の立方体に指近づけて、クリック状態にします。
7.クリック状態で指を移動すると、立方体も移動します。
8.立方体の移動中にクリックを解除すると、立方体の移動が止まります。
--- < ソースの概要 > ---
今回のプログラムでは、いくつかのクラスを追加しました。
・CHandContourクラス:手の輪郭線を扱います。指の認識などを行えます。
・CPointActionクラス:複数の点を用いたカーソルアクションを行います。
こちらについては、近いうちにドキュメントを公開する予定です。
FingerDetect1.0.zip
-- < プログラムの使い方 > ---
0.Webカメラが2つあることが最低条件です。
ちなみに僕のは"Qcam Pro for Notebooks"。他のカメラでは試していないので、動くかどうかはわからないです。
あと、2つのカメラの設定を同じにしてください。
1.2つのカメラの向きを平行にして、まっすぐに並べる。
2.緑色のキャップのようなもの(作者は風船を使用)を用意し、それを親指に付けます。
3.TwoViewに関する説明(http://render.s73.xrea.com/pipe_render/2008/05/artoolkittwoview.html)を読み、"WDM_camera_flipV_01.xml"、"WDM_camera_flipV_02.xml"を作成し、Dataフォルダに入れる。
4.マーカーと手を表示し、マーカーと指の距離が表示されることを確認します。
5.親指と人差し指を近づけて、カーソルがクリック状態になるかどうか(2つの指の間の線が赤くなる)を確認します。
6.マーカー上の立方体に指近づけて、クリック状態にします。
7.クリック状態で指を移動すると、立方体も移動します。
8.立方体の移動中にクリックを解除すると、立方体の移動が止まります。
--- < ソースの概要 > ---
今回のプログラムでは、いくつかのクラスを追加しました。
・CHandContourクラス:手の輪郭線を扱います。指の認識などを行えます。
・CPointActionクラス:複数の点を用いたカーソルアクションを行います。
こちらについては、近いうちにドキュメントを公開する予定です。
ソースの公開ですが、まず最初に新規に作成した指認識のソースだけ公開いたします。
これは一応ライセンス上の体裁を整えるためだけの行為なので、この後にまとめたソースをちゃんと公開いたします。
というのも、このソースについてはGPLライセンスではなく、パブリックドメインになっています。
なので、この部分だけ分離し、先に公開しました。
(実際にはここまで厳密にやらなくてもいいと思いますが。
指認識部分のソース:
CHandContour1.0.zip
パブリックドメインソフトウェア(PDS)については以下のよう説明されています。
Wikipedeia:パブリックドメインソフトウェア
ここで、日本では著作人格権を放棄できないので、以下のようにしなくてはいけないと書かれています。
それから今回、コメントをdoxygenの形式に対応いたしました。近いうちにドキュメントを作成し、公開する予定です。
これは一応ライセンス上の体裁を整えるためだけの行為なので、この後にまとめたソースをちゃんと公開いたします。
というのも、このソースについてはGPLライセンスではなく、パブリックドメインになっています。
なので、この部分だけ分離し、先に公開しました。
(実際にはここまで厳密にやらなくてもいいと思いますが。
指認識部分のソース:
CHandContour1.0.zip
パブリックドメインソフトウェア(PDS)については以下のよう説明されています。
Wikipedeia:パブリックドメインソフトウェア
ここで、日本では著作人格権を放棄できないので、以下のようにしなくてはいけないと書かれています。
...「将来にわたって著作権(及び著作者人格権)を主張しないことを宣言する」などと明記することによって、事実上の PDS として扱われる...これによりこの部分のソースについては、利用者は著作権による制限なしにソフトウェアを利用することができます。GPLのような「ソース公開の義務」も発生いたしません。
それから今回、コメントをdoxygenの形式に対応いたしました。近いうちにドキュメントを作成し、公開する予定です。
指が認識できたら、これをポインティングデバイスとして利用します。
これで、普段僕らがやっている「手で掴む・離す」という作業をそのままUIとして利用できるので、より自然な操作が可能になるはずです。
--- < 概要 > ---
今回、「つまむ」という動作を検出するために、以下の2つが必要になりました。
・親指の判断
・指がくっついた状態でも手の領域が重ならないようにする
この問題を解決するために、親指に緑色のキャップを装着しました。
これで、指先に緑の領域がある場合は親指であると判定でき、さらに指がくっついた状態でも、キャップの緑が邪魔をして肌色領域が混ざるのを防ぐことができました。
ここで指がくっついた状態では、親指じゃない方の指が親指だと判定される現象が発生しましたが、そのときの2つの指の座標はほぼ同じになるので、あまり問題ありませんでした。
ポインティングのために行った処理を説明します。
1.指を認識する
2.親指を探す
3.親指と他の指との距離を測る
4.距離がある程度近い場合はドラッグ開始
5.ドラッグ中に距離が離れたら、ドラッグ終了
それぞれの詳細は以下の通りです。
--- < 1.指を認識する > ---
指の認識は、前回の処理とほぼ同様です。
今回追加した処理では、左右のカメラで指を一致させるために、指のマッチングを行いました。
左右画像での指のマッチングは単純で、基準の位置座標を各指を元に変えながら、その他の指の距離を測定し、最も近いものを探しているだけです。
マッチングで指先だけでなく、指の付け根も比較対象に加えることで、マッチングの精度が上がりました。さらに指認識の精度も上がります。
--- < 2.親指を探す > ---
親指には緑のキャップがあるはずなので、各指先でその緑を探します。
そして、最も緑の領域が多い指を親指であるとします。
また、親指のマッチングも行います。
--- < 3.親指と他の指との距離を測る > ---
左右の画像で一致した指の座標が取得できたので、前回と同様三角測量で指の3次元座標を計算します。
全ての指の3次元座標が分かったら、親指とその他の指との距離を計算します。そして、距離が最も近い指を探します。
--- < 4.距離がある程度近い場合はドラッグ開始 > ---
近い指までの距離が分かったら、その距離がある値より小さいかどうか調べます。そして、小さいときに「つまんでいる状態」のフラグを立てます。
「つまんでいる状態」で立方体との衝突判定を行い、
衝突していたら、ドラックを開始します。
ドラッグ中は立方体が指に追従して移動します。
--- < 5.ドラッグ中に距離が離れたら、ドラッグ終了 > ---
親指と近傍の指との距離が一定値より離れた場合、
「つまんでいる状態」フラグを下げます。
ドラッグ中に「つまんでいる状態」フラグが下がったら、ドラッグを中止します。これでドロップができます。
最後のドラッグ&ドロップは、前回の色認識ポインティングと同様です。
最近はARToolKitのプログラムも少しできてきたので、
次は手とかをそのまま認識させたいと思っていました。
そしたらちょうどmasafumiさんという方のブログで手認識を使ったARという記事を見つけました。
この方法は認識精度が高そうなので、twoViewでの物体認識にも使えそうです。
この手認識ARの研究は、手を認識することによってマーカーの代わりにしようというものです。
ソースも公開されているので、すぐにこのプログラムを使った動画がアップされています。
見ての通り、指認識の精度は非常に高いです。
というわけで今回は、この指認識のアルゴリズムだけをいただき、
この情報を元にtweVIewから指の3次元座標を計算してみました。
これで綿棒や色の付いた目印を使う必要がなくなります。
--- < 指認識の概要 > ---
指認識では、おおまかに以下のような処理を行っています。
1.手の色に近い領域を探し、輪郭線で分ける
2.距離変換画像を作成する
3.輪郭線を使ったラベリング
4.手の輪郭のカーブ具合を調べる
5.カーブ具合から指の判定
僕が感動したのは、手の輪郭線から指を判定する処理です。
--- < 1.手の色に近い領域を探し、輪郭線で分ける > ---
やはり最初は手の色を判定し、それを元に2値画像を作成します。
元のプログラムではここでRGBをYCrCbという色空間に変換し、
ヒストグラムなどを使って肌色を判定していました。
ですが、僕のプログラムでは前回のHSV色空間を使用しました。
そしてさらに、この肌色の2値画像から輪郭線情報を作成します。
輪郭線はOpenCVのcvFindContoursを使用して作成します。
--- < 2.距離変換画像を作成する > ---
次に、2値化画像から距離変換画像を作成します。
距離変換とは、値のある現在の点から値のない点への最短距離を求める計算です。
この最短距離を画像に書き込むと、上の1つめの画像のようになります。
この距離変換によって、肌色に近い領域で一番大きなものが大体分かります。
今回は、「その一番大きな領域が手である」という判定をしています。
--- < 3.輪郭線を使ったラベリング > ---
この手の領域を判別するために、輪郭線を使用します。
1.まっさらな画像を用意
2.画像に対し、各輪郭ごとに内部を塗りつぶしていく
3.塗りつぶすたびに、「距離変換の値が最大となる座標」が塗り潰されたかどうか判定する。
4.もし塗りつぶされいれば、その輪郭が「求める手の領域」のものになる。
この処理によってラベリングを行わずに、最大面積の領域を判定できてしまいます。
ラベリング処理は重いものが多いので、これはとても便利です。
結果的に上の2つ目の画像のようなものができあがります。
--- < 4.手の輪郭のカーブ具合を調べる > ---
手の輪郭を取得できたので、次にこれを用いて指を判定します。
指判定には、各輪郭点の狭い範囲で内積と外積を計算します。
1.輪郭線上の全ての点を調べる
2.各点の狭い範囲で、先の輪郭点へのベクトルと、後の輪郭点へのベクトルを取得する。
3.2つのベクトルの内積を計算し、それがある程度大きければ、その点はカーブしていると判定
4.2つのベクトルの外積を計算し、そのカーブの方向を判定
5.調べる範囲を変えて、2~4の処理を繰り貸す。
6.求める値になったら、そのカーブが指に似た曲がり具合であると判断する。
この処理で、上の3つ目の画像ができあがります。
--- < 5.カーブ具合から指の判定 > ---
上記の処理で指っぽいカーブは分かりましたが、これが本当に指かどうかはまだ分かりません。
また、場合によってはその指がどの指なのかも判定が必要です。
ですが、今回のプログラムではその処理を入れていません。
ここでは最後に、前回同様ステレオでこの2次元座標を3次元に変換して終わりです。
これで上の最後の画像のようになります。
元の研究では、事前に指の理想的な位置を取得しておいて、
それと比較することで各指を認識したりしているようです。
僕のプログラムも指っぽい形状の認識の精度は高くなりましたが、
その後の指判定はまだできていません。
ソースの清書も含め、その辺が今後の課題となります。
次は手とかをそのまま認識させたいと思っていました。
そしたらちょうどmasafumiさんという方のブログで手認識を使ったARという記事を見つけました。
この方法は認識精度が高そうなので、twoViewでの物体認識にも使えそうです。
この手認識ARの研究は、手を認識することによってマーカーの代わりにしようというものです。
ソースも公開されているので、すぐにこのプログラムを使った動画がアップされています。
見ての通り、指認識の精度は非常に高いです。
というわけで今回は、この指認識のアルゴリズムだけをいただき、
この情報を元にtweVIewから指の3次元座標を計算してみました。
これで綿棒や色の付いた目印を使う必要がなくなります。
--- < 指認識の概要 > ---
指認識では、おおまかに以下のような処理を行っています。
1.手の色に近い領域を探し、輪郭線で分ける
2.距離変換画像を作成する
3.輪郭線を使ったラベリング
4.手の輪郭のカーブ具合を調べる
5.カーブ具合から指の判定
僕が感動したのは、手の輪郭線から指を判定する処理です。
--- < 1.手の色に近い領域を探し、輪郭線で分ける > ---
やはり最初は手の色を判定し、それを元に2値画像を作成します。
元のプログラムではここでRGBをYCrCbという色空間に変換し、
ヒストグラムなどを使って肌色を判定していました。
ですが、僕のプログラムでは前回のHSV色空間を使用しました。
そしてさらに、この肌色の2値画像から輪郭線情報を作成します。
輪郭線はOpenCVのcvFindContoursを使用して作成します。
--- < 2.距離変換画像を作成する > ---
次に、2値化画像から距離変換画像を作成します。
距離変換とは、値のある現在の点から値のない点への最短距離を求める計算です。
この最短距離を画像に書き込むと、上の1つめの画像のようになります。
この距離変換によって、肌色に近い領域で一番大きなものが大体分かります。
今回は、「その一番大きな領域が手である」という判定をしています。
--- < 3.輪郭線を使ったラベリング > ---
この手の領域を判別するために、輪郭線を使用します。
1.まっさらな画像を用意
2.画像に対し、各輪郭ごとに内部を塗りつぶしていく
3.塗りつぶすたびに、「距離変換の値が最大となる座標」が塗り潰されたかどうか判定する。
4.もし塗りつぶされいれば、その輪郭が「求める手の領域」のものになる。
この処理によってラベリングを行わずに、最大面積の領域を判定できてしまいます。
ラベリング処理は重いものが多いので、これはとても便利です。
結果的に上の2つ目の画像のようなものができあがります。
--- < 4.手の輪郭のカーブ具合を調べる > ---
手の輪郭を取得できたので、次にこれを用いて指を判定します。
指判定には、各輪郭点の狭い範囲で内積と外積を計算します。
1.輪郭線上の全ての点を調べる
2.各点の狭い範囲で、先の輪郭点へのベクトルと、後の輪郭点へのベクトルを取得する。
3.2つのベクトルの内積を計算し、それがある程度大きければ、その点はカーブしていると判定
4.2つのベクトルの外積を計算し、そのカーブの方向を判定
5.調べる範囲を変えて、2~4の処理を繰り貸す。
6.求める値になったら、そのカーブが指に似た曲がり具合であると判断する。
この処理で、上の3つ目の画像ができあがります。
--- < 5.カーブ具合から指の判定 > ---
上記の処理で指っぽいカーブは分かりましたが、これが本当に指かどうかはまだ分かりません。
また、場合によってはその指がどの指なのかも判定が必要です。
ですが、今回のプログラムではその処理を入れていません。
ここでは最後に、前回同様ステレオでこの2次元座標を3次元に変換して終わりです。
これで上の最後の画像のようになります。
元の研究では、事前に指の理想的な位置を取得しておいて、
それと比較することで各指を認識したりしているようです。
僕のプログラムも指っぽい形状の認識の精度は高くなりましたが、
その後の指判定はまだできていません。
ソースの清書も含め、その辺が今後の課題となります。
新しいプログラムは「物体認識」とか凄そうな名前を付けましたが、
基本的にはtwoViewを使ったプログラムの延長です。
今回は、前回のプログラムの色認識を改良しました。
少しずつ純粋なARToolKitから離れてきています。
--- < HSV色空間について > ---
HSVなんて聞きなれない単語ですが、簡単に言うとRGBの親戚みたいなものです。
知っての通り、RGBは「赤・緑・青」の色を組み合わせて多くの色を表現しますが、
HSVでは代わりに「色相・彩度・明度」という属性を組み合わせることで色を作ります。
詳しくは、Wikiを参照してください。
なぜRGBじゃなくてHSVを使うのかというと、こっちの方が特定の色を見つけやすいからです。
Wikiを見てもらえば分かるように、HSVでは赤とか青とかの情報は色相を見れば大体分かります。
残りの彩度や明度は、言ってみれば明るさや暗さみたいなもので、ほとんど無視していいものです。
逆に言えば「明るい赤」も「暗い赤」も、同じ赤として認識してくれることになります。
実際には、物体の「影の部分」や「光が反射している部分」まで認識してくれる可能性がある、
ということです。
--- < 実行結果 > ---
今回は、このHSV色空間で画像を扱うために、OpenCVというフリーの画像処理ライブラリを使用しました。
また指定色の物体は綿棒ではなく、色風船の端を切って指にはめてみました。
HSV色系を用いる以外の処理は、今までと一緒です。
とりあえずはうまくいっているようです。
しかし、欠点もあります。
HSV色系はそのままだと感度が良すぎて、余計なものまで認識してしまいます。
上の画像では、閾値を狭くしたので指の先を正しく認識できていません。
そこで、閾値を広くすると下の画像のようになります。
閾値が広いと指の部分を正しく取得できますが、同時に関係ない部分まで誤認してしまっています。
このような結果にならないように、「彩度・明度」も考量しなくてはならず、
「色相」の閾値も、そのつど微調整が必要です。
またこれまで以上に、撮影環境に気を使わなくてはいけないかもしれません。
この辺は今後の課題です。
基本的にはtwoViewを使ったプログラムの延長です。
今回は、前回のプログラムの色認識を改良しました。
少しずつ純粋なARToolKitから離れてきています。
--- < HSV色空間について > ---
HSVなんて聞きなれない単語ですが、簡単に言うとRGBの親戚みたいなものです。
知っての通り、RGBは「赤・緑・青」の色を組み合わせて多くの色を表現しますが、
HSVでは代わりに「色相・彩度・明度」という属性を組み合わせることで色を作ります。
詳しくは、Wikiを参照してください。
なぜRGBじゃなくてHSVを使うのかというと、こっちの方が特定の色を見つけやすいからです。
Wikiを見てもらえば分かるように、HSVでは赤とか青とかの情報は色相を見れば大体分かります。
残りの彩度や明度は、言ってみれば明るさや暗さみたいなもので、ほとんど無視していいものです。
逆に言えば「明るい赤」も「暗い赤」も、同じ赤として認識してくれることになります。
実際には、物体の「影の部分」や「光が反射している部分」まで認識してくれる可能性がある、
ということです。
--- < 実行結果 > ---
今回は、このHSV色空間で画像を扱うために、OpenCVというフリーの画像処理ライブラリを使用しました。
また指定色の物体は綿棒ではなく、色風船の端を切って指にはめてみました。
HSV色系を用いる以外の処理は、今までと一緒です。
とりあえずはうまくいっているようです。
しかし、欠点もあります。
HSV色系はそのままだと感度が良すぎて、余計なものまで認識してしまいます。
上の画像では、閾値を狭くしたので指の先を正しく認識できていません。
そこで、閾値を広くすると下の画像のようになります。
閾値が広いと指の部分を正しく取得できますが、同時に関係ない部分まで誤認してしまっています。
このような結果にならないように、「彩度・明度」も考量しなくてはならず、
「色相」の閾値も、そのつど微調整が必要です。
またこれまで以上に、撮影環境に気を使わなくてはいけないかもしれません。
この辺は今後の課題です。
