步驟1:安裝Anaconda和需要的軟件包
Anaconda本質(zhì)上是一個(gè)包裝精美的Python IDE,隨附了大量有用的軟件包,如NumPy,Pandas,IPython筆記本等似乎在科學(xué)界的各個(gè)地方都值得推薦。查看Anaconda以安裝它。
所需的軟件包:
PyAutoGUI
OpenCv
安裝上述軟件包:
OpenCV:
點(diǎn)擊此鏈接逐步安裝for opencv
PyAutoGUI:
PyAutoGUI是一個(gè)Python模塊,用于以編程方式控制鼠標(biāo)和鍵盤(pán)。
PyAutoGUI可以從 pip 工具中安裝
打開(kāi)你的anaconda命令提示并粘貼它:
pip install PyAutoGUI
現(xiàn)在我們準(zhǔn)備好了代碼。..。..
第2步:技術(shù)概述
它本質(zhì)上是一個(gè)程序,它應(yīng)用圖像處理,檢索必要的數(shù)據(jù),并根據(jù)預(yù)定義的概念將其實(shí)現(xiàn)到計(jì)算機(jī)的鼠標(biāo)接口。
代碼是用Python編寫(xiě)的。它使用跨平臺(tái)圖像處理模塊OpenCV,并使用Python特定庫(kù)PyAutoGUI實(shí)現(xiàn)鼠標(biāo)操作。
處理網(wǎng)絡(luò)攝像頭的視頻捕獲,僅提取三個(gè)彩色指尖。他們的中心是用矩量法計(jì)算的,根據(jù)它們的相對(duì)位置決定要執(zhí)行什么動(dòng)作。
第3步:視頻入門(mén)
目標(biāo)一:
cv2.VideoCapture()
從中捕獲視頻相機(jī)
通常,我們必須使用相機(jī)捕捉直播。 OpenCV為此提供了一個(gè)非常簡(jiǎn)單的接口。讓我們從相機(jī)中捕捉視頻(我正在使用筆記本電腦的內(nèi)置網(wǎng)絡(luò)攝像頭),將其轉(zhuǎn)換為灰度視頻并顯示它。入門(mén)只是一項(xiàng)簡(jiǎn)單的任務(wù)。要捕獲視頻,您需要?jiǎng)?chuàng)建一個(gè)VideoCapture對(duì)象。它的參數(shù)可以是設(shè)備索引或視頻文件的名稱(chēng)。設(shè)備索引只是指定哪個(gè)攝像頭的數(shù)量。通常會(huì)連接一臺(tái)攝像機(jī)(如我的情況)。所以我只傳遞0(或-1)。您可以通過(guò)傳遞1來(lái)選擇第二個(gè)攝像頭,依此類(lèi)推。之后,您可以逐幀捕獲。但最后,不要忘記發(fā)布捕獲。
我們要做的第一件事就是將捕獲的視頻轉(zhuǎn)換為HSV格式。
代碼:
# All packages needed for the program are imported ahead
import cv2
cap = cv2.VideoCapture(0)
while(1):
# Capture frame-by-frame
_, frameinv = cap.read()
# flip horizontaly to get mirror image in camera
frame = cv2.flip( frameinv, 1)
# Our operations on the frame come here
hsv = cv2.cvtColor( frame, cv2.COLOR_BGR2HSV)
# Display the resulting frame
cv2.imshow(‘Frame’, hsv)
k = cv2.waitKey(10) & 0xFF
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
第4步:顏色范圍
目標(biāo)二:
calibrateColor()
校準(zhǔn)顏色范圍
現(xiàn)在,用戶(hù)可以分別校準(zhǔn)他的三個(gè)手指的顏色范圍。這可以通過(guò)在程序開(kāi)頭三次調(diào)用 calibrateColor()函數(shù)來(lái)完成。
用戶(hù)也可以選擇使用默認(rèn)設(shè)置。
代碼:
import cv2
import numpy as np
def nothing(x):
pass
# Create a black image, a window
kernel = np.zeros((300,512,3), np.uint8)
name = ‘Calibrate’
cv2.namedWindow(name)
# create trackbars for color change
cv2.createTrackbar(‘Hue’, name, 0, 255, nothing)
cv2.createTrackbar(‘Sat’, name, 0, 255, nothing)
cv2.createTrackbar(‘Val’, name, 0, 255, nothing)
# create switch for ON/OFF functionality
switch = ‘0 : OFF 1 : ON’
cv2.createTrackbar(switch, name,0,1,nothing)
while(1):
cv2.imshow(name,kernel)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# get current positions of four trackbars
hue = cv2.getTrackbarPos(‘Hue’, name)
sat = cv2.getTrackbarPos(‘Sat’, name)
val = cv2.getTrackbarPos(‘Val’, name)
s = cv2.getTrackbarPos(switch,name)
if s == 0:
kernel[:] = 0
else:
kernel[:] = [hue,sat,val]
cv2.destroyAllWindows()
第5步:刪除噪音&在視頻源中定義函數(shù)
取決于校準(zhǔn),只使用 cv2.inRange()功能逐一從視頻中提取三個(gè)指尖。為了消除視頻輸入中的噪聲,我們應(yīng)用兩步態(tài)射,即侵蝕和擴(kuò)張。 然后發(fā)送程序中稱(chēng)為掩碼的噪聲濾波圖像以定位中心。
# cv2.inRange function is used to filter out a particular color from the frame
# The result then undergoes morphosis i.e. erosion and dilation
# Resultant frame is returned as mask
def makeMask(hsv_frame, color_Range):
mask = cv2.inRange( hsv_frame, color_Range[0], color_Range[1])
# Morphosis next 。..
eroded = cv2.erode( mask, kernel, iterations=1)
dilated = cv2.dilate( eroded, kernel, iterations=1)
return dilated
三個(gè)中心的位置包括:
在與該顏色范圍相關(guān)的遮罩中查找輪廓。
使用區(qū)域過(guò)濾器丟棄不相關(guān)區(qū)域的輪廓。
在剩余的輪廓中找到最大的輪廓,并應(yīng)用力矩的方法找到它的中心。
然后是定義光標(biāo)在屏幕上的位置的步驟。黃色的拇指負(fù)責(zé)光標(biāo)的位置。為此目的使用了以下技術(shù):
?通常我們使用的網(wǎng)絡(luò)攝像頭以640x480像素的分辨率捕獲視頻。假設(shè)此幀線性映射到1920x1080像素顯示屏幕。如果我們有一個(gè)慣用右手的用戶(hù),他會(huì)發(fā)現(xiàn)與右邊緣相比,訪問(wèn)屏幕的左邊緣會(huì)感覺(jué)不舒服。訪問(wèn)屏幕的底部也會(huì)在手腕處產(chǎn)生壓力。
我們意識(shí)到,不是將整個(gè)視頻幀映射到屏幕,我們寧愿考慮更偏向右側(cè)的矩形子部分(考慮右手用戶(hù))和幀的上部以便改進(jìn)安慰。測(cè)量480x270像素的子部分然后以比例因子4線性映射到屏幕。
# Contours on the mask are detected.。 Only those lying in the previously set area
# range are filtered out and the centroid of the largest of these is drawn and returned
def drawCentroid(vid, color_area, mask, showCentroid):
contour, _ = cv2.findContours( mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
l=len(contour)
area = np.zeros(l)
# filtering contours on the basis of area rane specified globally
for i in range(l):
if cv2.contourArea(contour[i])》color_area[0] and cv2.contourArea(contour[i])
# bringing contours with largest valid area to the top
for i in range(l):
for j in range(1):
if area[i] == a[j]:
swap( contour, i, j)
if l 》 0 :
# finding centroid using method of ‘moments’
M = cv2.moments(contour[0])
if M[‘m00’] != 0:
cx = int(M[‘m10’]/M[‘m00’])
cy = int(M[‘m01’]/M[‘m00’])
center = (cx,cy)
if showCentroid:
cv2.circle( vid, center, 5, (0,0,255), -1)
return center
else:
# return error handling values
return (-1,-1)
?由于網(wǎng)絡(luò)攝像頭捕獲的噪聲和手中的振動(dòng),中心保持不變圍繞一個(gè)平均位置振動(dòng)。在按比例放大時(shí),這些振動(dòng)會(huì)對(duì)光標(biāo)位置的準(zhǔn)確性產(chǎn)生很多問(wèn)題。為了減少光標(biāo)中的抖動(dòng),我們使用光標(biāo)的差分位置分配。我們將新中心與光標(biāo)的先前位置進(jìn)行比較。如果差異小于5個(gè)像素,則通常是由于噪聲。因此,新光標(biāo)位置更傾向于前一個(gè)。但是,先前位置和新中心的較大差異被視為自愿移動(dòng),新光標(biāo)位置設(shè)置為接近新中心。有關(guān)詳細(xì)信息,請(qǐng)通過(guò)代碼中的setCursorPosition()函數(shù)。
‘’‘
This function takes as input the center of yellow region (yc) and
the previous cursor position (pyp)。 The new cursor position is calculated
in such a way that the mean deviation for desired steady state is reduced.
’‘’
def setCursorPos( yc, pyp):
yp = np.zeros(2)
if abs(yc[0]-pyp[0])《5 and abs(yc[1]-pyp[1])《5:
yp[0] = yc[0] + .7*(pyp[0]-yc[0])
yp[1] = yc[1] + .7*(pyp[1]-yc[1])
else:
yp[0] = yc[0] + .1*(pyp[0]-yc[0])
yp[1] = yc[1] + .1*(pyp[1]-yc[1])
return yp
現(xiàn)在發(fā)送三個(gè)中心,根據(jù)
的相對(duì)位置決定需要執(zhí)行哪些操作。這是在代碼中的chooseAction()函數(shù)中完成的。根據(jù)其輸出,performAction()函數(shù)使用PyAutoGUI庫(kù)執(zhí)行以下任一操作:
自由光標(biāo)移動(dòng)
左鍵單擊
右鍵單擊
拖動(dòng)/選擇
向上滾動(dòng)
向下滾動(dòng)
# Depending upon the relative positions of the three centroids, this function chooses whether
# the user desires free movement of cursor, left click, right click or dragging
def chooseAction(yp, rc, bc):
out = np.array([‘move’, ‘false’])
if rc[0]!=-1 and bc[0]!=-1:
if distance(yp,rc)《50 and distance(yp,bc)《50 and distance(rc,bc)《50 :
out[0] = ‘drag’
out[1] = ‘true’
return out
elif distance(rc,bc)《40:
out[0] = ‘right’
return out
elif distance(yp,rc)《40:
out[0] = ‘left’
return out
elif distance(yp,rc)》40 and rc[1]-bc[1]》120:
out[0] = ‘down’
return out
elif bc[1]-rc[1]》110:
out[0] = ‘up’
return out
else:
return out
else:
out[0] = -1
return out def performAction( yp, rc, bc, action, drag, perform):
if perform:
cursor[0] = 4*(yp[0]-110)
cursor[1] = 4*(yp[1]-120)
if action == ‘move’:
if yp[0]》110 and yp[0]《590 and yp[1]》120 and yp[1]《390:
pyautogui.moveTo(cursor[0],cursor[1])
elif yp[0]《110 and yp[1]》120 and yp[1]《390:
pyautogui.moveTo( 8 , cursor[1])
elif yp[0]》590 and yp[1]》120 and yp[1]《390:
pyautogui.moveTo(1912, cursor[1])
elif yp[0]》110 and yp[0]《590 and yp[1]《120:
pyautogui.moveTo(cursor[0] , 8)
elif yp[0]》110 and yp[0]《590 and yp[1]》390:
pyautogui.moveTo(cursor[0] , 1072)
elif yp[0]《110 and yp[1]《120:
pyautogui.moveTo(8, 8)
elif yp[0]《110 and yp[1]》390:
pyautogui.moveTo(8, 1072)
elif yp[0]》590 and yp[1]》390:
pyautogui.moveTo(1912, 1072)
else:
pyautogui.moveTo(1912, 8)
elif action == ‘left’:
pyautogui.click(button = ‘left’)
elif action == ‘right’:
pyautogui.click(button = ‘right’)
time.sleep(0.3)
elif action == ‘up’:
pyautogui.scroll(5)
# time.sleep(0.3)
elif action == ‘down’:
pyautogui.scroll(-5)
# time.sleep(0.3)
elif action == ‘drag’ and drag == ‘true’:
global y_pos
drag = ‘false’
pyautogui.mouseDown()
while(1):
k = cv2.waitKey(10) & 0xFF
changeStatus(k)
_, frameinv = cap.read()
# flip horizontaly to get mirror image in camera
frame = cv2.flip( frameinv, 1)
hsv = cv2.cvtColor( frame, cv2.COLOR_BGR2HSV)
b_mask = makeMask( hsv, blue_range)
r_mask = makeMask( hsv, red_range)
y_mask = makeMask( hsv, yellow_range)
py_pos = y_pos
b_cen = drawCentroid( frame, b_area, b_mask, showCentroid)
r_cen = drawCentroid( frame, r_area, r_mask, showCentroid)
y_cen = drawCentroid( frame, y_area, y_mask, showCentroid)
if py_pos[0]!=-1 and y_cen[0]!=-1:
y_pos = setCursorPos(y_cen, py_pos)
performAction(y_pos, r_cen, b_cen, ‘move’, drag, perform)
cv2.imshow(‘Frame’, frame)
if distance(y_pos,r_cen)》60 or distance(y_pos,b_cen)》60 or distance(r_cen,b_cen)》60:
break
pyautogui.mouseUp()
-
鼠標(biāo)
+關(guān)注
關(guān)注
6文章
593瀏覽量
40747 -
手勢(shì)控制
+關(guān)注
關(guān)注
4文章
44瀏覽量
22047
發(fā)布評(píng)論請(qǐng)先 登錄
用是德示波器3000T X系列的手勢(shì)操作簡(jiǎn)化汽車(chē)ECU復(fù)雜信號(hào)調(diào)試

基于stm32和mpu9250的usb hid鍵盤(pán)、鼠標(biāo)、游戲控制器實(shí)例打包下載
基于stm32和mpu9250的usb hid鍵盤(pán)、鼠標(biāo)、游戲控制器
如何移動(dòng)鼠標(biāo)時(shí)高亮下方的網(wǎng)絡(luò)?

基于Nordic nRF52840無(wú)線鍵盤(pán)、鼠標(biāo)物聯(lián)網(wǎng)解決方案
聲云AI語(yǔ)音鼠標(biāo)開(kāi)啟智能辦公新時(shí)代
電容電阻在鼠標(biāo)主板中的關(guān)鍵作用分析
大研智造激光焊錫機(jī):突破鼠標(biāo)微動(dòng)PCB焊接困境的“神器”
無(wú)線鼠標(biāo)是怎么工作的

Cortex-A55國(guó)產(chǎn)處理器_教學(xué)實(shí)驗(yàn)箱_操作案例分享:5-21 手勢(shì)識(shí)別實(shí)驗(yàn)
電容式觸摸手勢(shì)軟件和調(diào)整應(yīng)用說(shuō)明

適用于無(wú)線鼠標(biāo)與藍(lán)牙鼠標(biāo)中的晶振FA-238/FA-238V

NXP 恩智浦 電競(jìng)鼠標(biāo)方案集錦

評(píng)論