先日MediaPipeで手の形状を検出してみました。
elsammit-beginnerblg.hatenablog.com
最後に手の形状を検出してじゃんけんの判定を行ってみました。
これを見てふと、、、
せっかくなのでCPUと対戦出来るじゃんけんゲーム作ったら面白いかな??
と思い立ち、作成することに。
最初はとりあえず、OpenCVのimshowでの表示を用いてじゃんけんゲームを作成してみました。
■できたアプリ
作成できたアプリはこちら!!
音声も自分で用意したものを流しております。
youtu.be
■コードはgithubにて公開中
コードはこちらに格納しております。
よろしければご覧ください。
https://github.com/elsammit/rockpaperscissors-usingmediapipe
こちらのコードですが、
git cloneで取ってきたソースコードにて、
python JankenMain.py
を実行すればOKです。
なお、MediaPipeライブラリのインストールが必要になります。
インストール手順は前回のブログにまとめておりますのでこちらを参考に。
elsammit-beginnerblg.hatenablog.com
■コードに関して
こちらのコードですが、クラスとして下記定義しております。
・handsクラス:MediaPipeライブラリを用いて検出したじゃんけんの手
・Pertnerクラス:CPUの出す手
・Judgeクラス:CPUの手とユーザの手の結果を元に勝ち負け判定
・Onseiクラス:「じゃんけん。ぽん。」音声出力
handsクラスで実施している内容は前回のブログで記載済みになりますので詳細は割愛します。
また、Onseiクラスに関してもメソッドコールで音声出力しているのみになります。
このため、今回はPartnerクラス内で実施している内容について以下でまとめていきたいと思います。
■CPUが出す手の処理
CPU側の処理は下記コードの通りになります。
import cv2 import threading import JankenOnsei import random import time import Define m_Define = Define.Define() m_Onsei = JankenOnsei.Onsei() class Pertner: looretCnt = 1000 filePath = m_Define.HANDSHAPE_ROCK_IMG result_img = cv2.imread(m_Define.HANDSHAPE_ROCK_IMG) StartFlg = False JankenResult = False rsp = "" FinishFlg = False testFlg = False def StartOnseiThread(self): thread1 = threading.Thread(target=m_Onsei.jankenOnsei) thread1.start() def GetHandsMat(self, cnt): if cnt % 10 <= 2: self.filePath = m_Define.HANDSHAPE_ROCK_IMG self.rsp = m_Define.HANDSHAPE_ROCK elif cnt % 10 <= 5: self.filePath = m_Define.HANDSHAPE_SCISSORS_IMG self.rsp = m_Define.HANDSHAPE_SCISSOR elif cnt % 10 <= 9: self.filePath = m_Define.HANDSHAPE_PAPPERS_IMG self.rsp = m_Define.HANDSHAPE_PAPPER def PartnerHands(self): if m_Onsei.onseiStatus == 0: self.GetHandsMat(self.looretCnt) if self.looretCnt > 1000: self.looretCnt = 0 elif m_Onsei.onseiStatus == 1: x = random.randint(0,5) self.GetHandsMat(x) self.JankenResult = True m_Onsei.onseiStatus += 1 elif m_Onsei.onseiStatus == 2: self.JankenResult = False elif m_Onsei.onseiStatus == 3: m_Onsei.onseiStatus = 0 self.StartOnseiThread() self.JankenResult = False self.looretCnt = 0 time.sleep(0.1) resultImage = cv2.imread(self.filePath) return resultImage def PartnerLoop(self): m_Onsei.onseiStatus = 3 while True: self.looretCnt += 1 self.result_img = self.PartnerHands() self.StartFlg = True time.sleep(0.01) if self.FinishFlg == True: break
CPU側の処理としては、大きく分けると
・じゃんけんの掛け声の間は数百ミリ秒単位でグー、チョキ、パーをローリング
・ぽんの掛け声でランダムに処理を切り替える
の2つになります。
こちらの2つの処理の切り替えですが、
音声と同期をとるために、m_Onsei.onseiStatusにて管理しております。
m_Onsei.onseiStatusですが、
m_Onsei.onseiStatus = 0 :じゃんけんの掛け声中。
m_Onsei.onseiStatus = 1 :ぽんを言う直前。CPUの手を決定し表示。
m_Onsei.onseiStatus = 2 :ぽんを言った後。CPUとの勝敗を表示している間の待ち。
m_Onsei.onseiStatus = 3 :次のじゃんけんを行うための初期化処理。
音声ですが、本クラス内でOnseiインスタンスを生成させ、別スレッドで音声出力を実行しております。
じゃんけんの掛け声中のグー、チョキ、パーのルーレットですが、
looretCntの数値により切り替えております。
(こちらは別の方法の方がいいかも?)
こちらの切り替えを実施しているのが、
PartnerHands関数になります。
そして、PartnerHands関数を定期的にコールしているのが、
PartnerLoop関数。
PartnerLoop関数内では10ms間隔でループを実行。
PartnerLoop関数ですが、
このじゃんけんゲームのmain関数にあたる、
JankenMain.py内でmainとは別スレッドでコールしております。
デバッグ用ですがCPU側のみを出力させることも出来るようになっております。
こちらのコードを実行するとCPU側だけの処理が動くようになります。
python PartnerHands.py
実際に実行するとこちらのようになります。
※実際には音声も出力されています。
■最後に
とりあえずのレベルですがじゃんけんゲーム動くレベルまで持っていくことが出来ました!!
ちょっと気になる点もあるので、時間を見て修正していきたいと思います!!
また最新版が出来たらご連絡したいと思います。