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

Python虚拟鼠标项目调用自定义手部追踪模块报ValueError错误求解

错误原因
  • 直接触发报错的核心问题:你自行编写的handDetector类中findPosition方法仅返回1个值lmList,但虚拟鼠标主程序中使用lmList, bbox = detector.findPosition(img)尝试接收2个返回值,变量数量不匹配触发ValueError。
  • 代码还存在多处其他潜在错误,后续运行也会触发报错:
    1. 主程序调用cvzone.HandTrackingModule.HandDetector.fingersUp()是直接调用类方法,没有实例化对象也未传入当前手部关键点数据,逻辑完全错误
    2. 自定义的handDetector类没有实现findDistance方法,后续调用detector.findDistance(8,12,img)会触发属性不存在错误
    3. 主程序判断点击的条件if length [40]写法错误,length是数值类型不能用索引访问
    4. 主程序中帧率计算、窗口展示的代码缩进错误,被包在了点击逻辑的if分支里,只有触发点击才会更新画面和帧率
    5. 代码中所有"是HTML转义字符,需要替换为普通双引号",否则会触发语法错误
解决方案

1. 修改自定义手部追踪模块代码

完整修改后的HandTrackingModule.py代码如下:

import cv2
import mediapipe as mp
import time


class handDetector():
    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
        self.mode = mode
        self.maxHands = maxHands
        self.detectionCon = detectionCon
        self.trackCon = trackCon

        self.mpHands = mp.solutions.hands
        # 注意:mediapipe 0.10+版本需要新增model_complexity参数
        self.hands = self.mpHands.Hands(self.mode, self.maxHands,
                                        model_complexity=0,
                                        min_detection_confidence=self.detectionCon,
                                        min_tracking_confidence=self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils
        self.lmList = []

    def findHands(self, img, draw=True):
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)

        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)
        return img

    def findPosition(self, img, handNo=0, draw=True):
        self.lmList = []
        bbox = []
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNo]
            xList = []
            yList = []
            for id, lm in enumerate(myHand.landmark):
                h, w, c = img.shape
                cx, cy = int(lm.x * w), int(lm.y * h)
                xList.append(cx)
                yList.append(cy)
                self.lmList.append([id, cx, cy])
                if draw:
                    cv2.circle(img, (cx, cy), 7, (255, 0, 255), cv2.FILLED)
            # 计算手部边界框
            xmin, xmax = min(xList), max(xList)
            ymin, ymax = min(yList), max(yList)
            bbox = [xmin, ymin, xmax, ymax]
            if draw:
                cv2.rectangle(img, (xmin-20, ymin-20), (xmax+20, ymax+20), (0, 255, 0), 2)
        return self.lmList, bbox

    def fingersUp(self):
        fingers = []
        # 拇指判断
        if self.lmList[4][1] > self.lmList[3][1]:
            fingers.append(1)
        else:
            fingers.append(0)
        # 其余四指判断
        for id in range(8, 21, 4):
            if self.lmList[id][2] < self.lmList[id-2][2]:
                fingers.append(1)
            else:
                fingers.append(0)
        return fingers

    def findDistance(self, p1, p2, img, draw=True):
        x1, y1 = self.lmList[p1][1], self.lmList[p1][2]
        x2, y2 = self.lmList[p2][1], self.lmList[p2][2]
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2

        if draw:
            cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
            cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
            cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)

        length = ((x2 - x1)**2 + (y2 - y1)**2)**0.5
        return length, img, [x1, y1, x2, y2, cx, cy]


def main():
    pTime = 0
    cap = cv2.VideoCapture(0)
    detector = handDetector()
    while True:
        success, img = cap.read()
        img = detector.findHands(img)
        lmList, bbox = detector.findPosition(img)
        if len(lmList) != 0:
            print(lmList[4])

        cTime = time.time()
        fps = 1 / (cTime - pTime)
        pTime = cTime

        cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                    (255, 0, 255), 3)

        cv2.imshow("Image", img)
        if cv2.waitKey(1) == ord("q"):
            break

if __name__ == "__main__":
    main()

2. 修改虚拟鼠标主程序代码

完整修改后的主程序代码如下:

import cv2
import numpy as np
import HandTrackingModule as htm
import time
import autopy

##########################
wCam, hCam = 640, 480
frameR = 100  # 帧边界缩减
smoothening = 7
#########################

pTime = 0
plocX, plocY = 0, 0
clocX, clocY = 0, 0

cap = cv2.VideoCapture(0) # 摄像头索引如果打不开可以换1
cap.set(3, wCam)
cap.set(4, hCam)
detector = htm.handDetector(maxHands=1) # 只识别一只手提升性能
wScr, hScr = autopy.screen.size()

while True:
    # 1. 获取手部关键点
    success, img = cap.read()
    img = detector.findHands(img)
    lmList, bbox = detector.findPosition(img)
    # 2. 获取食指和中指指尖坐标
    if len(lmList) != 0:
        x1, y1 = lmList[8][1:]
        x2, y2 = lmList[12][1:]

        # 3. 检测手指抬起状态
        fingers = detector.fingersUp()
        cv2.rectangle(img, (frameR, frameR), (wCam - frameR, hCam - frameR),
                      (255, 0, 255), 2)
        # 4. 仅食指抬起:鼠标移动模式
        if fingers[1] == 1 and fingers[2] == 0:
            # 5. 坐标转换
            x3 = np.interp(x1, (frameR, wCam - frameR), (0, wScr))
            y3 = np.interp(y1, (frameR, hCam - frameR), (0, hScr))
            # 6. 平滑处理
            clocX = plocX + (x3 - plocX) / smoothening
            clocY = plocY + (y3 - plocY) / smoothening
            # 7. 移动鼠标
            autopy.mouse.move(wScr - clocX, clocY)
            cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
            plocX, plocY = clocX, clocY

        # 8. 食指和中指都抬起:点击模式
        if fingers[1] == 1 and fingers[2] == 1:
            # 9. 计算两指间距
            length, img, lineInfo = detector.findDistance(8, 12, img)
            # 10. 间距小于阈值触发点击
            if length < 40:
                cv2.circle(img, (lineInfo[4], lineInfo[5]),
                                 15, (0, 255, 0), cv2.FILLED)
                autopy.mouse.click()

    # 11. 计算帧率
    cTime = time.time()
    fps = 1 / (cTime - pTime)
    pTime = cTime
    cv2.putText(img, str(int(fps)), (20, 50), cv2.FONT_HERSHEY_PLAIN, 3,
                (255, 0, 0), 3)
    # 12. 展示画面
    cv2.imshow("Image", img)
    cv2.waitKey(1)

依赖安装说明

如果运行提示缺少依赖,执行以下命令安装:

pip install opencv-python mediapipe numpy autopy cvzone

注意autopy仅支持Python 3.8及以下版本,如果Python版本过高可以用pyautogui替代对应功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 04:48:01