|
1编写背景 在2024年的高效智能创意大赛中,有一个手势识别的任务,需要通过四足机器人的摄像头识别手势然后做出相应动作。在这我将介绍我的手势识别的思路和相关代码,已记录我那2024.7.21死去的比赛。2任务要求 比赛规则如下: 3问题分析与解决3.1MediaPipe介绍 MediaPipe是一款由GoogleResearch开发并开源的机器学习模型应用框架,专门用于实时流媒体的多模态处理。Mediapipehand库内置了已经训练好的手部检测和关键点识别模型,这些模型由Mediapipe团队使用大规模标注数据进行训练和优化,确保了高精度和高效能,开发者在使用时无需再进行模型训练,只需调用相关API即可实现手部检测功能。此外,Mediapipe还训练了获取手部21个地标的模型。这21个地标是预定义好的,具体位置如下:(1)手腕(1个地标): 0:手腕(2)拇指(4个地标): 1:拇指根部 2:拇指第一个关节 3:拇指第二个关节 4:拇指指尖(3)食指(4个地标): 5:食指根部 6:食指第一个关节 7:食指第二个关节 8:食指指尖(4)中指(4个地标): 9:中指根部 10:中指第一个关节 11:中指第二个关节 12:中指指尖(5)无名指(4个地标): 13:无名指根部 14:无名指第一个关节 15:无名指第二个关节 16:无名指指尖(6)小指(4个地标): 17:小指根部 18:小指第一个关节 19:小指第二个关节 20:小指指尖21个手部地标3.2MediaPipe的使用 此框架最大的好处是不需要自己去训练,模型已经被训练并封装好在python软件包里面,我们可以通过调用他的API很容易实现手部信息获取。3.2.1下载安装 要使用此包,则需要在python3.8环境(建议,比3.8低了没有此包,好像最高可以3.10?)下pipinstallmediapipe3.2.2调用方法和代码 话不多说,我直接给出完整的代码和详细注释:#-*-coding:utf-8-*-"""@By:ZhengXuan@Date:2024-4-21"""importcv2importmediapipeasmpimportnumpyasnpclassHandDetector:"""使用mediapipe库查找手。导出地标像素格式。添加了额外的功能。如查找方式,许多手指向上或两个手指之间的距离。而且提供找到的手的边界框信息。"""def__init__(self,mode=False,maxHands=2,detectionCon=0.5,minTrackCon=0.5):""":parammode:在静态模式下,对每个图像进行检测:parammaxHands:要检测的最大手数:paramdetectionCon:最小检测置信度:paramminTrackCon:最小跟踪置信度"""self.results=Noneself.mode=modeself.maxHands=maxHandsself.modelComplex=Falseself.detectionCon=detectionConself.minTrackCon=minTrackCon#初始化手部识别模型self.mpHands=mp.solutions.handsself.hands=self.mpHands.Hands(self.mode,self.maxHands,self.modelComplex,self.detectionCon,self.minTrackCon)self.mpDraw=mp.solutions.drawing_utils#初始化绘图器self.tipIds=[4,8,12,16,20]#指尖列表self.fingers=[]#存储手的状态self.lmList=[]#储检测到的手部的每个关键点的坐标deffindHands(self,img,draw=True):"""从图像(BRG)中找到手部。:paramimg:用于查找手的图像。:paramdraw:在图像上绘制输出的标志。:return:带或不带图形的图像"""imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#将传入的图像由BGR模式转标准的Opencv模式——RGB模式,self.results=self.hands.process(imgRGB)#处理图像,返回包含检测到的手部信息的结果。这个结果通常包含了手部的关键点坐标#画出手的关键点和线条ifself.results.multi_hand_landmarks:forhandLmsinself.results.multi_hand_landmarks:ifdraw:self.mpDraw.draw_landmarks(img,handLms,self.mpHands.HAND_CONNECTIONS)returnimgdeffindPosition(self,img,handNo=0,draw=True):"""查找单手的地标并将其放入列表中像素格式。还可以返回手部周围的边界框。:paramimg:要查找的主图像:paramhandNo:如果检测到多只手,则为手部id:paramdraw:在图像上绘制输出的标志。(默认绘制矩形框):return:像素格式的手部关节位置列表;手部边界框"""#保存关键点的像素坐标xList=[]yList=[]bbox=[]bboxInfo=[]#保存首部检测框信息self.lmList=[]ifself.results.multi_hand_landmarks:myHand=self.results.multi_hand_landmarks[handNo]forid,lminenumerate(myHand.landmark):#遍历手部关键点,id表示关键点下标,lm表示关键点对象h,w,c=img.shape#lm是存储的是关键点归一化(0~1)的相对位置,px,py=int(lm.x*w),int(lm.y*h)#转换为图像中的像素坐标xList.append(px)yList.append(py)self.lmList.append([px,py])ifdraw:cv2.circle(img,(px,py),5,(255,0,255),cv2.FILLED)#用红点标记关键点#获取手关键点的左上点和右下点xmin,xmax=min(xList),max(xList)ymin,ymax=min(yList),max(yList)#边界框信息存储boxW,boxH=xmax-xmin,ymax-yminbbox=xmin,ymin,boxW,boxH#边界框中心坐标cx,cy=bbox[0]+(bbox[2]//2),\bbox[1]+(bbox[3]//2)#id含义是指的手部最后一个关键点的下标bboxInfo={"id":id,"bbox":bbox,"center"cx,cy)}ifdraw:cv2.rectangle(img,(bbox[0]-20,bbox[1]-20),(bbox[0]+bbox[2]+20,bbox[1]+bbox[3]+20),(0,255,0),2)returnself.lmList,bboxInfodeffingcurved(self):"""查找除拇指外的四个手指弯曲状态计算方式:取出除了大拇指以外的四个手指指尖坐标a1、a2、a3、a4(对应地标8,12,16,20),然后取出地标为6,10,14,18的坐标b1、b2、b3、b4(即每个指尖以下第二个关节),通过比较指尖(a1、a2、a3、a4)到手腕地标(0)和指关节(b1、b2、b3、b4)到地标0的欧几里得距离,即可区分手指是否弯曲:return:弯曲手指的列表"""finger=[]foridinrange(1,5):point1=np.array((self.lmList[self.tipIds[id]][0],self.lmList[self.tipIds[id]][1]))point2=np.array((self.lmList[self.tipIds[id]-2][0],self.lmList[self.tipIds[id]-2][1]))point3=np.array((self.lmList[0][0],self.lmList[0][1]))ifnp.linalg.norm(point1-point3)
|
|