Pong Game by Detecting Hand Gesture
All about how to cvzone package to make a simple computer vision game.
Creating the environment for the project
-
Creating conda environment :
conda create -n pong python=3.7 -y
-
Activating the conda environment :
conda activate pong
-
Installing Libraries :
pip install opencv-python
pip install cvzone
-
For this project we are using
cvzone
package to detect hand gesture and overlaying images. You can explore about the packages here
Now Importing required modules
import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector
import numpy as np
- Importing the required images
imgBackground = cv2.imread("images/Background.png")
imgGameOver = cv2.imread("images/gameOver.png")
imgBall = cv2.imread("images/Ball.png", cv2.IMREAD_UNCHANGED)
imgBat1 = cv2.imread("images/bat1.png", cv2.IMREAD_UNCHANGED)
imgBat2 = cv2.imread("images/bat2.png", cv2.IMREAD_UNCHANGED)
Logic of the game :
First read the frame by taking images using OpenCV.
Fliping the image horizontally using **cv2.flip** function available on OpenCV.
Setting variables as ballPos for initial place of ball speedX and speedY for initial speed of ball, gameOver is False as a initial value and we set a score as a dictionary and put 0 as a value since during a gameplay we can add the score and store on that.
-
We overlay the images using **cv2.addWeighted** to display the original images read by opencv.
-
Check for hand section :
- After finding hand coordinates using
cvzone
findhands method we also take the shape of bat images and perform the operation to set our hands positions in the middle of bat. - We use numpy np.clip function to set our bat inside the image only.
- Now if the hand is left we overlay bat1 images in the gameover image which is already overlayed in frame image.
- Again to make sure ball is just hitting the bat we set a if condition and if true we reverse the speed of the ball and increase the score by 1. Here we increment ballPos[0] by 30 to make visual effect that ball just hit the bat
- We do same for right hand.
- After finding hand coordinates using
-
Now we check if the game is over or not by setting the if condition where if ballPos is below its limit and above its limit.
-
If game is over then we display the game over images where total score is displayed.
-
If game is not over then keep continuing the game by displaying the scores.
-
-
Finally we set a condition to replay the game when it is over by hitting r key in keyboard.
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
# Hand Detector
detector = HandDetector(detectionCon=0.8, maxHands=2)
# Variables
ballPos = [100, 100]
speedX = 15
speedY = 15
gameOver = False
score = [0, 0]
while True:
_, img = cap.read()
img = cv2.flip(img, 1)
imgRaw = img.copy()
# Find the hand and its landmarks
hands, img = detector.findHands(img, flipType=False) # with draw
# Overlaying the background image
img = cv2.addWeighted(img, 0.4, imgBackground, 0.6, 0)
# Check for hands
if hands:
for hand in hands:
x, y, w, h = hand['bbox']
h1, w1, _ = imgBat1.shape
y1 = y - h1 // 2
y1 = np.clip(y1, 20, 415)
if hand['type'] == "Left":
img = cvzone.overlayPNG(img, imgBat1, (59, y1))
if 59 < ballPos[0] < 59 + w1 and y1 < ballPos[1] < y1 + h1:
speedX = -speedX
ballPos[0] += 30
score[0] += 1
if hand['type'] == "Right":
img = cvzone.overlayPNG(img, imgBat2, (1195, y1))
if 1195 - 50 < ballPos[0] < 1195 and y1 < ballPos[1] < y1 + h1:
speedX = -speedX
ballPos[0] -= 30
score[1] += 1
# Game Over
if ballPos[0] < 40 or ballPos[0] > 1200:
gameOver = True
if gameOver:
img = imgGameOver
cv2.putText(img, str(score[1] + score[0]).zfill(2), (585, 360), cv2.FONT_HERSHEY_COMPLEX,
2.5, (200, 0, 200), 5)
# If game not over move the ball
else:
# Move the Ball
if ballPos[1] >= 500 or ballPos[1] <= 10:
speedY = -speedY
ballPos[0] += speedX
ballPos[1] += speedY
# Draw the ball
img = cvzone.overlayPNG(img, imgBall, ballPos)
cv2.putText(img, str(score[0]), (300, 650), cv2.FONT_HERSHEY_COMPLEX, 3, (255, 255, 255), 5)
cv2.putText(img, str(score[1]), (900, 650), cv2.FONT_HERSHEY_COMPLEX, 3, (255, 255, 255), 5)
img[580:700, 20:233] = cv2.resize(imgRaw, (213, 120))
cv2.imshow("Image", img)
key = cv2.waitKey(1)
if key == ord('r'):
ballPos = [100, 100]
speedX = 15
speedY = 15
gameOver = False
score = [0, 0]
imgGameOver = cv2.imread("images/gameOver.png")