人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

カメラを用いた指認識コントローラーの作り方②指認識【Unity, Mediapipe, Websocket】

f:id:hiro-htm877:20220130092803j:plain

 

本記事のテーマ

指に連動してキャラクターが動くアプリを制作する。

制作環境

・Unity2020.3.26.f1

・Mediapipe Python

・NodeJs

本記事ではPythonで指認識を行い、Websocketサーバーへキャラクターの移動量を送信する機能の作り方を説明します。

■前記事

カメラを用いた指認識コントローラーの作り方①リアルタイム同期通信【Unity, Mediapipe, Websocket】 - 人工知性を作りたい

 

仕様書(指認識コントローラー)

■機能

1. 指の形を認識する

 ”1”、”2”、”3”、”4”、”5”、”OK”、キツネ”、”いいね”

 ※上記以外は”1”とする

2. Pythonスクリプトを起動したときに指認識で動かすオブジェクトを生成

 画像の黒い球

3. 手を”1”にしたときの人差し指先端を基準位置として、指の移動量を計算する

4. 3で計算した移動量を随時Websocketサーバーへ送信する。

f:id:hiro-htm877:20220130083214p:plain

 

作成したコード

・JavaScriptsフォルダ:Websocketサーバー用

・Pythonフォルダ:指認識(Mediapipe)、Websocketクライアント用

・Unityフォルダ:リアルタイム同期通信アプリ、Websocketクライアント用

GitHub - hiro877/FingerController-Unity-Mediapipe

 

実行方法

GitHub - hiro877/FingerController-Unity-Mediapipe

上記のコードをダウンロードする。

1. mediapipe Pythonの環境を構築する(手順は下記サイト参照)

  MediaPipe in Python - mediapipe

2. JavaScriptsフォルダ内のws.jsを起動する

 $ node we.js

3. UnityHub→リストに追加でUnityProjectsフォルダを選択し起動する。

4. 1で作成した環境からPythonフォルダ内のclient.pyを実行する。

※Pythonなどで必要な求められたパッケージをインストールしてください。

 

作り方

指認識にはMediapipeのhand trackingを使用します。

コードはKazuhito00さんが作成しているサンプルを編集しています。

■元コード

・sample_hand.py

https://github.com/Kazuhito00/mediapipe-python-sample

■完成コード

・Python/client.py

 

実装手順

0. sample_hand.pyをダウンロード

1. 指の形認識の処理を追加

2. 指の移動量の計算処理を追加

3. Websocketへの送信

1. 指の形認識の処理を追加

下記記事で説明されているJavaScriptのコードをPythonに置き換えました。

すみませんが、内容については把握していません。

ご存知の方はコメント欄で教えください!

MediaPipe 入門 (6) - 指ポーズの検出|npaka|note

■実装部分

Python/client.py

・calcDistance()

・calcAngle()

・cancFingerAngle()

・detectFingerPose()

2. 指の移動量の計算処理を追加

detectFingerPoseで指の形を認識します。

基準値となるx, y座標を記録するorigin_posを定義しておきます。(初期値は空リスト)

最初のみ、認識した指の形が”1”のときorigin_posに基準値となるx, y座標を記録します。

2回目以降は現在の人差し指の位置と基準値との距離を計算して、基準値で割ることで正規化(-1 ~ 1の間に収める)をしています。

■実装コード

finger_pose = detectFingerPose(landmark_point)
if finger_pose == "1":
    if origin_pos:
        cv.circle(debug_image, origin_pos, 5, (0, 0, 255), 2)
        cv.circle(debug_image, index_finger_pos, 5, (0, 0, 255), 2)
        finger_x, finger_y = (origin_pos[0]-index_finger_pos[0])/origin_pos[0], (origin_pos[1]-index_finger_pos[1])/origin_pos[1]
        data["pos_x"] = -1*finger_x
        data["pos_y"] = finger_y
        ws.send(json.dumps(data))
        result =  ws.recv()
    else:
        origin_pos = index_finger_pos
        cv.circle(debug_image, origin_pos, 5, (0, 0, 255), 2)
else:
    origin_pos = []

 

3. Websocketへの送信

まず、起動後にWebsocketサーバーとのコネクションを確立します。

# Websocket ########################################################
ws = create_connection("ws://192.168.0.29:3000")

次に、指認識で移動させるオブジェクトを生成するJsonデータを生成します。

data_connect = {
"action": "connect",
"room_no": 1,
"user": "mediapipe",
"pos_x": 2,
"pos_y": 0,
"pos_z": 2,
"way": "neutral",
"range": 0,
}
ws.send(json.dumps(data_connect))

その後は、カメラが指を認識している間Websocketサーバーへ移動量を送信します。

data = {
"action": "move",
"room_no": 1,
"user": "mediapipe",
"pos_x": 2.1,
"pos_y": 0.1,
"pos_z": 0,
"way": "mediapipe",
"range": 0,
}
data["pos_x"] = -1*finger_x
data["pos_y"] = finger_y
ws.send(json.dumps(data))

最後に、生成したオブジェクトを退出させる処理をスクリプトが終了する直前に行います。

# キー処理(ESC:終了) #################################################
key = cv.waitKey(1)
if key == 27: # ESC
ws.send(json.dumps(data_disconnect))
result = ws.recv()
ws.close()
break

 

 

以上、ご参考になると幸いです!

質問などは下のコメント欄でお待ちしております!

分かりにくいなどのクレームもお待ちしております!