Python Mediapipe 手势识别:实时识别剪刀石头布
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对象。
原文地址: https://www.cveoy.top/t/topic/op4s 著作权归作者所有。请勿转载和采集!