ひとりで「だるまさんがころんだ」をしたい -技術編-
先日、ひとりで「だるまさんがころんだ」をする記事を書いた。
なんだかんだ楽しむことができたが、そこで一か所大きく飛ばした場所があった。それが「ソフト製作」だ。今回はその部分を詳しく書いていきたい。ちょっと固い内容になります。
概要
改めて簡単に仕組みを紹介する。
「だるまさんがころんだ」を行うと同時に姿勢推定を行い、動きがあったらゲームオーバー。普通の「だるまさんがころんだ」とほとんど同じルールだ。
作る中身の全体像
処理は主に二種類に分かれている。
■ 姿勢推定の処理
・PCのカメラで動画を撮影
・リアルタイムで「姿勢推定」を行う
・時間ごとの姿勢の座標を保持
■ 「だるまさんがころんだ」の処理
・姿勢推定と同時に「だるまさんがころんだ」を行う
・だるまが人を見ているときに動いた場合、ゲームオーバー
・だるまが動きを検知しない間にキーが押されたらクリア!
動かした実際の様子はこんな感じ。
どの姿勢推定を使うか決めよう
さて、最初に考えるのがどの姿勢推定の手法を使おうかというところ。
ここでまっさきに思い浮かんだのはこの二種類。
1. 「Kinect」を使う
2. 「OpenPose」を使う
「Kinect」はいわずと知れたマイクロソフトのモーションセンサだ。しかしこれは「Kinect」を買う必要がある。なのでこれはやめとおこう。
もう一つの「OpenPose」とは、今はやりのディープラーニングを使った姿勢推定の手法だ。おそらく画像から姿勢推定をする手法として一番有名で、日本でも発表当初は大きなニュースとなった。今でも研究ではさかんに使われている。
じゃあ「OpenPose」を使えばいいか。と思いきや、「OpenPose」のライセンスに落とし穴があった。「スポーツ用途には使用不可」。
スポーツ。「だるまさんがころんだ」はスポーツに入るのだろうか。遊びだからスポーツではない? でも身体を動かしているからスポーツと言い張ることもできる。つまり、ライセンスが引っかかる可能性は0ではない……。
グレーな場所に突っ込む勇気はないので、「OpenPose」を使うのはやめておくことにした。残念。
ようやく見つけた姿勢推定の本命
さて、ほかにいい姿勢推定はないのか。調べていると見つかりましたよ!
「PoseNet」。これはかなりライセンスがゆるく、商用利用も可能だ。こっちもディープラーニングを用いた手法だ。そして性能は「OpenPose」にとても近い。これならいいでしょう! ということで「PoseNet」を使うことにした。
プログラミング言語を決めよう
さて、次に決めるのは「PoseNet」を何で作るか。調べてみると、「TypeScript」がいいらしい。これならスマートフォンでも使えるとか。ということでTypeScriptで書くことにした。
――と思ったら無理でした。全然わからん……。TypeScriptとかJavaScriptは使ったことがないけどいけるっしょーと思って書こうとしたら挫折した。
さて、別の言語でないかな。調べてみるとありました。使い慣れたPythonのコードだ。助かった。これならいけるだろう。
ということで、Pythonで作ることにしました!
環境を整えよう
今回の「PoseNet-Python」を動かすためには、「CUDA」を使える環境を整える必要がある。実際に導入している先例があるので、その記事を貼っておく。
せっかくなので、今回利用した環境も残しておく。同じようなことをする人(いるのか?)は参考にしてほしい。
■ PCの環境
・ GPU: RTX2070(ノートPC)
・ CPU: i7 10750H
・ メモリ: 16GB
■ ソフトのバージョン
・ CUDA: 9.0.176
・ CuDNN: 7.3.1
・ opencv-python: 3.4.5.20
動いた判定を作ろう
姿勢推定部分は、でもソフトを元にいろいろいじっていたらなんやかんやでできあがった。
次に必要になるのは動きの判定だ。細かい方法は省略するが大まかな手順はこのようにした。
・ 時間ごとに動いた距離を計算
・ 一定時間の動いた距離を平均
・ 動いた距離がしきい値以上なら動いたと判定
この処理、実は問題が残っている。
それは、「人とPCの距離が近い場合は動いたと判定されやすい」こと。画像で姿勢推定を行う場合、座標の単位は画像の座標に対応している。
これは人が遠くにいるとき。それに対して、
人が近づくと、当然姿勢の座標の変化が大きくなる。
遠くで1cm動いた場合は5ドットしか動かないとしても、カメラの前で動いた場合は100ドットの動きと検知されるみたいなイメージだ。
この問題については、今回いろいろ対処を考えたが、結局は無視することにした。画像の人の座標から身長を推定すればいいかとも思ったが、しゃがんだ場合とかに精度が下がって変な値になりそうな気がしたからだ。
最後に
こういうプログラミングの記事は日本語の情報が少ないので、ちょっとは参考になるかなと思って書いてみた。コードは拙いので公開しないでおくが、もし見たいという物好きな人がいたらのせようと思う(コメントあれば反応します)。