├── .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 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 | About | 29 | How To Use | 30 | Features | 31 | Technologies | 32 | Requirements | 33 | Starting | 34 | Made By | 35 | Author 36 |
37 | 38 |