├── .vscode └── settings.json ├── Game Controller.ipynb ├── README.md ├── media └── Basic Interface.png └── requirements.txt /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.typeCheckingMode": "basic" 3 | } -------------------------------------------------------------------------------- /Game Controller.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Importing Necessary Libraries" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import cv2\n", 17 | "import mediapipe\n", 18 | "import traceback\n", 19 | "import math\n", 20 | "import keyboard" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "# Defining Functions" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "#It shows small points and coordinates on the tip of fingers\n", 37 | "\n", 38 | "def show(i,frame):\n", 39 | " if i is not None:\n", 40 | " coor = mediapipe.solutions.drawing_utils._normalized_to_pixel_coordinates(i.x,i.y,fw,fh)\n", 41 | " if coor is not None:\n", 42 | " frame=cv2.circle(frame, coor, 5, (0, 0, 255), -1)\n", 43 | " cv2.putText(frame,str(coor),(coor[0]+10,coor[1]+10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0, 0), 2)\n", 44 | " return frame" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "# Defining Keyboard Press & Release Function" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 3, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "#This function is used for pressing and releasing the keyboard buttons\n", 61 | "\n", 62 | "def keybd(ratio,frame):\n", 63 | " if ratio is not None:\n", 64 | " if ratio>=0.35:\n", 65 | " keyboard.release(\"left arrow\")\n", 66 | " keyboard.press(\"right arrow\")\n", 67 | " cv2.putText(frame,\"GAS\",(40,130),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255, 0), 3)\n", 68 | " elif ratio<0.2:\n", 69 | " keyboard.release(\"right arrow\")\n", 70 | " keyboard.press(\"left arrow\")\n", 71 | " cv2.putText(frame,\"BRAKE\",(40,130),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0, 255), 3)\n", 72 | " else:\n", 73 | " keyboard.release(\"left arrow\")\n", 74 | " keyboard.release(\"right arrow\")\n", 75 | " cv2.putText(frame,\"NEUTRAL\",(40,130),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255, 255), 3)\n", 76 | " else:\n", 77 | " keyboard.release(\"left arrow\")\n", 78 | " keyboard.release(\"right arrow\")" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "# Main Code" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 4, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "# Instructions:- Open Hill Climb Racing App before running this program.\n", 95 | "# Set the focus to the HCR app by opening the window of the app or clicking on it after executing the code.\n", 96 | "\n", 97 | "try:\n", 98 | " \n", 99 | " \n", 100 | " #Getting Video Input from Camera\n", 101 | " capture = cv2.VideoCapture(0)\n", 102 | " fw = capture.get(cv2.CAP_PROP_FRAME_WIDTH)\n", 103 | " fh = capture.get(cv2.CAP_PROP_FRAME_HEIGHT)\n", 104 | " \n", 105 | " \n", 106 | "\n", 107 | "# Detecting Fingers\n", 108 | " with mediapipe.solutions.hands.Hands(static_image_mode=False, min_detection_confidence=0.7, min_tracking_confidence=0.7, max_num_hands=1) as hands:\n", 109 | " while capture.isOpened():\n", 110 | " ret, frame = capture.read()\n", 111 | " if ret == False:\n", 112 | " continue\n", 113 | " \n", 114 | " frame = cv2.flip(frame, 1)\n", 115 | " results = hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))\n", 116 | " \n", 117 | " # Collecting coordinates of 6 hand landmarks\n", 118 | " if results.multi_hand_landmarks != None:\n", 119 | " thumb=results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.THUMB_TIP]\n", 120 | " index = results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.INDEX_FINGER_TIP]\n", 121 | " middle = results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.MIDDLE_FINGER_TIP]\n", 122 | " ring= results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.RING_FINGER_TIP]\n", 123 | " little=results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.PINKY_TIP]\n", 124 | " wri=results.multi_hand_landmarks[0].landmark[mediapipe.solutions.hands.HandLandmark.WRIST]\n", 125 | "\n", 126 | " \n", 127 | " a=[thumb,index,middle,ring,little]\n", 128 | " x0=0\n", 129 | " y0=0\n", 130 | " \n", 131 | " # Calculating the centroid of 5 finger's tips\n", 132 | " for i in a:\n", 133 | " x0+=i.x\n", 134 | " y0+=i.y\n", 135 | " c=(x0/5,y0/5)\n", 136 | " centroid = mediapipe.solutions.drawing_utils._normalized_to_pixel_coordinates(c[0],c[1],fw,fh)\n", 137 | " if centroid is not None:\n", 138 | " frame=cv2.circle(frame, centroid, 5, (0, 255, 0), -1)\n", 139 | " cv2.putText(frame,str(centroid),(centroid[0]+10,centroid[1]+10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0, 0), 2)\n", 140 | " \n", 141 | " \n", 142 | " # Calculating the ratio(r/s) of distance between the centroid, avg of 5 fingers (r) and the centroid,wrist (s)\n", 143 | " wrist=mediapipe.solutions.drawing_utils._normalized_to_pixel_coordinates(wri.x,wri.y,fw,fh)\n", 144 | " if wrist is not None and centroid is not None and all(a):\n", 145 | " frame=cv2.circle(frame, wrist, 5, (0, 0, 255), -1)\n", 146 | " cv2.putText(frame,str(wrist),(wrist[0]+10,wrist[1]+10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0, 0), 2)\n", 147 | " dis=[]\n", 148 | " for i in a:\n", 149 | " v=mediapipe.solutions.drawing_utils._normalized_to_pixel_coordinates(i.x,i.y,fw,fh)\n", 150 | " if v is not None:\n", 151 | " dis.append(math.dist(v,centroid))\n", 152 | " if len(dis)==5:\n", 153 | " r=sum(dis)/5\n", 154 | " s=math.dist(centroid,wrist)\n", 155 | " cv2.putText(frame,\"Ratio:- \"+str(round(r/s,2)),(20, 70),cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0, 0), 2)\n", 156 | " \n", 157 | " #Clicking keyboard buttons\n", 158 | " keybd(r/s,frame)\n", 159 | " \n", 160 | " frame=show(thumb,frame)\n", 161 | " frame=show(index,frame)\n", 162 | " frame=show(middle,frame)\n", 163 | " frame=show(ring,frame)\n", 164 | " frame=show(little,frame)\n", 165 | " \n", 166 | " \n", 167 | " cv2.imshow('HCR Game Controller', frame)\n", 168 | " \n", 169 | " if cv2.waitKey(1) == 27: #Escape(ESC.) key\n", 170 | " break\n", 171 | " \n", 172 | " cv2.destroyAllWindows()\n", 173 | " capture.release()\n", 174 | "\n", 175 | "except:\n", 176 | " \n", 177 | " cv2.destroyAllWindows()\n", 178 | " capture.release()\n", 179 | " traceback.print_exc()" 180 | ] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 3.9.12 ('base')", 186 | "language": "python", 187 | "name": "python3" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 3 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython3", 199 | "version": "3.9.12" 200 | }, 201 | "orig_nbformat": 4, 202 | "vscode": { 203 | "interpreter": { 204 | "hash": "f2b718e513c62edc6ede9b03ad3c84aa738011d553e5bf64ca2c77beb104330f" 205 | } 206 | } 207 | }, 208 | "nbformat": 4, 209 | "nbformat_minor": 2 210 | } 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Hill Climb Racing Game Controller 3 | 4 |   5 | 6 | 7 |
8 | 9 |

Hill Climb Racing Game Controller

10 | 11 |

12 | Github Top Language 13 | 14 | Github Language Count 15 | 16 | Repository Size 17 | 18 | 19 | 20 | 21 | 22 | 23 |

24 | 25 | 26 | 27 |

28 | About   |   29 | How To Use   |   30 | Features   |   31 | Technologies   |   32 | Requirements   |   33 | Starting   |   34 | Made By   |   35 | Author 36 |

37 | 38 |
39 | 40 | ## :dart: About ## 41 | 42 | I have made a Hill Climb Racing Game Controller. The game runs as we move our hand in front of the Primary Camera. It uses Machine Learning to infer 21 3-Dimensional Landmarks of our hand using Mediapipe's State-of-the-art techniques. 43 | 44 | ## :dart: How To Use ## 45 | 46 | ### Basic Interface of Window:- 47 | ![Basic Interface of Window](https://github.com/UtkarshPrajapati/Game-Controller-Using-Hand-Gestures/blob/07cf1f7f5c7cf9705b6a3bda8c47d21e1fbd2c65/media/Basic%20Interface.png) 48 | 49 | 50 | ### Playing the Game:- 51 | https://user-images.githubusercontent.com/87516213/197361717-c5ada7e9-fa10-49a9-a13f-fb07b41ab75a.mp4 52 | 53 | 54 | ## :sparkles: Features ## 55 | 56 | :heavy_check_mark: Uses Open Computer Vision (OpenCV)\ 57 | :heavy_check_mark: Tracks hands and Finger Tips Efficiently\ 58 | :heavy_check_mark: Moves the vehicle according to hand gestures. \ 59 | :heavy_check_mark: Can operate Hill Climb Racing game without touching the laptop. 60 | 61 | ## :rocket: Technologies ## 62 | 63 | The following tools were used in this project: 64 | 65 | - [Numpy](https://numpy.org/) 66 | - [Pandas](https://pandas.pydata.org/) 67 | - [Matplotlib](https://matplotlib.org/) 68 | - [OpenCV](https://opencv.org/) 69 | 70 | ## :white_check_mark: Requirements ## 71 | 72 | Before starting, you need to have [Git](https://git-scm.com) & basic Deep Learning libraries installed. 73 | You should also install Hill Climb Racing by going to This Link 74 | 75 | ## :checkered_flag: Starting ## 76 | 77 | ```bash 78 | # Clone this project 79 | $ git clone https://github.com/UtkarshPrajapati/Game-Controller-Using-Hand-Gestures.git 80 | 81 | # Access 82 | $ cd Game-Controller-Using-Hand-Gestures 83 | 84 | # Install dependencies 85 | $ pip install -r requirements.txt 86 | 87 | # Run the project 88 | $ jupyter nbconvert --to notebook --execute "Game Controller.ipynb" 89 | 90 | ``` 91 | 92 | ## :memo: Made By ## 93 | 94 | Made with :heart: by Utkarsh Prajapati 95 | 96 |   97 | 98 | Back to top 99 | -------------------------------------------------------------------------------- /media/Basic Interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UtkarshPrajapati/Game-Controller-Using-Hand-Gestures/24567663e4f455cc4a5afd2642dd5723a88c4486/media/Basic Interface.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mediapipe 2 | opencv-python 3 | keyboard --------------------------------------------------------------------------------