当前位置: 首页 > 后端技术 > Python

Python玩人工智能:你能做几个引体向上?

时间:2023-03-26 15:09:58 Python

谷歌发布了一个开源、跨平台、可定制的机器学习解决方案工具包,为在线流媒体提供机器学习解决方案(当然也可以用于普通视频、图片等)。有兴趣的同学可以打开这个网站了解详情:https://mediapipe.dev/提供了手势、人体姿态、人脸、物体等识别和跟踪功能,并提供了编程语言的工具,如适用于iOS和Android平台的C++、Python、JavaScript封装和解决方案,今天我们就来看看如何使用MediaPipe提供的人体姿态识别功能,用Python编程完成一个“上拉检测”程序。电脑需要安装Python3,建议安装Python3.8.x版本。另外需要安装Opencv-Python、MediaPipe和numpy几个工具包,可以使用pip安装:pipinstallmediapipenumpyopencv-python我的电脑是Python3.8.3,各个工具包版本为:mediapipe==0.8.3.1numpy==1.20.2opencv-python==4.5.1.48写一个poseutil.py模块。这个postutil模块有一个PoseDetector类,提供检测人体姿态、获取人体姿态数据、获取人体关节角度的方法。代码如下,具体见代码注释:importcv2importmediapipeasmpimportmathclassPoseDetector():'''人体姿态检测类'''def__init__(self,static_image_mode=False,upper_body_only=False,smooth_landmarks=True,min_detection_confidence=0.5,min_tracking_confidence=0.5):'''初始化:paramstatic_image_mode:是否为静态图片,默认为No:paramupper_body_only:是否为上半身,默认为No:paramsmooth_landmarks:设置为true减少抖动:parammin_detection_confidence:人体检测模型的最小值设置信度值,默认为0.5:parammin_tracking_confidence:位置信息标记的最小设置信度值,默认为0.5'''self.static_image_mode=static_image_modeself.upper_body_only=upper_body_onlyself.smooth_landmarks=smooth_landmarksself.min_detection_confidence=min_detection_confidenceself.min_tracking_confidence=min_tracking_confidence#创建一个用于检测人体的姿势对象姿势self.pose=mp.solutions.pose.Pose(self.static_image_mode,self.upper_body_only,self.smooth_landmarks,self.min_detection_confidence,self.min_tracking_confidence)deffind_pose(self,img,draw=True):'''检测姿势方法:paramimg:一帧图像:paramdraw:是否绘制人体姿态节点和连接图:return:processedimage'''imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#pose.process(imgRGB)会识别这一帧的人体姿态数据图片,保存到self.resultsself.results=self.pose.process(imgRGB)ifself.results.pose_landmarks:ifdraw:mp.solutions.drawing_utils.draw_landmarks(img,self.results.pose_landmarks,mp.solutions.pose.POSE_CONNECTIONS)returnimgdeffind_positions(self,img):'''获取人体姿态数据:paramimg:一帧图像:paramdraw:是否绘制人体姿态节点和连接图:return:人体姿态数据list'''#人体姿态数据列表,每个成员由3个数字组成:id,x,y#id表示人体的一个关节点,x和y表示坐标位置数据self.lmslist=[]ifself.results.pose_landmarks:forid,lminenumerate(self.results.pose_landmarks.landmark):h,w,c=img.shapecx,cy=int(lm.x*w),int(lm.y*h)self.lmslist.append([id,cx,cy])返回self.lmslistdeffind_angle(self,img,p1,p2,p3,draw=True):'''获取人体pose中p1-p2-p3三个点的夹角:paramimg:一帧图像:paramp1:第一个点:paramp2:第二个points:paramp3:第三个points:paramdraw:是否绘制3个点的连线图:return:angle'''x1,y1=self.lmslist[p1][1],self.lmslist[p1][2]x2,y2=self.lmslist[p2][1],self.lmslist[p2][2]x3,y3=self.lmslist[p3][1],self.lmslist[p3][2]#用三角函数公式得到3个点p1-p2-p3,以p2为角度的角度值,在0-180度之间angle=int(math.degrees(math.atan2(y1-y2,x1-x2)-数学.atan2(y3-y2,x3-x2)))如果角度<0:角度=角度+360如果角度>180:angle=360-绘制时的角度:cv2.圆(img,(x1,y1),8,(0、255、255),cv2。填充)cv2。circle(img,(x2,y2),15,(255,0,255),cv2.FILLED)cv2.circle(img,(x3,y3),8,(0,255,255),cv2.FILLED)cv2.line(img,(x1,y1),(x2,y2),(255,255,255,3))cv2.line(img,(x2,y2),(x3,y3),(255,255,255,3))#cv2.putText(img,str(angle),(x2-50,y2+50),cv2.FONT_HERSHEY_SIMPLEX,2,(0,255,255),2)returnangle写另一个posetracking。py代码,在这段代码中,调用poseutil.py的PoseDetector类提供的方法,从上拉视频(或实时摄像头视频)中获取人体左右手肘的弯曲角度,假设我们用肘部角度从170度(完全放松时)到20度(引体向上拉起时)来识别一个标准引体向上,这样我们就可以检测出标准引体向上完成的次数。从上图中我们可以看出,11、13、15这三个点是左肩、肘和手腕的节点,而12、14、16是右手的节点。完整代码如下:importcv2importnumpyasnpfromposeutilimportPoseDetector#opencv打开一个视频cap=cv2.VideoCapture('mp4/1.mp4')#创建PoseDetector类的对象detector=PoseDetector()#变量为方向和完成次数dir=0count=0whileTrue:#读取视频图片帧成功,img=cap.read()ifsuccess:#检测视频图片帧中的人体姿势img=detector.find_pose(img,draw=True)#getlistofhumanposesDatalmslist=detector.find_positions(img)#右手肘的角度right_angle=detector.find_angle(img,12,14,16)#检测右手肘在170到20度的弯曲程度right_per=np.interp(right_angle,(20,170),(100,0))#进度条高度数据right_bar=np.interp(right_angle,(20,170),(200,400))#使用opencv绘制进度条并写下右肘弯曲度cv2。矩形(img,(1200,200),(1220,400),(0,255,0),3)cv2.rectangle(img,(1200,int(right_bar)),(1220,400),(0,255,0),cv2.FILLED)cv2.putText(img,str(int(right_per))+'%',(1190,450),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,255),2)#左肘角left_angle=detector.find_angle(img,11,13,15)left_per=np.interp(left_angle,(20,170),(100,0))left_bar=np.interp(left_angle,(20,170),(200,400))cv2.rectangle(img,(500,200),(520,400),(0,255,0),3)cv2.rectangle(img,(500,int(left_bar)),(520,400),(0,255,0),cv2.FILLED)cv2.putText(img,str(int(left_per))+'%',(490,450),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,255),2)#检测次数,我这里设置的是20%到80%,算是一个if(left_per>=80andright_per>=80):ifdir==0:count=count+0.5dir=1if(left_per<=20andright_per<=20):ifdir==1:count=count+0.5dir=0#显示视频的完成数cv2.putText(img,str(int(count)),(1000,100),cv2.FONT_HERSHEY_SIMPLEX,3,(0,255,255),4)cv2.imshow('Image',img)else:breakk=cv2.waitKey(1)ifk==或d('q'):breakcap.release()cv2.destroyAllWindows()运行代码,我们会看到2个弯头和2个进度条的角度变化和完成次数,用它来检测标准引体向上完成次数