We all know the game ‘rock paper scissors’ that we used to play. I chose to recreate this game in an innovant way. Recently we have been talking a lot about AI, so I decided to create a rock paper scissors using your cam, your real hand and IA to play the game.

How I did it

First of all I created a file called ‘module_trace.py’ to initialize the hand detector AI. It is on the main file ‘jeu.py’ that the fun really is (there will be some variables with French name because it is my native language and the context in witch I code the game required it). The game start a really simple GUI interface on witch you can start playing. You are against the computer (a really simple algorithm to chose randomly between the three choices)

Here is the code of the module to detect the hands :


import cv2

import mediapipe as mp

import time



# création d'une classe pour detecter une main avec pour parametres : self, mode=False, maxHands=2,

#detectionCon=0.5,modelComplexity=1,trackCon=0.5
class handDetector():

    """Constructeur de l'objet """

    def __init__(self, mode=False, maxHands=2, detectionCon=0.5,modelComplexity=1,trackCon=0.5):

        self.mode = mode

        self.maxHands = maxHands

        self.detectionCon = detectionCon

        self.modelComplex = modelComplexity

        self.trackCon = trackCon

        self.mpHands = mp.solutions.hands

        self.hands = self.mpHands.Hands(self.mode, self.maxHands,self.modelComplex,

                                        self.detectionCon, self.trackCon)

        

        self.mpDraw = mp.solutions.drawing_utils #Fonction pour dessiner les points reliant les mains







    def findHands(self,img,draw=True):

        """

        Trouve les  mains, crée les points puis les relei. C'est la structure 

        des mains

        """

             

        # envoie une image en rbg

        imgRGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

        self.results = self.hands.process(imgRGB)



        if self.results.multi_hand_landmarks:

            for handLms in self.results.multi_hand_landmarks:



                if draw:

                    #crée les points et les relie 

                    self.mpDraw.draw_landmarks(img,handLms,

                                                self.mpHands.HAND_CONNECTIONS)



        return img



    def findPosition(self,img, handNo=0, draw=True):

        """

        Répertorie la position/le type de points de repère que nous donnons

        dans la liste et dans la liste où nous avons stocké le type et la

        position des points de repère. La liste a toutes les positions lm

        """



        lmlist = []



        # vérifier si landmarks est détecter

        if self.results.multi_hand_landmarks:

            #savoir de quelle main il est question

            myHand = self.results.multi_hand_landmarks[handNo]

            # avoir les info 

            for id, lm in enumerate(myHand.landmark):

                # hauteur largeur 

                h,w,c = img.shape

                #trouver la position

                cx,cy = int(lm.x*w), int(lm.y*h) 



                lmlist.append([id,cx,cy])



                # Dessiner les points 

                #if draw:

                    #cv2.circle(img,(cx,cy), 15 , (255,0,255), cv2.FILLED)



        return lmlist



#Fonction maine, code princiaple

def main():

    #Frame rates (fps)

    pTime = 0

    cTime = 0

    #entrée numéros 0, port de la caméra utilisée

    cap = cv2.VideoCapture(0)

    detector = handDetector()

    

    #boucle de pour la vidéo

    while True:

        #traiter l'image + liste pour les coordonée 

        success,img = cap.read()

        img = detector.findHands(img)

        lmList = detector.findPosition(img)

        if len(lmList) != 0:

            print(lmList[4])

            

            

        #création des fps

        cTime = time.time()

        fps = 1/(cTime-pTime)

        pTime = cTime

        

        #mettre les fps sur l'ecran

        cv2.putText(img,str(int(fps)),(10,70), cv2.FONT_HERSHEY_PLAIN,3,(255,0,255),3)

            

        cv2.imshow("Video",img) #afficher la cam grace a cv2

        if cv2.waitKey(1) == ord('q'): #appuyter sur 'q' pour quitter la cam

            break





    

    

#dès que le fichier est appeler main se lace automatiquement

if __name__ == "__main__":

    main()

Here is the code for the game 😀:

import cv2
import time
import os 
import module_trace as htm
import tkinter as tk
from tkinter import *
import random
from PIL import Image, ImageTk
import time 


############################################################## FUNCTION : USER INUPUT ##############################################################


def video():
    """
    Using module 'module_trace.py' to:
    - Use the webcam to create video (image list)
    - Link a chosen pattern with the hand to 'rock, papper, scissors'
    - Print an image on the screen of a sheet, stone, or scissors to help the user
    """

    
    global cap
    cap = cv2.VideoCapture(0)
    
    global choix
    choix = ""
    
    # load images and put them in a list to use them later
    fichier = "image"
    myList = os.listdir(fichier)
    
    overlayList = []
    for im in myList:
        image = cv2.imread(f'{fichier}/{im}')
        overlayList.append(image)

        
        
    overlayList[0] = overlayList[3] #bug in the loading so we change manually the parameters
    print(overlayList[0])
    
    pTime = 0
    
    detector = htm.handDetector()   #calling the module
    
    
    tipIds = [4, 8, 12, 16, 20]  #name the id for the special part of the finger (see documenation of mediapipe)
    
    #main loop to run the game
    while True :
        success, img = cap.read()  
        img = detector.findHands(img)
        lmList = detector.findPosition(img , draw=False)
    
        if len(lmList) != 0:    # using mediapipe and the tipIds we are cheking what is the choice of the user
    
            if lmList[8][2] > lmList[6][2] and lmList[16][2] > lmList[14][2] and lmList[20][2] > lmList[18][2] and lmList[20][2] > lmList[18][2]  :
                choix = "pierre"
                img[0: 146, 0:200] = overlayList[2]

            if lmList[8][2] < lmList[6][2] and  lmList[20][2] > lmList[18][2] and  lmList[12][2] < lmList[10][2] :
                choix = "ciseaux"
                img[0: 112, 0:192] = overlayList[0]
            
            if lmList[12][2] < lmList[10][2] and lmList[8][2] < lmList[6][2] and lmList[20][2] < lmList[18][2]:
                choix = "feuille"
                img[0: 150 , 0: 200] = overlayList[1] 

    
            

        
        cTime = time.time()
        fps = 1/(cTime - pTime)  
        pTime = cTime
        
        cv2.putText(img, "appuyez sur 'q' pour valider", (400,700), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3 )
    
        
 
        cv2.imshow("Image", img)
        if cv2.waitKey(1) == ord('q'): # set an exit key
            cv2.destroyAllWindows() #fclsoe the game
            cv2.waitKey(1)
            trouver_vainqueur()  # check the winner (between us an the computer)

            
            break


def c():
    """
    set the game winner using trouver_vainqueur()
    """
    global result2
    result2 = ""
    
    if gagner == 1:
        result2 = "gagné"
    elif gagner == 2:
        result2 = "egalité"
    elif gagner == 3 :
        result2 = "perdu"
        
    return result2
     


def trouver_vainqueur():
    
    """
    first using a simple algorithm we are setting the choice of the computer and we retrun the winner
    """
    global gagner
    global result
    global result2
    global choix_ordi
    
    gagner = 0
    choix_ordi = ""

    
        
    list_choix = ["pierre", "feuille", "ciseaux"]
    a = random.randint(0,2)
    choix_ordi = list_choix[a] # random choice for the computer
    
    
    
    if choix == "pierre" and choix_ordi == "ciseaux":
        gagner = 1
        
    if choix == "ciseaux" and choix_ordi == "feuille":
        gagner = 1
        
    if choix == "feuille" and choix_ordi == "pierre":
        gagner = 1
        
        
    
    if choix == "pierre" and choix_ordi == "pierre":
        gagner = 2
    
    if choix == "feuille" and choix_ordi == "feuille":
        gagner = 2
    
    if choix == "ciseaux" and choix_ordi == "ciseaux":
        gagner = 2
        
        
        
    if choix == "pierre" and choix_ordi == "feuille":
        gagner = 3
            
    if choix == "feuille" and choix_ordi == "ciseaux":
        gagner = 3
        
    if choix == "ciseaux" and choix_ordi == "pierre":
        gagner = 3
            

    c() # finishing the game


    
    f_print() # using the function tu print on the screen using t kinter
    
    return choix, choix_ordi, result2



############################################################## GUI in TKINTER ##############################################################






def f_print():
    """print the result on the screen"""
    
    if gagner == 1:
        texte_r=Label(root,text = result2, font='Times 18 bold',fg='green')  
        texte_r.grid(row = 11, column = 5, columnspan= 2)
        
    elif gagner == 2:
        texte_r=Label(root,text = result2, font='Times 18 bold',fg='black')  
        texte_r.grid(row = 11, column = 5, columnspan= 2)
    
    elif gagner == 3:
        texte_r=Label(root,text = result2, font='Times 18 bold',fg='red')  
        texte_r.grid(row = 11, column = 5, columnspan= 2)
        
        
    
    texte5=Label(root,text= choix_ordi ,font='Times 18 bold ',fg='blue')  
    texte5.grid(row =9, column =8)
    

    
    texte4=Label(root,text= choix ,font='Times 18 bold ',fg='blue')  
    texte4.grid(row =9, column =2)


    

def f ():
    """ create the window and the GUI of the game """
    global root
    root = Tk()
    root.title('PFC')
    #root.iconbitmap('/Users/piedroleyssieux/Desktop/projet_pfc/main_pierre.jpg')
    root.geometry('500x400')

    root.configure(bg='black')
    
    texte1=Label(root,text='PFC',font='Times 22 bold')  
    texte1.grid(row =0, column =5, columnspan= 4)
    
    space4= Label(root, text="", bg = "skyBlue1" )
    space4.grid(row = 1, column=6)
    
    texte6=Label(root,text='choissir entre : ',font='Times 18 bold ',fg='blue')  
    texte6.grid(row =2, column = 0, columnspan = 3)
    
    
    
    img_pierre = ImageTk.PhotoImage(Image.open("main_pierre.jpg").resize((70,70)))
    img_pierre_display = Label(image = img_pierre)
    img_pierre_display.grid(row= 3, column=5)
    
    texte7=Label(root,text='Pierre ',font='Times 18 bold ',fg='blue')  
    texte7.grid(row =4, column = 5)
    
    



    img_ciseaux = ImageTk.PhotoImage(Image.open("main_ciseaux.jpg").resize((70,70)))
    img_ciseaux_display = Label(image = img_ciseaux)
    img_ciseaux_display.grid(row= 3, column=6)
    
    texte7=Label(root,text='Ciseaux ',font='Times 18 bold ',fg='blue')  
    texte7.grid(row =4, column = 6)
    

    
    
    img_feuille = ImageTk.PhotoImage(Image.open("main_feuille.jpg").resize((70,70)))
    img_feuille_display = Label(image = img_feuille)
    img_feuille_display.grid(row= 3, column=7)
    texte7=Label(root,text='Feuille ',font='Times 18 bold ',fg='blue')  
    texte7.grid(row =4, column = 7)


    space4= Label(root, text="", bg = "skyBlue1" )
    space4.grid(row = 8, column=6, columnspan=2)



    texte2=Label(root,text='Toi : ',font='Times 18 bold italic',fg='blue')  
    texte2.grid(row =9, column =1)
    
    texte3=Label(root,text='Ordi : ',font='Times 18 bold italic',fg='blue')  
    texte3.grid(row =9, column =7)
    
    
    space4= Label(root, text="", bg = "skyBlue1" )
    space4.grid(row = 9, column=6, columnspan=2)
    
    space5= Label(root, text="", bg = "skyBlue1" )
    space5.grid(row = 10, column=6, columnspan=2)
    
    space7= Label(root, text="", bg = "skyBlue1" )
    space7.grid(row = 12, column=6, columnspan=2)

    
    
    b = tk.Button(text ="jouer !",font='Times 18 bold ',fg='blue', command = video)
    b.grid(row = 13, column =6, columnspan= 2)
    
    

    root.mainloop()

    
    

f() # start the game

Note that I have been using tutorials, especially from Murtaza’s Workshop and the Google’s IA Mediapipe.

If you want to use easily the modules save the following text file as *.yml and upload it to a Conda virtual env.

name: RPC_game
channels:
  - conda-forge
  - defaults
dependencies:
  - blas=1.0=openblas
  - brotli=1.0.9=h1a28f6b_7
  - brotli-bin=1.0.9=h1a28f6b_7
  - bzip2=1.0.8=h3422bc3_4
  - ca-certificates=2023.01.10=hca03da5_0
  - contourpy=1.0.5=py39h525c30c_0
  - cycler=0.11.0=pyhd3eb1b0_0
  - fonttools=4.25.0=pyhd3eb1b0_0
  - freetype=2.12.1=h1192e45_0
  - giflib=5.2.1=h80987f9_3
  - importlib_resources=5.2.0=pyhd3eb1b0_1
  - jpeg=9e=h80987f9_1
  - kiwisolver=1.4.4=py39h313beb8_0
  - lcms2=2.12=hba8e193_0
  - lerc=3.0=hc377ac9_0
  - libbrotlicommon=1.0.9=h1a28f6b_7
  - libbrotlidec=1.0.9=h1a28f6b_7
  - libbrotlienc=1.0.9=h1a28f6b_7
  - libcxx=14.0.6=h848a8c0_0
  - libdeflate=1.17=h80987f9_0
  - libffi=3.4.2=h3422bc3_5
  - libgfortran=5.0.0=11_3_0_hca03da5_28
  - libgfortran5=11.3.0=h009349e_28
  - libopenblas=0.3.21=h269037a_0
  - libpng=1.6.39=h80987f9_0
  - libtiff=4.5.0=h313beb8_2
  - libwebp=1.2.4=ha3663a8_1
  - libwebp-base=1.2.4=h80987f9_1
  - llvm-openmp=14.0.6=hc6e5704_0
  - lz4-c=1.9.4=h313beb8_0
  - matplotlib=3.7.1=py39hca03da5_1
  - matplotlib-base=3.7.1=py39h78102c4_1
  - munkres=1.1.4=py_0
  - ncurses=6.3=h07bb92c_1
  - numpy-base=1.23.5=py39h90707a3_0
  - openssl=1.1.1t=h1a28f6b_0
  - packaging=23.0=py39hca03da5_0
  - pip=23.0.1=pyhd8ed1ab_0
  - pyparsing=3.0.9=py39hca03da5_0
  - python=3.9.16=hc0d8a6c_0
  - python-dateutil=2.8.2=pyhd3eb1b0_0
  - readline=8.2=h92ec313_1
  - setuptools=67.6.0=pyhd8ed1ab_0
  - six=1.16.0=pyhd3eb1b0_1
  - sqlite=3.40.1=h7a7dc30_0
  - tk=8.6.12=hb8d0fd4_0
  - tornado=6.2=py39h1a28f6b_0
  - wheel=0.40.0=pyhd8ed1ab_0
  - xz=5.2.10=h80987f9_1
  - zipp=3.11.0=py39hca03da5_0
  - zlib=1.2.13=h5a0b063_0
  - zstd=1.5.2=h8574219_0
  - pip:
      - absl-py==1.4.0
      - attrs==23.1.0
      - certifi==2022.12.7
      - cffi==1.15.1
      - charset-normalizer==3.1.0
      - filelock==3.10.2
      - flatbuffers==23.5.26
      - idna==3.4
      - jinja2==3.1.2
      - joblib==1.2.0
      - markupsafe==2.1.2
      - mediapipe==0.10.1
      - mpmath==1.3.0
      - networkx==3.0
      - numpy==1.24.2
      - opencv-contrib-python==4.8.0.74
      - opencv-python==4.8.0.74
      - pandas==2.0.1
      - pillow==9.4.0
      - protobuf==3.20.3
      - pycparser==2.21
      - pytz==2023.3
      - requests==2.28.2
      - scikit-learn==1.2.2
      - scipy==1.10.1
      - sounddevice==0.4.6
      - sympy==1.12rc1
      - threadpoolctl==3.1.0
      - torch==2.1.0.dev20230323
      - torchaudio==2.1.0.dev20230323
      - torchsummary==1.5.1
      - torchvision==0.16.0.dev20230323
      - typing-extensions==4.5.0
      - tzdata==2023.3
      - urllib3==1.26.15
variables:
  CONDA_SUBDIR: osx-arm64
prefix: /Users/piedroleyssieux/miniconda3/envs/testTorch


Categories:

Tags:

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *