Last active
March 1, 2023 09:36
-
-
Save pgaijin66/f0f65f2e4fc078635496ed4cf735d682 to your computer and use it in GitHub Desktop.
Draw on screen using OpenCV and Handgesture.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# DO NOT REMOVE THESE TWO LINES. | |
# Disabling hardward transform flag for OpenCV package. This needs to be done before importing OpenCV package. | |
# This will stop slow startup and initialization behaviour effectively making webcam initialize faster. | |
# See more: https://github.com/opencv/opencv/issues/17687 | |
import os | |
os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" | |
# Now import openCV package | |
import cv2 | |
import mediapipe as mp | |
import numpy as np | |
import time | |
from cvzone.HandTrackingModule import HandDetector | |
from threading import Thread | |
class WebcamStream: | |
""" WebcamStream captures frames from the web cam.""" | |
def __init__(self, stream_id=0): | |
self.stream_id = stream_id # default is 0 for main camera | |
self.vcap = cv2.VideoCapture(self.stream_id) | |
if self.vcap.isOpened() is False : | |
print("[Exiting]: Error accessing webcam stream.") | |
exit(0) | |
fps_input_stream = int(self.vcap.get(5)) # hardware fps | |
print("FPS of input stream: {}".format(fps_input_stream)) | |
# reading a single frame from vcap stream for initializing | |
self.grabbed , self.frame = self.vcap.read() | |
if self.grabbed is False : | |
print('[Exiting] No more frames to read') | |
exit(0) | |
# self.stopped is initialized to False | |
self.stopped = True | |
# thread instantiation | |
self.t = Thread(target=self.update, args=()) | |
self.t.daemon = True # daemon threads run in background | |
def start(self): | |
self.stopped = False | |
self.t.start() | |
def update(self): | |
while True : | |
if self.stopped is True : | |
break | |
self.grabbed , self.frame = self.vcap.read() | |
if self.grabbed is False : | |
print('[Exiting] No more frames to read') | |
self.stopped = True | |
break | |
self.vcap.release() | |
def read(self): | |
return self.frame | |
def stop(self): | |
self.stopped = True | |
class HandGestureDetector: | |
""" HandGestureDetector detects hand and draws on the x and y co-ordinates of the index finger """ | |
def __init__(self, cap, hands, mpHands, detector, canvas): | |
self.mpHands = mpHands | |
self.hands = hands | |
self.cap = cap | |
self.detector = detector | |
self.canvas = canvas | |
self.canvas.fill(255) | |
self.canvas= cv2.flip(canvas, 1) | |
self.x = 0 | |
self.y = 0 | |
self.drawing = False | |
self.tool= None | |
self.thickness= 3 | |
self.input_size= (1200, 1080) | |
self.pTime = 0 | |
self.cTime = 0 | |
def run_detection(self): | |
num_frames_processed = 0 | |
start = time.time() | |
while True: | |
img = self.cap.read() | |
img_resized= cv2.resize(img, self.input_size) | |
hand, img = self.detector.findHands(img_resized) | |
img= cv2.flip(img, 1) | |
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
results = self.hands.process(imgRGB) | |
if results.multi_hand_landmarks: | |
for hand_landmarks in results.multi_hand_landmarks: | |
index_finger_tip = hand_landmarks.landmark[self.mpHands.HandLandmark.INDEX_FINGER_TIP] | |
cx, cy = int(index_finger_tip.x * self.canvas.shape[1]), int(index_finger_tip.y * self.canvas.shape[0]) | |
if hand: | |
handType = hand[0]['type'] | |
if handType == "Left": | |
self.drawing = False | |
cv2.circle(self.canvas, (cx, cy), 200, (0), cv2.FILLED) | |
elif handType == 'Right': | |
if self.drawing: | |
cv2.line(self.canvas, (self.x, self.y), (cx, cy), 0, thickness=10) | |
self.x = cx | |
self.y = cy | |
self.drawing = True | |
# Adding some readability to the code to see how much frame per second we are getting ( FPS ). In general mac have | |
# FPS of around 50 | |
self.cTime = time.time() | |
fps = 1/( self.cTime- self.pTime) | |
self.pTime = self.cTime | |
cv2.imshow("Canvas", self.canvas) | |
cv2.putText(img, f'FPS: {int(fps)}', (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,255), 3) | |
cv2.imshow("image", img) | |
# This will gratefully quit the program when you press "ESC" | |
if cv2.waitKey(5) & 0XFF == 27: | |
break | |
end = time.time() | |
self.cap.stop() # stop the webcam stream | |
def __del__(self): | |
cap.release() | |
cv2.destroyAllWindows() | |
if __name__ == "__main__": | |
# Moving out things that should not be inside the class constructor. | |
cap = WebcamStream(stream_id=0) # 0 id for main camera | |
cap.start() | |
# cap = cv2.VideoCapture(0) | |
# cap.set(cv2.CAP_PROP_FPS,40) | |
mpHands = mp.solutions.hands | |
hands = mpHands.Hands(static_image_mode=False, | |
max_num_hands=2, | |
min_detection_confidence=0.5, | |
min_tracking_confidence=0.5) | |
detector = HandDetector(detectionCon=0.8, maxHands=2) | |
canvas = np.zeros((1200, 1800, 3), np.uint8) | |
model = HandGestureDetector(cap, hands, mpHands, detector, canvas) | |
model.run_detection() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment