首先大家应该需要对于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() 
                
发表回复