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

Python+OpenCV+MediaPipe手部追踪模块:NoneType无len()方法报错求助

问题分析与解决

问题描述

我用Python、OpenCV和MediaPipe开发手部追踪模块,准备后续集成到其他代码中,但运行时触发错误:

TypeError: object of type 'NoneType' has no len()

错误出在main函数的if len(lmList) != 0:这一行。

错误原因

  1. findPosition方法返回值缺失:该方法仅在检测到手部(self.results.multi_hand_landmarks不为空)时返回(self.lmList, bbox),未检测到手时没有return语句,默认返回None。当main函数调用len(lmList)时,lmList是None,自然无法计算长度。
  2. 返回值接收错误:findPosition返回的是包含关键点列表和边界框的元组,但main里直接把它赋值给lmList,就算检测到手,后续lmList[4]的写法也会出错,因为元组的第一个元素才是关键点列表。
  3. 未定义指尖ID常量:类中的fingersUp方法用到了self.tipIds,但初始化方法里没有定义这个属性,后续调用该方法会触发新错误。
  4. 未处理摄像头读取失败:cap.read()可能返回success=False(比如摄像头无法打开),后续处理空图像会引发潜在问题。

解决步骤

  1. 给findPosition添加默认返回值,未检测到手时返回空列表和空边界框,确保永远返回可迭代对象:
    在findPosition方法的末尾(if self.results.multi_hand_landmarks:块之外)添加:
    return self.lmList, bbox
    
  2. 修正main函数中对返回值的接收,同时处理摄像头读取失败的情况:
    success, img = cap.read()
    if not success:
        break
    img = detector.findHands(img)
    lmList, bbox = detector.findPosition(img)
    
  3. 在handDetector的__init__方法中添加指尖ID定义:
    self.tipIds = [4, 8, 12, 16, 20]  # 拇指、食指、中指、无名指、小指的指尖关键点ID
    
  4. 修正main函数中打印关键点的代码,因为lmList是关键点列表,直接判断长度后访问:
    if len(lmList) != 0:
        print(lmList[4])  # 打印拇指指尖的关键点信息
    

修复后的完整代码

import cv2
import mediapipe as mp
import time
import math


class handDetector():
    def __init__(self, mode=False, maxHands=1, modelComplexity=1, detectionCon=0.5, trackCon=0.5):
        self.mode = mode
        self.maxHands = maxHands
        self.modelComplex = modelComplexity
        self.detectionCon = detectionCon
        self.trackCon = trackCon
        self.tipIds = [4, 8, 12, 16, 20]  # 添加指尖ID定义

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.modelComplex, self.detectionCon, self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils

    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):
        xList = []
        yList = []
        bbox = []
        self.lmList = []
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNo]
            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), 5, (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, (bbox[0] - 20, bbox[1] - 20),
                              (bbox[2] + 20, bbox[3] + 20), (0, 255, 0), 2)
        
        return self.lmList, bbox  # 添加默认返回值

    def fingersUp(self):
        fingers = []
        # 拇指判断
        if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:
            fingers.append(1)
        else:
            fingers.append(0)
        # 其他四指判断
        for id in range(1, 5):
            if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[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 = math.hypot(x2 - x1, y2 - y1)
        return length, img, [x1, y1, x2, y2, cx, cy]

def main():
    pTime = 0
    cTime = 0
    cap = cv2.VideoCapture(0)
    detector = handDetector()
    while True:
        success, img = cap.read()
        if not success:  # 处理摄像头读取失败
            break
        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) & 0xFF == ord('q'):  # 添加退出逻辑
            break
    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:00:57