You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python3与OpenCV的虚拟键盘项目:合并手势键盘脚本与摄像头镜像脚本的问题求助

Hey there! Let's fix this merge issue and get your virtual keyboard working with a mirrored camera feed. Here's a straightforward solution that combines both scripts and resolves the inverted display problem:

Solution: Merged Script with Mirrored Camera Feed

We can either integrate the mirror functionality directly into your virtual keyboard script (simpler approach) or keep using your Mirror class for modularity. Below are both options:

Option 1: Simplified Merge (No Separate Mirror Class)

This approach adds the mirror flip directly to your original keyboard script, cutting down on redundant code while keeping all your core features intact:

import cv2
from time import sleep
import mediapipe as mp
from cvzone.HandTrackingModule import HandDetector
import numpy as np
import cvzone

detector = HandDetector(detectionCon=0.8)
keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
        ["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],
        ["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
finalText = ""

def drawAll(img, buttonList):
    imgNew = np.zeros_like(img, np.uint8)
    for button in buttonList:
        x, y = button.pos
        cvzone.cornerRect(imgNew, (button.pos[0], button.pos[1], button.size[0], button.size[1]), 20, rt=0)
        cv2.rectangle(imgNew, button.pos, (x + button.size[0], y + button.size[1]), (255, 0, 255), cv2.FILLED)
        cv2.putText(imgNew, button.text, (x + 40, y + 60), cv2.FONT_HERSHEY_PLAIN, 2, (255, 255, 255), 3)
    out = img.copy()
    alpha = 0.5
    mask = imgNew.astype(bool)
    out[mask] = cv2.addWeighted(img, alpha, imgNew, 1 - alpha, 0)[mask]
    return out

class Button():
    def __init__(self,pos,text,size=[85,85]):
        self.pos = pos
        self.size = size
        self.text = text

buttonList =[]
for i in range(len(keys)):
    for j, key in enumerate(keys[i]):
        buttonList.append(Button([100 * j + 50, 100 * i + 50], key))

# Initialize camera
video = cv2.VideoCapture(0)
video.set(3, 1280)
video.set(4, 720)

# Optional: Enable fullscreen mode (from your Mirror script)
cv2.namedWindow('Virtual Keyboard', cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty('Virtual Keyboard', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

while True:
    success, img = video.read()
    if not success:
        break
    
    # Mirror the camera feed to fix inverted/opposite hand movement
    img = cv2.flip(img, 1)
    
    img = detector.findHands(img)
    lmList, bboxInfo = detector.findPosition(img)
    img = drawAll(img, buttonList)

    if lmList:
        for button in buttonList:
            x,y = button.pos
            w,h = button.size
            if x< lmList[8][0] <x+w and y<lmList[8][1]<y+h:
                cv2.rectangle(img, button.pos, (x + w, y + h), (175, 0, 175), cv2.FILLED)
                cv2.putText(img, button.text, (x + 20, y + 65), cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)
                l,_,_ = detector.findDistance(8,12,img,draw=False)
                if l<30:
                    cv2.rectangle(img, button.pos, (x + w, y + h), (0, 255, 0), cv2.FILLED)
                    cv2.putText(img, button.text, (x + 20, y + 65), cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)
                    finalText += button.text
                    sleep(0.25)

    cv2.rectangle(img, (50,350), (700,450), (175, 0, 175), cv2.FILLED)
    cv2.putText(img, finalText, (60, 435), cv2.FONT_HERSHEY_PLAIN,5 , (255, 255, 255), 5)

    cv2.imshow("Virtual Keyboard",img)
    # Exit on ESC key
    if cv2.waitKey(1) == 27:
        break

# Cleanup resources
video.release()
cv2.destroyAllWindows()

Option 2: Merge with Your Mirror Class

If you want to keep using your Mirror class for modularity, here's how to integrate it properly without conflicts:

import cv2
from time import sleep
import mediapipe as mp
from cvzone.HandTrackingModule import HandDetector
import numpy as np
import cvzone

detector = HandDetector(detectionCon=0.8)
keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
        ["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],
        ["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
finalText = ""

def drawAll(img, buttonList):
    imgNew = np.zeros_like(img, np.uint8)
    for button in buttonList:
        x, y = button.pos
        cvzone.cornerRect(imgNew, (button.pos[0], button.pos[1], button.size[0], button.size[1]), 20, rt=0)
        cv2.rectangle(imgNew, button.pos, (x + button.size[0], y + button.size[1]), (255, 0, 255), cv2.FILLED)
        cv2.putText(imgNew, button.text, (x + 40, y + 60), cv2.FONT_HERSHEY_PLAIN, 2, (255, 255, 255), 3)
    out = img.copy()
    alpha = 0.5
    mask = imgNew.astype(bool)
    out[mask] = cv2.addWeighted(img, alpha, imgNew, 1 - alpha, 0)[mask]
    return out

class Button():
    def __init__(self,pos,text,size=[85,85]):
        self.pos = pos
        self.size = size
        self.text = text

class Mirror:
    def __init__(self):
        self.__setupCamera()
        self.__setupWindow()

    def __setupCamera(self):
        self.cam = cv2.VideoCapture(0)
        self.cam.set(3, 1280)
        self.cam.set(4, 720)

    def __setupWindow(self):
        cv2.namedWindow('Virtual Keyboard', cv2.WND_PROP_FULLSCREEN)
        cv2.setWindowProperty('Virtual Keyboard', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

    def read(self):
        ret, frame = self.cam.read()
        if ret:
            return cv2.flip(frame, 1)
        return None

    def release(self):
        self.cam.release()

buttonList =[]
for i in range(len(keys)):
    for j, key in enumerate(keys[i]):
        buttonList.append(Button([100 * j + 50, 100 * i + 50], key))

# Initialize Mirror instead of direct VideoCapture
mirror = Mirror()

while True:
    img = mirror.read()
    if img is None:
        break
    
    img = detector.findHands(img)
    lmList, bboxInfo = detector.findPosition(img)
    img = drawAll(img, buttonList)

    if lmList:
        for button in buttonList:
            x,y = button.pos
            w,h = button.size
            if x< lmList[8][0] <x+w and y<lmList[8][1]<y+h:
                cv2.rectangle(img, button.pos, (x + w, y + h), (175, 0, 175), cv2.FILLED)
                cv2.putText(img, button.text, (x + 20, y + 65), cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)
                l,_,_ = detector.findDistance(8,12,img,draw=False)
                if l<30:
                    cv2.rectangle(img, button.pos, (x + w, y + h), (0, 255, 0), cv2.FILLED)
                    cv2.putText(img, button.text, (x + 20, y + 65), cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)
                    finalText += button.text
                    sleep(0.25)

    cv2.rectangle(img, (50,350), (700,450), (175, 0, 175), cv2.FILLED)
    cv2.putText(img, finalText, (60, 435), cv2.FONT_HERSHEY_PLAIN,5 , (255, 255, 255), 5)

    cv2.imshow("Virtual Keyboard",img)
    if cv2.waitKey(1) == 27:
        break

mirror.release()
cv2.destroyAllWindows()

Why Your Original Merge Failed:

The main issue was conflicting frame sources—you were trying to use both video.read() (from script 1) and the Mirror class's read method at the same time. By either adding the cv2.flip call directly to your keyboard script or replacing the direct VideoCapture with the Mirror class's camera handling, you ensure the mirrored frame is used consistently throughout the keyboard logic.

Both solutions will fix the inverted camera feed and let you control the virtual keyboard with natural hand movements. Let me know if you hit any other snags!

内容的提问来源于stack exchange,提问作者ngkenx98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 19:17:44