python - 带背景减法的手形光标控制器
问题描述
我正在使用带有 MOG 背景减法的网络摄像头制作带有手势的光标控制器。当我使用没有 MOG 的光标控制器时一切都很好,但是当我使用它时,我无法移动光标。当我搜索问题时,似乎无法将 x 值发送到运动步骤中,我需要一些关于此的建议。
if used_defect is not None:
best = used_defect
if count_defects == 2:
x = best['x']
y = best['y']
display_x = x
display_y = y
if MOVEMENT_START is not None:
M_START = (x, y)
x = x - MOVEMENT_START[1]
y = y - MOVEMENT_START[1]
x = x * (SCREEN_X / CAMERA_X)
y = y * (SCREEN_Y / CAMERA_Y)
MOVEMENT_START = M_START
print("X: " + str(x) + " Y: " + str(y))
pyautogui.moveRel(x,y)
x 值可以到这里:
if used_defect is not None:
best = used_defect
if count_defects == 2:
x = best['x']
y = best['y']
display_x = x
display_y = y
但是当我试图将它移到下一个时,它总是 X: 0.0 并且光标根本不会移动,但计数缺陷工作正常。
这是我的完整代码:
import cv2
import numpy as np
import math
import time
import copy
import pyautogui
#Parameters
pyautogui.FAILSAFE = False
SCREEN_X = 0
SCREEN_Y = 1
# SCREEN_X, SCREEN_Y = pyautogui.size()
CLICK = CLICK_MESSAGE = MOVEMENT_START = None
blurValue = 35
bgSubThreshold = 50
learningRate = 0
#Variables
isBgCaptured = 0 # bool, whether the background captured
def removeBG(img):
fgmask = bgModel.apply(img, learningRate=learningRate)
kernel = np.ones((3,3), np.uint8)
fgmask = cv2.erode(fgmask, kernel, iterations=1)
res = cv2.bitwise_and(img, img, mask=fgmask)
return res
#Camera
cap = cv2.VideoCapture(1)
while cap.isOpened():
ret, img = cap.read()
CAMERA_X, CAMERA_Y, channels = img.shape
img = cv2.bilateralFilter(img, 5, 50, 100) #Smoothing Filter
img = cv2.flip(img, 1) #Flip kamera secara horizontal
cv2.rectangle(img, (int(SCREEN_X * img.shape[1]), 0),
(img.shape[1], int(SCREEN_Y * img.shape[0])), (255, 0, 0), 2)
cv2.imshow('original', img)
#Main Operation
if isBgCaptured == 1:
crop_img = removeBG(img)
crop_img = crop_img[0:int(SCREEN_Y * img.shape[0]),
int(SCREEN_X * img.shape[1]):img.shape[1]]
cv2.imshow('mask', crop_img)
grey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(grey, (blurValue, blurValue), 0)
ret, thresh = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow('Thresholded', thresh)
#Mendapatkan kontur tangan
thresh1 = copy.deepcopy(thresh)
contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
length = len(contours)
max_area = -1
if length > 0 :
for i in range(length):
cnt = contours[i]
area = cv2.contourArea(cnt)
if area > max_area:
max_area = area
ci = i
cnt = contours[ci]
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(crop_img, (x, y), (x + w, y + h), (0, 0, 255), 0)
hull = cv2.convexHull(cnt)
drawing = np.zeros(crop_img.shape, np.uint8)
cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0)
cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 0)
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
count_defects = 0
cv2.drawContours(thresh, contours, -1, (0, 255, 0), 3)
if type(defects) != type(None): #Untuk menghindari crash
used_defect = None
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
a = math.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)
b = math.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)
c = math.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)
angle = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) * 57
if angle <= 90:
count_defects += 1
cv2.circle(drawing, far, 5, [0, 0, 255], -1)
cv2.line(drawing, start, end, [0, 255, 0], 2)
medium_x = (start[0] + end[0]) / 2
medium_y = (start[1] + end[1]) / 2
if count_defects == 2 and angle <= 90:
used_defect = {"x": start[0], "y": start[1]}
if used_defect is not None:
best = used_defect
if count_defects == 2:
x = best['x']
y = best['y']
display_x = x
display_y = y
print (x)
if MOVEMENT_START is not None:
M_START = (x, y)
x = x - MOVEMENT_START[0]
y = y - MOVEMENT_START[1]
x = x * (SCREEN_X / CAMERA_X)
y = y * (SCREEN_Y / CAMERA_Y)
MOVEMENT_START = M_START
print("X: " + str(x) + " Y: " + str(y))
pyautogui.moveRel(x,y)
else:
MOVEMENT_START = (x, y)
cv2.circle(drawing, (display_x, display_y), 5, [255, 255, 255], 20)
elif count_defects == 3 and CLICK is None:
CLICK = time.time()
pyautogui.click()
CLICK_MESSAGE = "LEFT CLICK"
elif count_defects == 4 and CLICK is None:
CLICK = time.time()
pyautogui.rightClick()
CLICK_MESSAGE = "RIGHT CLICK"
else:
MOVEMENT_START = None
if CLICK is not None:
cv2.putText(drawing, CLICK_MESSAGE, (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
if CLICK < time.time():
CLICK = None
cv2.putText(drawing, "Defects: " + str(count_defects), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
# cv2.imshow('Gesture', img)
cv2.imshow('Drawing', drawing)
k = cv2.waitKey(10)
if k == 27:
cap.release()
cv2.destroyAllWindows()
break
elif k == ord('b'):
bgModel = cv2.createBackgroundSubtractorMOG2(0, bgSubThreshold)
isBgCaptured = 1
print('!!!Background Captured!!!')
elif k == ord('r'):
bgModel = None
isBgCaptured = 0
print('!!!Reset Background!!!')
如果我不能给出更多解释,我很抱歉,英语不是我的主要语言,我刚开始使用 python。哦,我已经尝试从 pyautogui.moveRel 更改为其他代码,但它总是最终将光标移动到我的屏幕一角
编辑 1:x 值始终为 0 是因为参数是SCREEN_X = 0,我已经尝试将其更改为pyautogui.size()但出现错误并且光标仍然不会移动
解决方案
推荐阅读
- ios - UISearchbar 在 Swift 4 中使用 UItextfield
- c++ - 如何让 QTreeView 填充整个对话框并调整其大小?
- excel - VBA 合并单元格的大小必须相同
- angular - Clarity 可重复使用的布尔过滤器
- javascript - 尝试使用 Laravel mix / webpack 时出现 JS 错误
- java - Hibernate Search:从查询中获取参数化结果,没有未经检查的警告
- r - 如何提高 sparklyr 读取 csv 的性能?
- angular - 如何使用 redux 设置超时
- java - 为什么延迟堆栈跟踪没有平均值?
- android - 从清单中删除类后应用程序未安装错误