ラズパイ7日目①:カメラモジュールから動画を撮影してジェスチャーを判定する
今回は、Raspberry Pi + Edge TPU + PoseNet を使ったジェスチャー判定について勉強しました。
- Raspberry Pi 3 Model B+
- カメラ:Raspberry Pi Camera B01 (Rev1.3)
- Edge TPU:Google Coral Edge TPU Accelerator vertion 1.0
- 機械学習モデル:Google Coral PoseNet
作ったもの
右手を水平に左方向に動かす(スマホでスワイプするイメージ)と「RIGHT SCROLL GESTURE」を出力するプログラムです。前回同様、顔部分には円形オブジェクトを重ねています。
ポーズとジェスチャーの違い
ポーズとジェスチャーの違いですが、自分なりの解釈では
ポーズ判定 ⇒ 関節の角度や座標から特定の姿勢を判定すること。1フレームのみ解析する。
ジェスチャー判定 ⇒ 関節の角度や座標の遷移から特定の動きを判定すること。複数フレームを解析する。
きちんとした勉強をしたわけじゃないのであくまでイメージですが。
なお前回のポーズ判定の話はコチラ
ジェスチャーの判定方法
ポーズ判定の回と同様、ネットにはあまりやり方が載っていないため、自力でがんばる日々…
ゲームプログラミングの本とかに解説されてないものかしら~
とにかく1フレームでやってたポーズ判定を、複数フレーム介してやればいいだけなハズ!
以下の条件を満たした場合に『右スクロール』とジェスチャー判定させました。
- 右手が前フレームよりも左側にある(つまり右手を左方向に移動させている)
- 上記の動作を5フレーム連続で行っている
なぜ5フレームかというと、1秒未満でジェスチャー判定させたかったから。私の環境ではPoseNetのフレームレートが6〜7fpsだったので5フレームとしました。30fpsなら20フレームにするなど適当に調整してください。
KEYPOINTS = ( 'nose', 'left eye', 'right eye', 'left ear', 'right ear', 'left shoulder', 'right shoulder', 'left elbow', 'right elbow', 'left wrist', 'right wrist', 'left hip', 'right hip', 'left knee', 'right knee', 'left ankle', 'right ankle' ) dict_KEYPOINTS = { 'nose':0, 'left eye':1, 'right eye':2, 'left ear':3, 'right ear':4, 'left shoulder':5, 'right shoulder':6, 'left elbow':7, 'right elbow':8, 'left wrist':9, 'right wrist':10, 'left hip':11, 'right hip':12, 'left knee':13, 'right knee':14, 'left ankle':15, 'right ankle':16 } def copy_to_prepose(pose, prepose): tmp=copy.copy(prepose) prepose=[] if len(tmp) == 0: for i in range(17): tmp.append((0,0)) for point_i in KEYPOINTS: prepose.append(((pose.keypoints.get(point_i).yx[1]),(pose.keypoints.get(point_i).yx[0]))) if prepose[dict_KEYPOINTS[point_i]][0] == '': prepose[dict_KEYPOINTS[point_i]][0] = tmp[dict_KEYPOINTS[point_i]][0] if prepose[dict_KEYPOINTS[point_i]][1] == '': prepose[dict_KEYPOINTS[point_i]][1] = tmp[dict_KEYPOINTS[point_i]][1] return prepose def gesture_check(pose,prepose,frameCnt): #初回は前フレームが存在しないため何もせず終了 if len(prepose) == 0: return frameCnt #右手が前フレームよりも左側に移動した場合、frameCntを+1する if pose.keypoints.get('right wrist').yx[1] > prepose[dict_KEYPOINTS['right wrist']][0]: frameCnt += 1 else: frameCnt = 0 #5フレーム連続で同じ動作を検知した場合、右スクロールジェスチャーと判定する if frameCnt >= 5: print('RIGHT SCROLL GESTURE') frameCnt = 0 return frameCnt def main(): ・・・略・・・ prepose = [] frameCnt = 0 ・・・略・・・ def render_overlay(engine, output, src_size, inference_box): nonlocal n, sum_process_time, sum_inference_time, fps_counter, prepose, frameCnt ・・・略・・・ for pose in outputs: ・・・略・・・ frameCnt = gesture_check(pose,prepose,frameCnt) prepose=copy_to_prepose(pose,prepose) ・・・略・・・
一番ややこしかったのが、前フレームのKeyPoint情報をどうやって取得するかということ。次フレームのKeyPoint情報取得が始まる前に、現在のKeyPoint情報を退避させておけばいいのだけど、Pythonのグローバル変数とローカル変数の仕組みやら、ListとTupleの違いやらに躓きました~。Pythonなかなか癖あるなぁ。
ところではてなブログのコードハイライトがいまいちなんだけどどうにかならんものか。