首页 > 解决方案 > 带背景减法的手形光标控制器

问题描述

我正在使用带有 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()但出现错误并且光标仍然不会移动

标签: pythonobjectcursortrackingbackground-subtraction

解决方案


推荐阅读