首先大家应该需要对于python,opencv和MediaPipe有一定的了解
最近在用MediaPipe Hands试着判断一些简单的手势中有一点小思路,大致如下:
人们判断一只手掌所做出的手势主要是通过观察哪些手指竖直/弯曲,以及观察手指之间是否相接触。比如“OK”手势,就是大拇指与食指指尖相碰,剩余三根手指弯曲。
(放一张MediaPipe手部21个关键点的图)
通过观察可以发现,对于除大拇指外的四根手指,我们仅需要通过对于它们指尖到指根的距离,一旦小于某个值,便可以认定弯曲。
另外对于大拇指,我们仅需特别判断一下4点与0点的距离是否会小于3点与0点的距离差便可判断其是否弯曲
那这样就可以开始写代码了
主要核心就是这几句,其实就是用勾股定理罢了
判断大拇指是否弯曲
#获得掌根和大拇指中间指节的坐标
three = (int(hand_list.landmark[3].x*w),int(hand_list.landmark[3].y*h))
zero = (int(hand_list.landmark[0].x*w),int(hand_list.landmark[0].y*h))
#勾股定理
length_compare = int(three[0]-zero[0])**2 + int(three[1]-zero[1])**2
length_compare = int(math.sqrt(length_compare))
#对大拇指判断 4-0的距离
thumb_tip = (int(hand_list.landmark[4].x*w),int(hand_list.landmark[4].y*h))
length_damuzhi = int(thumb_tip[0]-zero[0])**2 + int(thumb_tip[1]-zero[1])**2
length_damuzhi = int(math.sqrt(length_damuzhi))
这样当length_damuzhi < length_compare
就能判断大拇指是弯曲的了
对于剩下的四根手指同理
for id in range(0,4) :
#对于指尖和指根距离判断
finger_tip = (int(hand_list.landmark[tipsid[id]].x*w),int(hand_list.landmark[tipsid[id]].y*h))
finger_bottom (int(hand_list.landmark[tipsid[id]-3].x*w),int(hand_list.landmark[tipsid[id]-3].y*h))
length = int(finger_tip[0]-finger_bottom[0])**2 + int(finger_tip[1]-finger_bottom[1])**2
length = int(math.sqrt(length))
经过尝试发现当指尖和指根距离差小于50的时候便认为它们弯曲
这样就能判断每根手指的竖直/弯曲情况了
附上一个能判断数字1-5的小程序吧(理论上通过这个思路可以判断相当多的手势)
import mediapipe as mp
import cv2
import math
cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands
hand = mpHands.Hands()
mphanddraw = mp.solutions.drawing_utils
tipsid = [8,12,16,20] #除大拇指外每个手指指尖的坐标
while True:
f , img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
result = hand.process(RGBImage)
if result.multi_hand_landmarks :
hands_data = result.multi_hand_landmarks
fingerlist = []
for hand_list in hands_data:
h,w,c = img.shape
#获得掌根和大拇指中间指节的坐标,来判断手掌的长度
three = (int(hand_list.landmark[3].x*w),int(hand_list.landmark[3].y*h))
zero = (int(hand_list.landmark[0].x*w),int(hand_list.landmark[0].y*h))
#勾股定理
length_compare = int(three[0]-zero[0])**2 + int(three[1]-zero[1])**2
length_compare = int(math.sqrt(length_compare))
#对大拇指判断 4-0的距离
thumb_tip = (int(hand_list.landmark[4].x*w),int(hand_list.landmark[4].y*h))
length_damuzhi = int(thumb_tip[0]-zero[0])**2 + int(thumb_tip[1]-zero[1])**2
length_damuzhi = int(math.sqrt(length_damuzhi))
#弯曲的话就往列表里记录0
if length_damuzhi<length_compare :
fingerlist.append(0)
else :
fingerlist.append(1)
#再用一个循环判断剩余四根手指是否弯曲
for id in range(0,4) :
finger_tip = (int(hand_list.landmark[tipsid[id]].x*w),int(hand_list.landmark[tipsid[id]].y*h))
finger_bottom = (int(hand_list.landmark[tipsid[id]-3].x*w),int(hand_list.landmark[tipsid[id]-3].y*h))
length = int(finger_tip[0]-finger_bottom[0])**2 + int(finger_tip[1]-finger_bottom[1])**2
length = int(math.sqrt(length))
if length<50 :
fingerlist.append(0)
else:
fingerlist.append(1)
totalfinger = fingerlist.count(1) #数有几个手指竖着判断为数字几
cv2.putText(img,str(totalfinger),(50,50),cv2.FONT_HERSHEY_PLAIN,5,(255,255,255),5)
# 这个只是绘制手指关节的,可以忽略这段代码
for id,lm in enumerate(hand_list.landmark):
cx,cy = int(lm.x * w),int(lm.y * h)
cv2.circle(img,(cx,cy),5,(255,0,255),cv2.FILLED)
# cv2.putText(img,str(id),(cx,cy),cv2.FONT_HERSHEY_PLAIN,1,(0,255,255),1)
mphanddraw.draw_landmarks(img,hand_list,mpHands.HAND_CONNECTIONS,)
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release()
cv2.destroyAllWindows()
发表回复