※このブログエントリーは「グローカルな仲間たち」が主催する年忘れサイエンス・サロン ~宇宙と機械学習を体感しよう~(12月27日(金))でのミニ講演で話した内容を再編集しまとめ直したものです。
寒い冬の夜、ちょっと不思議なサイエンスの世界に浸ってみませんか?今年の年末は、お酒を片手に科学を楽しむ特別なサロン会。かつてファラデーがクリスマスに科学実験で人々を魅了したように、私たちも科学の不思議と楽しさを分かち合う特別な夜を過ごしましょう!
という素敵な趣旨のイベントで、Scratchと機械学習について紹介してほしいという依頼を12月上旬に受けました。
もうひとつのトークである「ゆうこ先生と宇宙 -折り紙で宇宙を表現する」では、元JAXA研究員で宇宙と科学を紹介するプログラムをこどもたちに届けているゆうこ博士と、地球以外に知的生命体は存在するのか?といったことを議論したり、折り紙でIKAROSの電力セイルの構造を折って学んだりして、好奇心をとてもくすぐられました。
さて、その依頼というのが、原文ママ載せると
「猪木」の顔真似をして、どこまで「猪木」になったのかということを数値で測ることはできるのでしょうか(笑)
参考: アントニオ猪木
というものでした。
Scratchの独自拡張機能で、カメラに映した画像があらかじめ学習させた画像のどれに近いかを判定できるML2ScratchやTMScratchを利用すればできそうですが、顔の特徴点をもっと精密に推定できるFacemesh2Scratchを使ったほうが精度良く作れそうだと思ったので、今回はこちらを紹介することにしました。
ScratchのMODである
Stretch3: https://stretch3.github.io/
を使います。Facemesh2Scratchはじめ、先に紹介したML2ScratchやTM2Scratch、さらに他の機械学習を使った独自拡張機能を使うことができます。
基本的な機能を紹介するサンプルプログラムがFacemesh2Scratchのページにあるので、これをベースにして作っていきます。
https://github.com/champierre/facemesh2scratch
を開いて、サンプルプロジェクトの最初の random.sb3 をダウンロードします。
Stretch3 のメニューで ファイル > コンピューターから読み込む を選んで、ダウンロードした random.sb3 を開きます。
緑の旗ボタンを押してプログラムを実行すると、以下のように自分の顔の上のあちこちに黄色いボールが表示されます。
これで準備ができました。
さて、「猪木」の顔真似をしてそれを数値で表示するということは、これは「猪木」顔かどうか?を判定できるということです。数値で表すより、「猪木」顔であれば「猪木」に変身できるという方が楽しそうです。
ということで、紹介するプログラムの内容を
「猪木」顔だったら、「猪木」に変身できる
と再定義します。
では、「猪木」顔というのはどういう顔なのでしょうか?
「猪木」とは、、、
あご
ですね。
あごがいつもより伸びていたら「猪木」に変身できるようにしましょう。
プログラムを実装するには「あごがいつもより伸びたら?」を厳密に定義する必要があります。
Facemesh2Scratchが内部で使っているFacemeshは、顔の上の468ヶ所の特徴点の位置を推定することができます。以下が、各特徴点が顔のどの部位にあたるかを示す図です。
出典: https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection
図によると、たとえばあごの一番先は152となっています。
random.sb3のプログラムを以下のように変えます。
1から468までの乱数を keypoint という変数にセットしていたところをやめて、153固定にすることで、153番目の特徴点にだけ黄色いボールを置くようにしています。見やすいようにボールの大きさは40%に変更してあります。また、Facemesh2Scratch ではわかりやすさを優先して、特徴点の番号を1はじまりで468までふっているのに対し、もとの Facemesh の図では0はじまり、467までの番号がふられているので、図では152番目でしたが、プログラムでは1だけずらした153番目に設定しています。
緑の旗ボタンを押して再度実行してみると、以下のようにあごの先にだけ常に黄色いボールが表示されます。
プログラムを少し解説します。
の部分で、keypoint という変数に153をセットし、そのあとで黄色いボールのx座標を1人目の keypoint (つまり153)番目の部位のx座標に、y座標は1人目の keypoint (=153)番目の部位のy座標にあわせています。これを「ずっと」おこなうことで、常に黄色いボールは153番目の部位、つまりあごの先を追いかけることになるのです。
Facemesh2Scratch では顔の各部位のx座標とy座標を取得できることがわかりました。
であるならば、「あごがいつもより伸びたら?」を判定するためにあごの長さを求めれば良さそうです。
あごの長さとは?
ここでは、あごの長さとは、
鼻下のy座標 - あごの先のy座標
と定義することにします。
先に登場した各特徴点が顔のどの部位にあたるかを示す図によれば、鼻のすぐ下は164(Facemesh2Scratchでは165)です。
以上をもとに、あごの長さを常に表示するようにプログラムを書き換えます。
緑の旗をクリックして実行します。
普段のあごの長さ40近辺ですが、
「猪木顔」をしてみると、あごの長さが49まで上がりました。
あごの長さがたとえば 45 以上になったら、猪木に変身するというプログラムを書けばうまくいきそうです。
ところがこの方法には欠陥があります。
この長さは、画面上での長さなので以下のように顔をカメラに近づけてしまうと、猪木顔でもないのにあごの長さは長くなってしまうのです。
カメラからの距離に関係なく、あごの長さが普段よりも長くなったら?を定義するにはどうすればいいでしょうか?
それには長さが変わらない顔の他の部分と比較すれば良いのです。
顔の他の部分で長さが変わらない部分とは?
縦幅に比べてなかなか変えることができない横幅などいろいろあるのですが、ここでは、右目頭と左目頭の間隔を使うことにします。
再び各特徴点が顔のどの部位にあたるかを示す図によれば、右目頭は133(Facemesh2Scratchでは134)、左目頭は362(Facemesh2Scratchでは363)です。
右目頭と左目頭の間隔は、
右目頭のx座標 - 左目頭のx座標
で表せます。
あごの長さが目頭間の距離の何倍長いか?という比率は、同じ状態の顔であれば、顔がカメラに近くても遠くても変わらないはずです。
そこで、
あごの長さ / 目頭間の距離
を常に表示するようにプログラムを変更しました。
あごの先に黄色いボールを表示するのはもう不要なのでやめています。またわかりやすいように目頭間の距離とあごの長さを表示するようにしていますが、これはデバッグ用の別のコードで実現しています。(最後に掲載するサンプルプログラム inoki.sb3 に含まれているので興味があれば参照してください)
通常だと あごの長さ/目頭間の距離 は 1.8 くらいですが、
猪木顔をすると 2 以上になりました。
カメラに顔を近づけても、遠ざけても変わりません。
敷居値を2にしておいて、それ以上になったら猪木に変身する、というようにすればうまくいきそうです。
もしあごの長さ/目頭間の距離が2以上になったら、「猪木」というメッセージを送るようにします。
こちらが「猪木」のメッセージを受け取る側のプログラムです。普段は表示されていませんが「猪木」のメッセージを受け取ったら表示して、5秒後に再び隠すようにしています。
実物の猪木の顔が写っている素材はフリーで利用できるものが見つからなかったので、photoAC の
https://www.photo-ac.com/main/detail/3253627/
にあったフリー素材を使っています。
猪木顔をしたら、猪木に変身できるようになりました。
紹介した猪木に変身できるプログラムは、以下リンク先からダウンロードできるようにしておきました。
https://github.com/champierre/facemesh2scratch/raw/master/sample_projects/inoki.sb3
Stretch3: https://stretch3.github.io/ から開くことができます。
このエントリーを参考にして、Facemesh2Scratch を使ったほかに面白いプロジェクトができたらぜひハッシュタグ #facemesh2scratch をつけて Tweet したりして教えてください。
2024/12/28 16:41:00