Skip to content

Commit

Permalink
Ai rockpaper scisor game first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
AadrianLeo committed Jul 6, 2022
0 parents commit ac0d1fa
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 0 deletions.
197 changes: 197 additions & 0 deletions HandTrackingModule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"""
Hand Tracking Module
By: Computer Vision Zone
Website: https://www.computervision.zone/
"""

import cv2
import mediapipe as mp
import math


class HandDetector:
"""
Finds Hands using the mediapipe library. Exports the landmarks
in pixel format. Adds extra functionalities like finding how
many fingers are up or the distance between two fingers. Also
provides bounding box info of the hand found.
"""

def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
"""
:param mode: In static mode, detection is done on each image: slower
:param maxHands: Maximum number of hands to detect
:param detectionCon: Minimum Detection Confidence Threshold
:param minTrackCon: Minimum Tracking Confidence Threshold
"""
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.minTrackCon = minTrackCon

self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
min_detection_confidence=self.detectionCon,
min_tracking_confidence=self.minTrackCon)
self.mpDraw = mp.solutions.drawing_utils
self.tipIds = [4, 8, 12, 16, 20]
self.fingers = []
self.lmList = []

def findHands(self, img, draw=True, flipType=True):
"""
Finds hands in a BGR image.
:param img: Image to find the hands in.
:param draw: Flag to draw the output on the image.
:return: Image with or without drawings
"""
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)
allHands = []
h, w, c = img.shape
if self.results.multi_hand_landmarks:
for handType, handLms in zip(self.results.multi_handedness, self.results.multi_hand_landmarks):
myHand = {}
## lmList
mylmList = []
xList = []
yList = []
for id, lm in enumerate(handLms.landmark):
px, py, pz = int(lm.x * w), int(lm.y * h), int(lm.z * w)
mylmList.append([px, py, pz])
xList.append(px)
yList.append(py)

## bbox
xmin, xmax = min(xList), max(xList)
ymin, ymax = min(yList), max(yList)
boxW, boxH = xmax - xmin, ymax - ymin
bbox = xmin, ymin, boxW, boxH
cx, cy = bbox[0] + (bbox[2] // 2), \
bbox[1] + (bbox[3] // 2)

myHand["lmList"] = mylmList
myHand["bbox"] = bbox
myHand["center"] = (cx, cy)

if flipType:
if handType.classification[0].label == "Right":
myHand["type"] = "Left"
else:
myHand["type"] = "Right"
else:
myHand["type"] = handType.classification[0].label
allHands.append(myHand)

## draw
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)
cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
(255, 0, 255), 2)
cv2.putText(img, myHand["type"], (bbox[0] - 30, bbox[1] - 30), cv2.FONT_HERSHEY_PLAIN,
2, (255, 0, 255), 2)
if draw:
return allHands, img
else:
return allHands

def fingersUp(self, myHand):
"""
Finds how many fingers are open and returns in a list.
Considers left and right hands separately
:return: List of which fingers are up
"""
myHandType = myHand["type"]
myLmList = myHand["lmList"]
if self.results.multi_hand_landmarks:
fingers = []
# Thumb
if myHandType == "Right":
if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)
else:
if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)

# 4 Fingers
for id in range(1, 5):
if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
fingers.append(1)
else:
fingers.append(0)
return fingers

def findDistance(self, p1, p2, img=None):
"""
Find the distance between two landmarks based on their
index numbers.
:param p1: Point1
:param p2: Point2
:param img: Image to draw on.
:param draw: Flag to draw the output on the image.
:return: Distance between the points
Image with output drawn
Line information
"""

x1, y1 = p1
x2, y2 = p2
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
length = math.hypot(x2 - x1, y2 - y1)
info = (x1, y1, x2, y2, cx, cy)
if img is not None:
cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
return length, info, img
else:
return length, info


def main():
cap = cv2.VideoCapture(0)
detector = HandDetector(detectionCon=0.8, maxHands=2)
while True:
# Get image frame
success, img = cap.read()
# Find the hand and its landmarks
hands, img = detector.findHands(img) # with draw
# hands = detector.findHands(img, draw=False) # without draw

if hands:
# Hand 1
hand1 = hands[0]
lmList1 = hand1["lmList"] # List of 21 Landmark points
bbox1 = hand1["bbox"] # Bounding box info x,y,w,h
centerPoint1 = hand1['center'] # center of the hand cx,cy
handType1 = hand1["type"] # Handtype Left or Right

fingers1 = detector.fingersUp(hand1)

if len(hands) == 2:
# Hand 2
hand2 = hands[1]
lmList2 = hand2["lmList"] # List of 21 Landmark points
bbox2 = hand2["bbox"] # Bounding box info x,y,w,h
centerPoint2 = hand2['center'] # center of the hand cx,cy
handType2 = hand2["type"] # Hand Type "Left" or "Right"

fingers2 = detector.fingersUp(hand2)

# Find Distance between two Landmarks. Could be same hand or different hands
length, info, img = detector.findDistance(lmList1[8][0:2], lmList2[8][0:2], img) # with draw
# length, info = detector.findDistance(lmList1[8], lmList2[8]) # with draw
# Display
cv2.imshow("Image", img)
cv2.waitKey(1)


if __name__ == "__main__":
main()
Binary file added Resources/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Resources/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Resources/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Resources/BG.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from random import random
from sre_constants import SUCCESS
import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector
import time
import random


cap = cv2.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)

detector = HandDetector(maxHands=1)

timer = 0
stateResult = False
startGame = False
scores = [0,0]

while True:
imgBG = cv2.imread('Resources/BG.png')
SUCCESS, img = cap.read()

imgScaled = cv2.resize(img, (0,0), None, 0.875, 0.875)
imgScaled = imgScaled[:, 80:480]

# find hands
hands, img = detector.findHands(imgScaled)

if startGame:

if stateResult is False:
timer = time.time() - initialTime
cv2.putText(imgBG, str(int(timer)), (605,435),cv2.FONT_HERSHEY_PLAIN, 6, (255, 0, 255), 4)

if timer > 3:
stateResult = True
timer = 0

if hands:
playerMove = None
hand = hands[0]
fingers = detector.fingersUp(hand)
if fingers == [0, 0, 0, 0, 0]:
playerMove = 1
if fingers == [1, 1, 1, 1, 1]:
playerMove = 2
if fingers == [0, 1, 1, 0, 0]:
playerMove = 3


randomNumber = random.randint(1, 3)

imgAI = cv2.imread(f'Resources/{randomNumber}.png', cv2.IMREAD_UNCHANGED)
imgBG = cvzone.overlayPNG(imgBG, imgAI, (149, 310))

# Player wins
if (playerMove == 1 and randomNumber == 3) or \
(playerMove == 2 and randomNumber == 1) or \
(playerMove == 3 and randomNumber == 2):
scores[1] +=1

# AI wins
if (playerMove == 3 and randomNumber == 1) or \
(playerMove == 1 and randomNumber == 2) or \
(playerMove == 2 and randomNumber == 3):
scores[0] +=1

imgBG[234:654, 795:1195] = imgScaled

if stateResult:
imgBG = cvzone.overlayPNG(imgBG, imgAI, (149, 310))

cv2.putText(imgBG, str(scores[0]), (410,215),cv2.FONT_HERSHEY_PLAIN, 4, (255, 225, 255), 6)
cv2.putText(imgBG, str(scores[1]), (1112,215),cv2.FONT_HERSHEY_PLAIN, 4, (255, 225, 255), 6)




# cv2.imshow('image', img)
cv2.imshow('BG', imgBG)
# cv2.imshow('Scaled', imgScaled)
key = cv2.waitKey(1)
if key == ord('s'):
startGame = True
initialTime = time.time()
stateResult = False

0 comments on commit ac0d1fa

Please sign in to comment.