Virtual Hand Cricket Game using OpenCV
A virtual Hand Cricket game implemented using OpenCV and Machine learning technologies to enable plyers to relive the game virtually with a bot.
Objective :
As children, a lot of us grew up playing the game of hand cricket with our friends and had a lot of fun! During times of social distancing, I figured it would be fun to play the game virtually. Hence I opted for OpenCV to implement the game.
In this game, you have the Player(or User) and the Bot. The model will recognize the number the player shows and the bot will randomly generate a number. When both Player and Bot play the same number the user batting will get out and the other tries to beat them.
OpenCV
OpenCV (Open Source Computer Vision Library) is an open-source computer vision and machine learning software library. OpenCV was built to provide a common infrastructure for computer vision applications and to accelerate the use of machine perception in commercial products.
Importing Libraries
- cv2: OpenCV [pip install opencv]
- numpy: for handling arrays as well as for math [pip install numpy]
- imutills: convenience functions to make basic image processing functions such as translation, rotation, resizing more easier with OpenCV[pip install imutils]
import cv2 as cv
import numpy as np
import imutils
Setting Initial Player and Bot Score
player_score = 0
bot_score = 0
player = False
bot = True
player_status = False
bot_status = False
Game_status = “Player Begins”
def check_status(player_score, bot_score):
if player_score > bot_score:
print(‘* * * Player wins * * *’)
else:
print(‘* * * Bot wins * * *’)
Detecting the fingers/ Score of Player
To calculate the score of the player we will use OpenCV to detect the number of fingers live during video display. We are using contours, masks, convex hulls, and defect detection to identify the same.
Masks
- hsv: Change BGR (blue, green, red) image to HSV (hue, saturation, value).
- lower_skin: lower range of skin color in HSV.
- upper_skin: upper range of skin color in HSV.
- mask: Detect skin on the range of lower and upper pixel values in the HSV colorspace.
- blur: blurring the image to improve masking
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_skin = np.array([0, 20, 80], dtype=np.uint8) upper_skin = np.array([20,255,255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)mask = cv2.dilate(mask,kernel,iterations = 4)
mask = cv2.GaussianBlur(mask,(5,5),100).
Contours
contours,hierarchy= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) if len(contours) > 0:
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt = contours[max_index]
epsilon = 0.0005*cv2.arcLength(cnt,True)
approx= cv2.approxPolyDP(cnt,epsilon,True)
After identifying the maximum area and drawing the contours on the hand, we approximate it to get a much more accurate contour.
Convex Hull
hull = cv2.convexHull(cnt)
areahull = cv2.contourArea(hull)
areacnt = cv2.contourArea(cnt)
Counting Defects (Fingers)
According to the convex hull, we have formed, we are going to identify the defects. The defects are points that belong to the convex hull but not the contours.
hull = cv2.convexHull(approx, returnPoints=False)
defects = cv2.convexityDefects(approx, hull)
Counting Defects:
#code for finding no. of defects due to fingers
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(approx[s][0])
end = tuple(approx[e][0])
far = tuple(approx[f][0])
Cosine Theorem
We have calculated the number of fingers using the cosine theorem.
In trigonometry, the law of cosines relates the lengths of the sides of a triangle to the cosine of one of its angles.
Formula
Using this theorem and OpenCV’s Convexity Defects,m we are detecting and counting the fingers. Convexity Defects returns an array where each row contains these values: start point, endpoint, farthest point, and approximate distance to the farthest point.
# find length of all sides of triangle
a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
b= math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) # apply cosine rule here
angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57if angle <= 90:
count_defect += 1
cv2.circle(img, far, 5, (255,0,0), -1)#draw lines around hand
cv2.line(img,start, end, (255,0,0), 3)
Finally, assing the number of defects + 1 to the player’s score
count_defect += 1
player_num = count_defect
Calculating the Bot Score and Displaying
Assing the random function to the bot score when the Player is not batting and compare both scores and display.
If the Player bats first, add up the score of the player in each iteration.
Else, update the bot score accordingly.
Flask API
To connect the model to Flask, there are 3 steps:
- Add the VideoCamera function
class VideoCamera(object):
def __init__(cap):
#real time video capture
cap.video = cv2.VideoCapture(0, cv2.CAP_DSHOW)
def __del__(cap):
cap.video.release()
def get_frame(cap):
try:
2. App.py
Add the output from the VideoCamera function to the flask app route function and import the necessary request.
3. index.html
Create a template folder and add an index.html file with similar content. Add the video feed from the function as the image tag in the HTML. If you want add more details to the HTML page.
<html>
<head>
<title>Hand Cricket API</title>
</head>
<body>
<h1>Hand Cricket API</h1>
<img id="bg" src="{{ url_for('game') }}">
</body>
</html>
Also check out my GitHub repository for the whole code and star the repo: https://github.com/HarshiniR4/Virtual-Hand-Cricket
If you like the blog, do leave a star!
Happy Coding!
References: