Skip to content

Instantly share code, notes, and snippets.

@smeschke
Created February 26, 2017 19:21
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save smeschke/d44f4afc7ef5392dbe13c98b0d6bad1b to your computer and use it in GitHub Desktop.
Save smeschke/d44f4afc7ef5392dbe13c98b0d6bad1b to your computer and use it in GitHub Desktop.
import numpy as np
import cv2
import math
#capture webcam video
cap = cv2.VideoCapture(0)
width, height = 1920,1080
cap.set(3,width)
cap.set(4,height)
#create a method that can seperate the foreground from the background
fgbg = cv2.createBackgroundSubtractorMOG2()
#setup outfile for writing video
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('/home/sm/Desktop/keyboard.avi',fourcc, 20.0, (1280,960))
#define alphabet position
position = 0
#define hand position
hand_position = 0,0
hand_on_keyboard = False
letter_selected = False
#define font and text color
font = cv2.FONT_HERSHEY_SIMPLEX
color = (13,32,210)
#create a list for the word
word = ''
#create a letter buffer
letter_buffer = []
#define frame_num
frame_num = 0
#function that determines distance between two points
def distance(p0,p1):
return math.sqrt((p1[1]-p0[1])**2+(p1[0]-p0[0])**2)
#main loop
while True:
#read a frame from the webcam
_, frame = cap.read()
frame = cv2.flip(frame, 1)
frame_num += 1
#create a composite image that includes the webcam
composite = frame.copy()
#add the letters
#make a list of letter positions
letter_positions = []
for letter in range(150):
x_position = position + letter*120
y_position = 150
xy = x_position, y_position
cv2.putText(composite,chr(40+letter),xy, font, 2,color,3)
letter_positions.append((chr(40+letter),xy))
#if there is a letter selected, make that letter green
if letter_selected:
cv2.putText(composite, closest_letter, close_letter_position, font, 2, (255,0,0), 3)
#add a line to show where the keyboard starts
cv2.line(composite, (composite.shape[1],200), (0,200), color, 2)
#find the background
#look only at the keyboard part of the frame
look = frame[50:200, 0:frame.shape[1]]
fgmask = fgbg.apply(look)
#define apparent_motion as false
apparent_motion = False
letter_selected = False
previous_position = hand_position
#find the largest contour in the fgmask image
b,a,c = cv2.findContours(fgmask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#draw a circle aroudn the contour
for cnt in a:
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
area = cv2.contourArea(cnt)
if area > 1000 and area < 2000:
radius = int(radius)
cv2.circle(composite,center,radius,(0,120,255), thickness=5)
cv2.line(composite, (center[0]-50,center[1]), (center[0]+50,center[1]), (0,0,0),3)
cv2.line(composite, (center[0],center[1]-50), (center[0],center[1]+50), (0,0,0),3)
letter_selected = True
#find the closest letter
closest_letter = 'a'
min_distance = 100000
for letter_tuple in letter_positions:
letter_position = letter_tuple[1]
if distance(letter_position, center) < min_distance:
closest_letter = letter_tuple[0]
min_distance = distance(letter_position, center)
close_letter_position = letter_position
letter_buffer.append(closest_letter)
#determine if there is apparent motion (swiping)
if area > 2000:
hand_position = center
if previous_position != (0,0):
apparent_motion = True
if previous_position[0] > hand_position[0]:
dirrection = 'Left'
position -=100
if previous_position[0] < hand_position[0]:
dirrection = 'Right'
position += 100
previous_position = hand_position
#if a letter has been selected for 10 frames, write the letter and clear the buffer
for letter in letter_buffer[20:]:
if letter == closest_letter:
word += letter
letter_buffer = []
#write the word
cv2.putText(composite, word, (50,50), font, 2, (0,0,0), 4)
#show the various images and wait
#cv2.imshow('fgmask',fgmask)
#cv2.imshow('frame', frame)
cv2.imshow('composite', composite)
out.write(composite)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment