forked from Gogul09/gesture-recognition
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
194 additions
and
121 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
# organize imports | ||
import cv2 | ||
import imutils | ||
import numpy as np | ||
from sklearn.metrics import pairwise | ||
|
||
# global variables | ||
bg = None | ||
|
||
#------------------------------------------------------------------------------- | ||
# Function - To find the running average over the background | ||
#------------------------------------------------------------------------------- | ||
def run_avg(image, accumWeight): | ||
global bg | ||
# initialize the background | ||
if bg is None: | ||
bg = image.copy().astype("float") | ||
return | ||
|
||
# compute weighted average, accumulate it and update the background | ||
cv2.accumulateWeighted(image, bg, accumWeight) | ||
|
||
#------------------------------------------------------------------------------- | ||
# Function - To segment the region of hand in the image | ||
#------------------------------------------------------------------------------- | ||
def segment(image, threshold=25): | ||
global bg | ||
# find the absolute difference between background and current frame | ||
diff = cv2.absdiff(bg.astype("uint8"), image) | ||
|
||
# threshold the diff image so that we get the foreground | ||
thresholded = cv2.threshold(diff, threshold, 255, cv2.THRESH_BINARY)[1] | ||
|
||
# get the contours in the thresholded image | ||
(_, cnts, _) = cv2.findContours(thresholded.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | ||
|
||
# return None, if no contours detected | ||
if len(cnts) == 0: | ||
return | ||
else: | ||
# based on contour area, get the maximum contour which is the hand | ||
segmented = max(cnts, key=cv2.contourArea) | ||
return (thresholded, segmented) | ||
|
||
#------------------------------------------------------------------------------- | ||
# Function - To count the number of fingers in the segmented hand region | ||
#------------------------------------------------------------------------------- | ||
def count(thresholded, segmented): | ||
# find the convex hull of the segmented hand region | ||
chull = cv2.convexHull(segmented) | ||
|
||
# find the most extreme points in the convex hull | ||
extreme_top = tuple(chull[chull[:, :, 1].argmin()][0]) | ||
extreme_bottom = tuple(chull[chull[:, :, 1].argmax()][0]) | ||
extreme_left = tuple(chull[chull[:, :, 0].argmin()][0]) | ||
extreme_right = tuple(chull[chull[:, :, 0].argmax()][0]) | ||
|
||
# find the center of the palm | ||
cX = (extreme_left[0] + extreme_right[0]) / 2 | ||
cY = (extreme_top[1] + extreme_bottom[1]) / 2 | ||
|
||
# find the maximum euclidean distance between the center of the palm | ||
# and the most extreme points of the convex hull | ||
distance = pairwise.euclidean_distances([(cX, cY)], Y=[extreme_left, extreme_right, extreme_top, extreme_bottom])[0] | ||
maximum_distance = distance[distance.argmax()] | ||
|
||
# calculate the radius of the circle with 80% of the max euclidean distance obtained | ||
radius = int(0.8 * maximum_distance) | ||
|
||
# find the circumference of the circle | ||
circumference = (2 * np.pi * radius) | ||
|
||
# take out the circular region of interest which has | ||
# the palm and the fingers | ||
circular_roi = np.zeros(thresholded.shape[:2], dtype="uint8") | ||
|
||
# draw the circular ROI | ||
cv2.circle(circular_roi, (cX, cY), radius, 255, 1) | ||
|
||
# take bit-wise AND between thresholded hand using the circular ROI as the mask | ||
# which gives the cuts obtained using mask on the thresholded hand image | ||
circular_roi = cv2.bitwise_and(thresholded, thresholded, mask=circular_roi) | ||
|
||
# compute the contours in the circular ROI | ||
(_, cnts, _) = cv2.findContours(circular_roi.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) | ||
|
||
# initalize the finger count | ||
count = 0 | ||
|
||
# loop through the contours found | ||
for c in cnts: | ||
# compute the bounding box of the contour | ||
(x, y, w, h) = cv2.boundingRect(c) | ||
|
||
# increment the count of fingers only if - | ||
# 1. The contour region is not the wrist (bottom area) | ||
# 2. The number of points along the contour does not exceed | ||
# 25% of the circumference of the circular ROI | ||
if ((cY + (cY * 0.25)) > (y + h)) and ((circumference * 0.25) > c.shape[0]): | ||
count += 1 | ||
|
||
return count | ||
|
||
#------------------------------------------------------------------------------- | ||
# Main function | ||
#------------------------------------------------------------------------------- | ||
if __name__ == "__main__": | ||
# initialize accumulated weight | ||
accumWeight = 0.5 | ||
|
||
# get the reference to the webcam | ||
camera = cv2.VideoCapture(0) | ||
|
||
# region of interest (ROI) coordinates | ||
top, right, bottom, left = 10, 350, 225, 590 | ||
|
||
# initialize num of frames | ||
num_frames = 0 | ||
|
||
# calibration indicator | ||
calibrated = False | ||
|
||
# keep looping, until interrupted | ||
while(True): | ||
# get the current frame | ||
(grabbed, frame) = camera.read() | ||
|
||
# resize the frame | ||
frame = imutils.resize(frame, width=700) | ||
|
||
# flip the frame so that it is not the mirror view | ||
frame = cv2.flip(frame, 1) | ||
|
||
# clone the frame | ||
clone = frame.copy() | ||
|
||
# get the height and width of the frame | ||
(height, width) = frame.shape[:2] | ||
|
||
# get the ROI | ||
roi = frame[top:bottom, right:left] | ||
|
||
# convert the roi to grayscale and blur it | ||
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) | ||
gray = cv2.GaussianBlur(gray, (7, 7), 0) | ||
|
||
# to get the background, keep looking till a threshold is reached | ||
# so that our weighted average model gets calibrated | ||
if num_frames < 30: | ||
run_avg(gray, accumWeight) | ||
if num_frames == 1: | ||
print "[STATUS] please wait! calibrating..." | ||
elif num_frames == 29: | ||
print "[STATUS] calibration successfull..." | ||
else: | ||
# segment the hand region | ||
hand = segment(gray) | ||
|
||
# check whether hand region is segmented | ||
if hand is not None: | ||
# if yes, unpack the thresholded image and | ||
# segmented region | ||
(thresholded, segmented) = hand | ||
|
||
# draw the segmented region and display the frame | ||
cv2.drawContours(clone, [segmented + (right, top)], -1, (0, 0, 255)) | ||
|
||
# count the number of fingers | ||
fingers = count(thresholded, segmented) | ||
|
||
cv2.putText(clone, str(fingers), (70, 45), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2) | ||
|
||
# show the thresholded image | ||
cv2.imshow("Thesholded", thresholded) | ||
|
||
# draw the segmented hand | ||
cv2.rectangle(clone, (left, top), (right, bottom), (0,255,0), 2) | ||
|
||
# increment the number of frames | ||
num_frames += 1 | ||
|
||
# display the frame with segmented hand | ||
cv2.imshow("Video Feed", clone) | ||
|
||
# observe the keypress by the user | ||
keypress = cv2.waitKey(1) & 0xFF | ||
|
||
# if the user pressed "q", then stop looping | ||
if keypress == ord("q"): | ||
break | ||
|
||
# free up memory | ||
camera.release() | ||
cv2.destroyAllWindows() |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.