From 9d381c0b141d768a025fe66c8fa5cb8d68306f86 Mon Sep 17 00:00:00 2001 From: Sandeep Ahirwar Date: Thu, 6 Oct 2022 12:02:57 +0530 Subject: [PATCH] Gesture Volume Control Using OpenCV python library to control the volume of windows using fingers --- Gesture-Volume-Control/VolumeHandControl.py | 74 ++++++++++++++++++ Gesture-Volume-Control/handTrackingModule.py | 80 ++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 Gesture-Volume-Control/VolumeHandControl.py create mode 100644 Gesture-Volume-Control/handTrackingModule.py diff --git a/Gesture-Volume-Control/VolumeHandControl.py b/Gesture-Volume-Control/VolumeHandControl.py new file mode 100644 index 0000000..2630872 --- /dev/null +++ b/Gesture-Volume-Control/VolumeHandControl.py @@ -0,0 +1,74 @@ +import cv2 +import time +import numpy as np +import handTrackingModule as htm +import math + +from ctypes import cast, POINTER +from comtypes import CLSCTX_ALL +from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume + +################################ +wCam, hCam = 640, 480 +################################ + +cap = cv2.VideoCapture(0) +cap.set(3, wCam) +cap.set(4, hCam) +pTime = 0 + +detector = htm.handDetector(detectionCon=0.7) + +devices = AudioUtilities.GetSpeakers() +interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None) +volume = cast(interface, POINTER(IAudioEndpointVolume)) +# volume.GetMute() +# volume.GetMasterVolumeLevel() +volRange = volume.GetVolumeRange() +minVol = volRange[0] +maxVol = volRange[1] +vol = 0 +volBar = 400 +volPer = 0 + +while True: + success, img = cap.read() + img = detector.findHands(img) + lmList = detector.findPosition(img, draw=False) + if len(lmList) != 0: + # print(lmList[4], lmList[8]) + x1, y1 = lmList[4][1], lmList[4][2] + x2, y2 = lmList[8][1], lmList[8][2] + + cv2.circle(img, (x1, y1), 15, (0, 255, 255), cv2.FILLED) + cv2.circle(img, (x2, y2), 15, (0, 255, 255), cv2.FILLED) + cv2.line(img, (x1, y1), (x2, y2), (100, 255, 255), 3) + cx, cy = (x1 + x2) // 2, (y1 + y2) // 2 + cv2.circle(img, (cx, cy), 10, (0, 255, 255), cv2.FILLED) + + length = math.hypot(x2 - x1, y2 - y1) + # print(length) + + #Hand range 50 - 260 + #volume range -63.5 to 0 + vol = np.interp(length, [50,260], [minVol, maxVol]) + volBar = np.interp(length, [50,270], [400, 150]) + volPer = np.interp(length, [50, 270], [0,100]) + print(vol) + volume.SetMasterVolumeLevel(vol, None) + + if length < 50: + cv2.circle(img, (cx, cy), 10, (0, 255, 0), cv2.FILLED) + + cv2.rectangle(img, (50,150), (85,400), (0,255,0), 3) + cv2.rectangle(img, (50,int(volBar)), (85,400), (0,255,0), cv2.FILLED) + cv2.putText(img, f'FPS: {int(volPer)} %', (40, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (255,0 , 0), 2) + + + cTime = time.time() + fps = 1 / (cTime - pTime) + pTime = cTime + + cv2.putText(img, f'FPS: {int(fps)}', (30, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2) + cv2.imshow("Img", img) + cv2.waitKey(1) diff --git a/Gesture-Volume-Control/handTrackingModule.py b/Gesture-Volume-Control/handTrackingModule.py new file mode 100644 index 0000000..a5176c9 --- /dev/null +++ b/Gesture-Volume-Control/handTrackingModule.py @@ -0,0 +1,80 @@ +# converting handTracking.py to a module so that we can use in any project + +import cv2 as cv +import mediapipe as mp +import time + + +class handDetector(): + def __init__(self, mode=False, maxHands=2, modelComplexity=1, detectionCon=0.5, trackCon=0.5): # mpHands variable + self.mode = mode # create an object with own variable, self.mode is variable, + self.maxHands = maxHands + self.modelComplexity = modelComplexity + self.detectionCon = detectionCon + self.trackCon = trackCon + + self.mpHands = mp.solutions.hands + self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.modelComplexity, + self.detectionCon, self.trackCon) # using default values #only uses rgb img + self.mpDraw = mp.solutions.drawing_utils + + def findHands(self, img, draw=True): + # converting img to rgb + imgRGB = cv.cvtColor(img, cv.COLOR_BGR2RGB) + self.results = self.hands.process(imgRGB) + # print(results.multi_hand_landmarks) #print none if hand is not in video else prints coordinates of hand + + if self.results.multi_hand_landmarks: + for handLms in self.results.multi_hand_landmarks: + if draw: + self.mpDraw.draw_landmarks(img, handLms, + self.mpHands.HAND_CONNECTIONS) # draws all 21 points in hands + # mpHands.HAND_CONNECTIONS --> this connects the dots + return img + + def findPosition(self, img, handNo=0, draw=True): + lmList = [] + + # extracting id and landmark(x,y,z) coordinate + if self.results.multi_hand_landmarks: + myHand = self.results.multi_hand_landmarks[handNo] # getting which hand + for id, lm in enumerate(myHand.landmark): + # print(id, lm) #values of x,y,z are in float + # we will convert them to pixels + h, w, c = img.shape + cx, cy = int(lm.x * w), int(lm.y * h) + # print(cx,cy) #now we don't know which value is for which point so we have to use id + # print(id, cx, cy) + lmList.append([id, cx, cy]) + if draw: + cv.circle(img, (cx, cy), 7, (255, 0, 0), cv.FILLED) + + return lmList + + +def main(): + #dummy code to use in any other project + pTime = 0 # previous time + cTime = 0 # current rime + cap = cv.VideoCapture(0) + detector = handDetector() # calling the class + while True: + success, img = cap.read() + img = detector.findHands(img) + lmList = detector.findPosition(img) + if len(lmList) != 0: + print(lmList[4]) + + cTime = time.time() + fps = 1 / (cTime - pTime) + pTime = cTime + + # display fps on screen + cv.putText(img, str(int(fps)), (10, 70), cv.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3) + + cv.imshow('Image', img) + cv.waitKey(1) + + +if __name__ == "__main__": + main()