In My Last OpenCV Tutorial I wrote a program to detect green objects and track them. in this post I am going to show you how we can extend that idea to do some more things like gesture recognition. We will apply that to create a virtual mouse.
I will be using that code as a base of this program and will work on top of it. So if you haven’t read the previous tutorial you can check it here
Libraries In Use
The external libraries that we will be using:
- openCV
- numpy
- wx
- pynput
Lets Take a Look Back At The Colour Detection Code
This was the color detection code. If you don’t know how its working check that post first
import cv2
import numpy as np
lowerBound=np.array([33,80,40])
upperBound=np.array([102,255,255])
cam= cv2.VideoCapture(0)
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))
font=cv2.cv.InitFont(cv2.cv.CV_FONT_HERSHEY_SIMPLEX,2,0.5,0,3,1)
while True:
ret, img=cam.read()
img=cv2.resize(img,(340,220))
#convert BGR to HSV
imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
# create the Mask
mask=cv2.inRange(imgHSV,lowerBound,upperBound)
#morphology
maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose)
maskFinal=maskClose
conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img,conts,-1,(255,0,0),3)
for i in range(len(conts)):
x,y,w,h=cv2.boundingRect(conts[i])
cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255), 2)
cv2.cv.PutText(cv2.cv.fromarray(img), str(i+1),(x,y+h),font,(0,255,255))
cv2.imshow("maskClose",maskClose)
cv2.imshow("maskOpen",maskOpen)
cv2.imshow("mask",mask)
cv2.imshow("cam",img)
cv2.waitKey(10)
Lets Create a Virtual Mouse with Gesture Recognition
Okay lets start modifying the above code for gesture recognition
Import libraries
import cv2
import numpy as np
from pynput.mouse import Button, Controller
import wx
These are the libraries that we will be using. pynput to control mouse movements and clicking and wx to get the display resolution of the monitor
Global variables Setup
now that we already have all the libraries lets setup all the variables and objects
mouse=Controller()
app=wx.App(False)
(sx,sy)=wx.GetDisplaySize()
(camx,camy)=(320,240)
we will need these variables and objects, mouse object is for mouse movements and to get the screen resolution we need an wx app then we can use the wx.GetDisplaySize()
to get the screen resolution.
lastly we are setting some variables camx, camy to set the captured image resolution. we will be using it later in image resize function
Lets Start The Main Loop
while True:
ret, img=cam.read()
img=cv2.resize(img,(camx,camy))
#convert BGR to HSV
imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
# create the Mask
mask=cv2.inRange(imgHSV,lowerBound,upperBound)
#morphology
maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose)
maskFinal=maskClose
conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
The above code it the portion of the loop we wrote in our color detection program. We don’t need to modify the loop till this point. We will be adding our code after this.
while True:
:
:
if(len(conts)==2):
# logic for the open gesture, move mouse without click
....
....
elif(len(conts)==1):
# logic for close gesture
....
....
cv2.imshow("cam",img)
cv2.waitKey(5)
Above is the structure of our extended code. after getting the contours in conts variable we will check if there are contour of 2 object present in the frame we will move the mouse but we wont perform any click operation
similarly if there are only one object contour present we will move the mouse as well as we will perform click operations
Implement The Open Gesture Operation

To Implement the open gesture we need to do some calculation to find some coordinates. See the below image to get the idea
We have to first calculate the centre of both detected green object which we can easily do by taking the average of the bounding boxes maximum and minimum points. now we got 2 coordinate from the centre of the 2 objects we will find the avarage of that and we will get the red point shown in the image.. okay lets do this
while True:
:
:
if(len(conts)==2):
# logic for the open gesture, move mouse without click
x1,y1,w1,h1=cv2.boundingRect(conts[0])
x2,y2,w2,h2=cv2.boundingRect(conts[1])
# drawing rectangle over the objects
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)
#centre coordinate of first object
cx1=x1+w1/2
cy1=y1+h1/2
# centre coordinate of the 2nd object
cx2=x2+w2/2
cy2=y2+h2/2
# centre coordinate of the line connection both points
cx=(cx1+cx2)/2
cy=(cy1+cy2)/2
# Drawing the line
cv2.line(img, (cx1,cy1),(cx2,cy2),(255,0,0),2)
# Drawing the point (red dot)
cv2.circle(img, (cx,cy),2,(0,0,255),2)
So the above code is the result of what I just explained earlier and with this we have the coordinate to position our mouse curser
Now we need to position our mouse curser according to the calculated coordinate okay lets do that
while True:
:
:
if(len(conts)==2):
:
:
mouse.release(Button.left)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
In the above code first we are doing a mouse release to ensure the mouse left button is not pressed. Then we are converting the detected coordinate from camera resolution to the actual screen resolution. After that we set the location as the mouse.position. but to move the mouse it will take time for the curser so we have to wait till the curser reaches that point. So we started a loop and we are not doing anything there we are just waiting will the current mouse location is same as assigned mouse location.That is for the open gesture
Implement Close Gesture/ Clicking
Now lets implement the close gesture where we will be clicking the object and dragging it
while True:
:
:
if(len(conts)==2):
:
:
elif(len(conts)==1):
x,y,w,h=cv2.boundingRect(conts[0])
#drawing the rectangle
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
cx=x+w/2
cy=y+h/2
cv2.circle(img,(cx,cy),(w+h)/4,(0,0,255),2)
mouse.press(Button.left)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
The above code is similar to the open gesture, but the difference is we only have one object here so we only need to calculate the centre of it. And that will be where we will position our mouse pointer. also we are performing a mouse press operation instead of mouse release operation. rest of the part is same as earlier one.
This is the result :

Some Fine Tuning
We are almost done. The code is almost perfect except. we wont be able to drag anything. because in close gesture we are continuously performing mouse.press operation which will result in continuous multiple clicks while dragging.
To solve this problem what we can do is, we will be putting a flag called “pinchFlag” and we will set that 1 once we perform a click operation. and we wont perform mouse press operation anymore until the flag is 0 again
so the code will look like this
pinchFlag=0# setting initial value
while True:
:
:
if(len(conts)==2):
:
:
if(pinchFlag==1): #perform only if pinch is on
pinchFlag=0 # setting pinch flag off
mouse.release(Button.left)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
elif(len(conts)==1):
:
:
if(pinchFlag==0): #perform only if pinch is off
pinchFlag=1 # setting pinch flag on
mouse.press(Button.left)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
Final Code For Virtual Mouse with Gesture Recognition
That pretty much it. I recorded a video tutorial for this which will fix some more common problems you can check that out below
but for now the final code looks like this
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)
lowerBound=np.array([33,80,40])
upperBound=np.array([102,255,255])
cam= cv2.VideoCapture(0)
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))
pinchFlag=0
while True:
ret, img=cam.read()
img=cv2.resize(img,(340,220))
#convert BGR to HSV
imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
# create the Mask
mask=cv2.inRange(imgHSV,lowerBound,upperBound)
#morphology
maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose)
maskFinal=maskClose
conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
if(len(conts)==2):
if(pinchFlag==1):
pinchFlag=0
mouse.release(Button.left)
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)
cx1=x1+w1/2
cy1=y1+h1/2
cx2=x2+w2/2
cy2=y2+h2/2
cx=(cx1+cx2)/2
cy=(cy1+cy2)/2
cv2.line(img, (cx1,cy1),(cx2,cy2),(255,0,0),2)
cv2.circle(img, (cx,cy),2,(0,0,255),2)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
elif(len(conts)==1):
x,y,w,h=cv2.boundingRect(conts[0])
if(pinchFlag==0):
pinchFlag=1
mouse.press(Button.left)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
cx=x+w/2
cy=y+h/2
cv2.circle(img,(cx,cy),(w+h)/4,(0,0,255),2)
mouseLoc=(sx-(cx*sx/camx), cy*sy/camy)
mouse.position=mouseLoc
while mouse.position!=mouseLoc:
pass
cv2.imshow("cam",img)
cv2.waitKey(5)
Virtual Mouse with Gesture Recognition Video Tutor
Great article…
hi,
i got a problem when i run it in pycharm edu.
It shows me an error saying “This program needs access to the screen. Please run with a
Framework build of python, and only when you are logged in
on the main display of your Mac.”
please can you help me sort it out.
facing the issue if you are using virtual envs like anaconda. in mac
check this
https://github.com/facelessuser/Rummage/issues/127
I think its best to skip wxpython and use tkinter instead
import wx
app = wx.App(False)
(sx, sy) = wx.GetDisplaySize()
remove above lines and add below lines intead
import tkinter as tk
root = tk.Tk()
sx = root.winfo_screenwidth()
sy = root.winfo_screenheight()
Hello, I am from Kazakhstan, and I teaching in School for gifted children “Nazarbayev Intelectual School”, Last time, together with my students, we tried create program for mouse control with use python + opencv. Thank you for great article, and I try your project, but I dont understand wich color are you used on you finger in video . I try used yellow paperstick, but I dont saw rectangle for group on videocapture. Please, help me. I use OpenCV 3.1.0 (opencv 3.3.1.whl), Python 3.5.2, numpy 1.13.3, pynpit 1.3.7. My email is [email protected].
I attach several files on my letter https://uploads.disquscdn.com/images/7b90db1eb97e0efa17391dc9dee514e707ef68c153cb705b89921037d276f9f6.png
try these values
————code——
import numpy as np
import cv2
from pynput.mouse import Button, Controller
import wx
mouse = Controller()
app = wx.App(False)
(sx, sy) = wx.GetDisplaySize()
(camx, camy) = (640, 480)
lowerBound = np.array([28, 80, 40])
upperBound = np.array([43, 255, 255])
cam = cv2.VideoCapture(0)
cam.set(3, camx)
cam.set(4, camy)
kernelOpen = np.ones((5, 5))
kernelClose = np.ones((20, 20))
pinchFlag = 0
while True:
#ret, img = cam.read()
img=cv2.imread(‘/Users/anirban/Downloads/Screenshot_1.png’)
img = cv2.resize(img, (640, 480))
# convert BGR to HSV imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) create the Mask mask = cv2.inRange(imgHSV, lowerBound, upperBound) morphology maskOpen = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernelOpen) maskClose = cv2.morphologyEx(maskOpen, cv2.MORPH_CLOSE, kernelClose) maskFinal = maskClose conts = cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) h = cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if (len(conts) == 2): if (pinchFlag == 1): pinchFlag = 0 mouse.release(Button.left) 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) <code>cx1 = x1 + w1 / 2 cy1 = y1 + h1 / 2 cx2 = x2 + w2 / 2 cy2 = y2 + h2 / 2 cx = (cx1 + cx2) / 2 cy = (cy1 + cy2) / 2 cv2.line(img, (cx1, cy1), (cx2, cy2), (255, 0, 0), 2) cv2.circle(img, (cx, cy), 2, (0, 0, 255), 2) mouseLoc = (sx - (cx * sx / camx), cy * sy / camy) mouse.position = mouseLoc while mouse.position != mouseLoc: pass
elif (len(conts) == 1):
x, y, w, h = cv2.boundingRect(conts[0])
if (pinchFlag == 0):
pinchFlag = 1
mouse.press(Button.left)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cx = x + w / 2
cy = y + h / 2
cv2.circle(img, (cx, cy), (w + h) / 4, (0, 0, 255), 2)
mouseLoc = (sx – (cx * sx / camx), cy * sy / camy)
mouse.position = mouseLoc
while mouse.position != mouseLoc:
pass
cv2.imshow(“Camera”, img)
cv2.imshow(“mask”,maskFinal)
cv2.waitKey(5)
Fix the indent properly
Hi,
I found your tutorial very useful and understood the concept. I am trying to make a similar project using yellow papersticks, I have set the lower and upperbound as mentioned in your code above still not getting any rectangle on papers. I am using OpenCV 3.3.0, Python 3.6.
Please help me implementing this project
I followed your code under this comment section
I got error conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
ValueError: too many values to unpack (expected 2)
Then when I fixed it using this _, conts, _ = cv2……… I got another error which is typeerror-integer-argument-expected-got-float. I am using python 3.5 with opencv-contrib-python 3.3
Can you share us your code?
Try to use these color. I tested all these color working fine for me
for green
lowerBound=np.array([40,80,40])
upperBound=np.array([65,255,255])
skin color
lowerBound=np.array([0,80,40])
upperBound=np.array([20,255,255])
yelloish
lowerBound=np.array([20, 80, 100])
upperBound=np.array([40,200,300])
for red
lowerBound=np.array([170,120,150])
upperBound=np.array([190,255,255])
for blue
lowerBound=np.array([110,150,100])
upperBound=np.array([120,200,200])
Hi Codacus,
How do i implement right click in conts=1 with no lag ?
i tried using wait key command but it only delays the right click for more than 5 seconds and performs left click at the same time. is there any command to implement right click when ur mouse is on the icon ?
HI
this is very cool and thanks for your sharing
but how can i fix this problem
Traceback (most recent call last):
File “C:Users6006685datapythonmouse_control.py”, line 68, in
mouse.position=(sx-(cxsx/camx),cysy/camy)
File “C:Users6006685AppDataLocalProgramsPythonPython36libsite-packagespynputmouse_base.py”, line 65, in position
self._position_set(pos)
File “C:Users6006685AppDataLocalProgramsPythonPython36libsite-packagespynputmouse_win32.py”, line 66, in _position_set
self.__SetCursorPos(*pos)
ctypes.ArgumentError: argument 1: : Don’t know how to convert parameter 1
convert both parameter to int
int(sx-(cxsx/camx)), int(cysy/camy) use this code in place of sx-(cxsx/camx), cysy/camy
Hi.. Thanks for sharing. this is very cool,
I try to make same project for demo but I found some error, how can I fix this problem,( “conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
ValueError: too many values to unpack (expected 2)”)
This Is complete code, please guide me. where I wrong and how i can fix these problems
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)
lowerBound=np.array([33,80,40])
upperBound=np.array([102,255,255])
cam=cv2.VideoCapture(0)
cam.set(3,camx)
cam.set(4,camy)
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))
while True:
ret, img=cam.read()
imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(imgHSV,lowerBound,upperBound)
maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose)
maskFinal=maskClose conts,h=cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if(len(conts)==2): mouse.release(Button.left) x1,y1,w1,h1=cv2.boundingRect(conts[0]) x2,y2,w2,h2=cv2.boundingRect(count[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) cx1=x1+w1/2 cy1=y1+h1/2 cx2=x2+w2/2 cy2=y2+h2/2 cx=(cx1+cx2)/2 cy=(cy1+cy2)/2 cv2.line(img, (cx1,cy1),(cx2,cy2),(255,0,0,),2) cv2.circle(img, (cx,cy),2,(0,0,255),2) <code> mouse.position=(sx-(cx*sx/camx),cy*cy/camy) while mouse.position1-(cx*sx/camx,sy*cy/camy): pass
elif(len(conts)==1):
x,y,w,h=cv2.boundingRect(conts[0])
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
cv2.rectangle()
cx=x+w/2
cy=y+h/2
cv2.circle(img,(cx,cy),(w+h)/4,(0,0,255),2)
mouse.position=(cxsx/camx,cycy/camy)
while mouse.position1-(sx-(cxsx/camx),cysy/camy):
pass
mouse.press(Button.left)
cv2.imshow(“cam”,img)
cv2.waitKey(5)
use this code _,conts,h=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
Thankss
welcome.
Again same problem
conts,h=cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
ValueError: too many values to unpack (expected 2)
anyparamater,conts,h=cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
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)
lowerBound=np.array([33,80,40])
upperBound=np.array([102,255,255])
cam=cv2.VideoCapture(0)
cam.set(3,camx)
cam.set(4,camy)
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))
pinchFlag=0
while True:
ret, img=cam.read()
img=cv2.resize(img,(320,240))
imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(imgHSV,lowerBound,upperBound)
maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose)
maskFinal=maskClose conts,h=cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) h = cv2.findContours(maskFinal.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if(len(conts)==2): if(pinchFlag==1): piinchFlag==0 mouse.release(Button.left) <code> mouse.release(Button.left) x1,y1,w1,h1=cv2.boundingRect(conts[0]) x2,y2,w2,h2=cv2.boundingRect(count[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) cx1=x1+w1/2 cy1=y1+h1/2 cx2=x2+w2/2 cy2=y2+h2/2 cx=(cx1+cx2)/2 cy=(cy1+cy2)/2 cv2.line(img, (cx1,cy1),(cx2,cy2),(255,0,0,),2) cv2.circle(img, (cx,cy),2,(0,0,255),2) mouseLoc=(sx-(cx*sx/camx), cy*sy/camy) mouse.position=mouseLoc while mouse.position!=mouseLoc: pass
elif(len(conts)==1):
x,y,w,h=cv2.boundingRect(conts[0])
if(pinchFlag==0):
pinchFlag==1
mouse.press(Button.left)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) cv2.rectangle() cx=x+w/2 cy=y+h/2 cv2.circle(img,(cx,cy),(w+h)/4,(0,0,255),2) mouseLoc=(sx-(cx*sx/camx), cy*sy/camy) mouse.position=mouseLoc while mouse.position!=mouseLoc: pass
cv2.imshow(“cam”,img)
cv2.waitKey(5)
https://uploads.disquscdn.com/images/24215424c852348443fe846c6320ae34715359a56c5b735b750b79f15a5b0daf.jpg
Sir can you Operate mypc through Team viewer if poosible for you..
yea, give me your teamviewer id
200 655 238
pass;- y412gm
cv2.rectangle()
TypeError: Required argument ‘img’ (pos 1) not found
also not detect green paper I try whole night but not success
Coonect me with whatsap. There need lot changes to run the program. +917384182524
Sir your no. is not shown in whatsApp.. 7284182524
+917384182524. sorry last time it was wrong number
cv2.rectangle()
TypeError: Required argument ‘img’ (pos 1) not found
also not detect green paper I try whole night but not success
+917384182524. sorry last time it was wrong number
Finally Code running but not show application where it run .
look at the red mark i have done. there is a “_” mark and then a comma. Do it and run
before conts and h you need another unused parameter, because this contour function returns three variables. so you need another unused variable. check and reply me back
Sir can you operate My PC through team Viewer If possible for you
hello , can you please tell me how to import wx in pycharm ???? i have an error (no module found)
how do i solve this
cv2.line(img, (cx1,cy1),(cx2,cy2),(255,0,0),2)
TypeError: integer argument expected, got float