-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathvirtual_mouse.py
More file actions
117 lines (91 loc) · 4.43 KB
/
virtual_mouse.py
File metadata and controls
117 lines (91 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import cv2
import numpy as np
from pynput.mouse import Button, Controller
import wx
mouse = Controller()
app = wx.App(False)
(sx, sy) = wx.GetDisplaySize()
(camx, camy) = (320, 240)
cap = cv2.VideoCapture(0)
cap.set(3, camx)
cap.set(4, camy)
# range for HSV (green color)
lowerBound = np.array([33, 70, 30])
upperBound = np.array([102, 255, 255])
# Kerenel
kernelOpen = np.ones((5, 5))
kernelClose = np.ones((20, 20))
mLocOld = np.array([0, 0])
mouseLoc = np.array([0, 0])
DampingFactor = 2 # Damping factor must be greater than 1
pinchFlag = 0
openx, openy, openw, openh = (0, 0, 0, 0)
while True:
ret, img = cap.read()
img = cv2.resize(img, (340, 220))
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(imgHSV, lowerBound, upperBound)
# using morphology to erase noise as maximum as possible
maskOpen = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernelOpen)
maskClose = cv2.morphologyEx(maskOpen, cv2.MORPH_CLOSE, kernelClose)
maskFinal = maskClose
conts, h_ = cv2.findContours(maskFinal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Once 2 objects are detected the center of there distance will be the reference on controlling the mouse
if (len(conts) == 2):
# if the button is pressed we need to release it first
if (pinchFlag == 1):
pinchFlag = 0
mouse.release(Button.left)
# drawing the rectagle around both objects
x1, y1, w1, h1 = cv2.boundingRect(conts[0])
x2, y2, w2, h2 = cv2.boundingRect(conts[1])
cv2.rectangle(img, (x1, y1), (x1 + w1, y1 + h1), (255, 0, 0), 2)
cv2.rectangle(img, (x2, y2), (x2 + w2, y2 + h2), (255, 0, 0), 2)
# the line between the center of the previous rectangles
cx1 = int(x1 + w1 / 2)
cy1 = int(y1 + h1 / 2)
cx2 = int(x2 + w2 / 2)
cy2 = int(y2 + h2 / 2)
cv2.line(img, (cx1, cy1), (cx2, cy2), (255, 0, 0), 2)
# the center of that line (reference point)
cx = int((cx1 + cx2) / 2)
cy = int((cy1 + cy2) / 2)
cv2.circle(img, (cx, cy), 2, (0, 0, 255), 2)
# adding the damping factor so that the movement of the mouse is smoother
mouseLoc = mLocOld + ((cx, cy) - mLocOld) / DampingFactor
mouse.position = (sx - int((mouseLoc[0] * sx) / camx), int((mouseLoc[1] * sy) / camy))
while mouse.position != (sx - int((mouseLoc[0] * sx) / camx), int((mouseLoc[1] * sy) / camy)):
pass
# setting the old location to the current mouse location
mLocOld = mouseLoc
# these variables were added so that we get the outer rectangle that combines both objects
openx, openy, openw, openh = cv2.boundingRect(
np.array([[[x1, y1], [x1 + w1, y1 + h1], [x2, y2], [x2 + w2, y2 + h2]]]))
# when there's only when object detected it will act as a left click mouse
elif (len(conts) == 1):
x, y, w, h = cv2.boundingRect(conts[0])
# we check first and we allow the press fct if it's not pressed yet
# we did that to avoid the continues pressing
if (pinchFlag == 0):
if (abs((w * h - openw * openh) * 100 / (
w * h)) < 30): # the difference between th combined rectangle for both objct and the
pinchFlag = 1 # the outer rectangle is not more than 30%
mouse.press(Button.left)
openx, openy, openw, openh = (0, 0, 0, 0)
# this else was added so that if there's only one object detected it will not act as a mouse
else:
# getting rectangle coordinates and drawing it
x, y, w, h = cv2.boundingRect(conts[0])
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
# getting the center of the circle that will be inside the outer rectangle
cx = int(x + w / 2)
cy = int(y + h / 2)
cv2.circle(img, (cx, cy), int((w + h) / 4), (0, 0, 255), 2) # drawing that circle
mouseLoc = mLocOld + ((cx, cy) - mLocOld) / DampingFactor
mouse.position = (sx - int((mouseLoc[0] * sx) / camx), int((mouseLoc[1] * sy) / camy))
while mouse.position != (sx - int((mouseLoc[0] * sx) / camx), int((mouseLoc[1] * sy) / camy)):
pass
mLocOld = mouseLoc
# showing the results
cv2.imshow("Virtual mouse", img)
cv2.waitKey(5)