import mediapipe as mp
import cv2
import time

gestures = ['None', 'rock', 'paper', 'scissors']
gesturestext = {'Rock', 'Paper', 'Scissors'}
usergesture = None
computergesture = None
cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands  # 选择策略 -- 监测手的模型
mpDraw = mp.solutions.drawingutils
handLmsStyle = mpDraw.DrawingSpec(color=(0, 0, 255), thickness=5)  # 设定点的样式 颜色 粗细,半径
handConStyle = mpDraw.DrawingSpec(color=(0, 255, 2), thickness=10)  # 设定线的样式 颜色 粗细,半径
pTime = 0
cTime = 0
hands = mpHands.Hands(staticimagemode=False,  # 影片 false 图片 True
                   maxnumhands=2,  # 最大手识别数量
                   modelcomplexity=1,  # 模型的复杂度 只能是 0 1 越高越准
                   mindetectionconfidence=0.9,  # 识别的精准度
                   mintracking_confidence=0.5)  # 追踪的严谨度

def getgesture(Lms):  # 获取手指的位置
    p0x = Lms.landmark[0].x
    p0_y = Lms.landmark[0].y

    p5_x = Lms.landmark[5].x
    p5_y = Lms.landmark[5].y

    p8_x = Lms.landmark[8].x
    p8_y = Lms.landmark[8].y
    p9_x = Lms.landmark[9].x
    p9_y = Lms.landmark[9].y

    p12_x = Lms.landmark[12].x
    p12_y = Lms.landmark[12].y
    p13_x = Lms.landmark[13].x
    p13_y = Lms.landmark[13].y

    p16_x = Lms.landmark[16].x
    p16_y = Lms.landmark[16].y
    p17_x = Lms.landmark[17].x
    p17_y = Lms.landmark[17].y

    p20_x = Lms.landmark[20].x
    p20_y = Lms.landmark[20].y

    # 通过两点距离公式,计算出两个点之间的距离
    distance_0_5 = ((p0_x - p5_x) ** 2 + (p0_y - p5_y) ** 2) ** 0.5
    distance_0_8 = ((p0_x - p8_x) ** 2 + (p0_y - p8_y) ** 2) ** 0.5
    distance_0_9 = ((p0_x - p9_x) ** 2 + (p0_y - p9_y) ** 2) ** 0.5
    distance_0_12 = ((p0_x - p12_x) ** 2 + (p0_y - p12_y) ** 2) ** 0.5
    distance_0_13 = ((p0_x - p13_x) ** 2 + (p0_y - p13_y) ** 2) ** 0.5
    distance_0_16 = ((p0_x - p16_x) ** 2 + (p0_y - p16_y) ** 2) ** 0.5
    distance_0_17 = ((p0_x - p17_x) ** 2 + (p0_y - p17_y) ** 2) ** 0.5
    distance_0_20 = ((p0_x - p20_x) ** 2 + (p0_y - p20_y) ** 2) ** 0.5
    # 通过距离并不能准确地判断手指是否屈伸,因为手可以前后移动,在屏幕中手的大小会改变
    # 所以通过从手的0点到手指的距离与食指与手掌的距离的比值进行判断,这样就可根据一个固定值来判断时候手指屈伸
    # 食指
    base_1 = distance_0_5 / 0.8
    # 中指
    base_2 = distance_0_9 / 0.8
    # 无名指
    base_3 = distance_0_13 / 0.8
    # 小指
    base_4 = distance_0_17 / 0.8

    if distance_0_8 > base_1 and distance_0_12 > base_2:
        if distance_0_16 > base_3 and distance_0_20 > base_4:
            user_gesture = 2
        elif distance_0_16 < base_3 and distance_0_20 < base_4:
            user_gesture = 3
        else:
            user_gesture = 0
    elif distance_0_8 < base_1 and distance_0_12 < base_2:
        if distance_0_16 < base_3 and distance_0_20 < base_4:
            user_gesture = 1
        else:
            user_gesture = 0
    else:
        user_gesture = 0
    return user_gesture
while True:
    ret, img = cap.read()  # 读取到的图片都是bgr的图片 ,故需要将其转换为RGB的图片

    if ret:
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        result = hands.process(imgRGB)  # 侦测
        # print(result.multi_hand_landmarks)  结果为 三个坐标 XYZ
        imgHeight = img.shape[0]  # 获取视窗的高度
        imgWidth = img.shape[1]  # 获取视窗的宽度
        if result.multi_hand_landmarks:
            for handLms in result.multi_hand_landmarks:  # 画出所有点和线
                mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS, handLmsStyle, handConStyle)
                gesture1 = get_gesture(handLms)
                cv2.putText(img, "you: " + gestures[gesture1], (int(0.1 * imgWidth), int(0.5 * imgHeight)),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.4, (50, 150, 50), 1)
                # enumerate函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,常用于for循环中
                for i, lm in enumerate(handLms.landmark):
                    xPos = int(lm.x * imgHeight)
                    yPos = int(lm.y * imgWidth)
                    cv2.putText(img, str(i), (xPos - 1, yPos + 1), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 200, 50), 1)
                    print(i, xPos, yPos)

    cTime = time.time()
    fps = 1 / (cTime - pTime)
    pTime = cTime
    cv2.putText(img, f"FPS : {int(fps)}", (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
    cv2.imshow('img', img)
    if cv2.waitKey(1) == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

# 上面代码中,handLms的属性特征是什么,怎么通过它知道当前遍历是第几只手
# handLms是一个HandLandmark对象,用于表示检测到的手的关键点信息。它包含属性landmark,表示手的21个关键点的位置信息,以及属性visibility,表示每个关键点的可见度。
# 可以通过遍历result.multi_hand_landmarks来获取每只检测到的手的HandLandmark对象,通过enumerate函数获取当前遍历的是第几只手的HandLandmark对象。
Python Mediapipe 手势识别:实时识别剪刀石头布

原文地址: https://www.cveoy.top/t/topic/op4s 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录