803浏览
查看: 803|回复: 1

[项目分享] Mind+Python+Mediapipe项目——AI健身之开合跳

[复制链接]
本帖最后由 云天 于 2021-12-3 23:02 编辑

【项目背景】
要说燃脂运动,相信很多人首先会想到“波比跳”,当然啦对于很多新手来说做波比跳并不是特别的容易,所以他们就会选择一种相对比较简单但效果同样很不错的——开合跳!长时间锻炼,需要毅力坚持。但也可以让枯燥的运动,变的有乐趣。今天这个项目让人工智能陪我们一起快乐健身。

【项目设计】
2021_0109_d728a471g00qmngmq0592d200ia00a7g00ia00a7.gif

使用Mind+Python模式下加载Google的开源Mediapipe人工智能算法库,识别人体姿态,利用动作中两臂与躯体的夹角及两腿夹角的变化来判断开合跳次数,并通过Pinpong库控制LED灯实时显示次数。
其中使用到了Python文件操作功能,边制作边学习。

【测试程序】
QQ截图20211202112854.png

使用网络视频进行合跳测试,标注关键信息点。
  1. import numpy as np
  2. import time
  3. import cv2
  4. import PoseModule as pm
  5. cap = cv2.VideoCapture('hetiao4.mp4')
  6. detector = pm.poseDetector()
  7. count = 0
  8. dir = 0
  9. pTime = 0
  10. success=True
  11. while success:
  12.   success, img = cap.read()
  13.   if success:
  14.     img = cv2.resize(img, (640, 480))
  15.     img = detector.findPose(img, False)
  16.     lmList = detector.findPosition(img, False)
  17.    
  18.     if len(lmList) != 0:
  19.         # 双腿
  20.         angle1 = detector.findAngle(img, 28, 23, 27)
  21.         # 双臂
  22.         angle2 = detector.findAngle(img, 15, 11, 23)
  23.         angle3 = detector.findAngle(img, 16, 12, 24)
  24.         print(angle1,angle2,angle3)
  25.     cTime = time.time()
  26.     fps = 1 / (cTime - pTime)
  27.     pTime = cTime
  28.     cv2.putText(img, str(int(fps)), (50, 100), cv2.FONT_HERSHEY_PLAIN, 5,(255, 0, 0), 5)
  29.     cv2.imshow("Image", img)
  30.     cv2.waitKey(1)
  31. cap.release()
  32. cv2.destroyAllWindows()
复制代码


【获取标准数据】
QQ截图20211202114133.png



通过对标准动作检测,获取动作标准数据,并存储在数据文件中。
  1. import numpy as np
  2. import time
  3. import cv2
  4. import PoseModule as pm
  5. import os,sys
  6. cap = cv2.VideoCapture('ht.mp4')
  7. detector = pm.poseDetector()
  8. count = 0
  9. dir = 0
  10. pTime = 0
  11. success=True
  12. angle1=[]
  13. angle2=[]
  14. angle3=[]
  15. def max_min(a):
  16. h = []
  17. l = []
  18. for i in range(1, len(a)-1):
  19.     if(a[i-1] < a[i] and a[i+1] < a[i]):
  20.         h.append(a[i])
  21.     elif(a[i-1] > a[i] and a[i+1] > a[i]):
  22.         l.append(a[i])
  23. if(len(h) == 0):
  24.     h.append(max(a))
  25. if(len(l) == 0):
  26.     l.append(min(a[a.index(max(a)):]))
  27. print(int(np.mean(h)),int(np.mean(l)))
  28. return(int(np.mean(h)),int(np.mean(l)))
  29. while success:
  30.   success, img = cap.read()
  31.   if success:
  32.     img = cv2.resize(img, (640, 480))
  33.     img = detector.findPose(img, False)
  34.     lmList = detector.findPosition(img, False)
  35.    
  36.     if len(lmList) != 0:
  37.         # 双腿
  38.         angle1.append( detector.findAngle(img, 28, 23, 27))
  39.         # 双臂
  40.         angle2.append( detector.findAngle(img, 15, 11, 23))
  41.         angle3.append( detector.findAngle(img, 16, 12, 24))
  42.         
  43.         
  44.     cTime = time.time()
  45.     fps = 1 / (cTime - pTime)
  46.     pTime = cTime
  47.     cv2.putText(img, str(int(fps)), (50, 100), cv2.FONT_HERSHEY_PLAIN, 5,(255, 0, 0), 5)
  48.     cv2.imshow("Image", img)
  49.     cv2.waitKey(1)
  50. a1,b1=max_min(angle1)
  51. a2,b2=max_min(angle2)
  52. a3,b3=max_min(angle3)
  53. fo = open("data.txt", "w")
  54. fo.write(str(a1)+","+str(b1)+","+str(a2)+","+str(b2)+","+str(a3)+","+str(b3))
  55. # 关闭文件
  56. fo.close()
  57. cap.release()
  58. cv2.destroyAllWindows()
复制代码
调用函数计算出两臂、两腿夹角的最大角度和最小角度,并通过文件操作将数据写入“data.txt”文件中。

  1. a1,b1=max_min(angle1)
  2. a2,b2=max_min(angle2)
  3. a3,b3=max_min(angle3)
  4. fo = open("data.txt", "w")
  5. fo.write(str(a1)+","+str(b1)+","+str(a2)+","+str(b2)+","+str(a3)+","+str(b3))
复制代码

【开合跳计数程序】
1、读取标准数据文件,并将数据转换为列表
  1. from pathlib import Path
  2. import sys
  3. my_file = Path("data.txt")
  4. if not my_file.is_file():
  5.     print("没有标准数据文件")
  6.     sys.exit()
  7. else:
  8.     f = open("data.txt",encoding = "utf-8")
  9.     data=f.read()
  10.     data=data.split(",")
  11.     f.close()
复制代码
2、利用标准数据对动作进行判定,是否完成一次完整动作,并在屏幕显示
  1. # 双腿夹角
  2.         angle1 = detector.findAngle(img, 28, 23, 27)
  3.         # 双臂与躯干夹角
  4.         angle2 = detector.findAngle(img, 15, 11, 23)
  5.         angle3 = detector.findAngle(img, 16, 12, 24)
  6.         #print(angle1,angle2,angle3)
  7.         per1 = np.interp(angle1, (int(data[1]), int(data[0])), (0, 100))
  8.         per2 = np.interp(angle2, (int(data[3]), int(data[2])), (100, 0))
  9.         per3 = np.interp(angle3, (int(data[5]), int(data[4])), (0, 100))
  10.         light = int(np.interp(angle1, (220, 310), (119, 0)))
  11.         # print(angle, per)
  12.         # 计算个数
  13.         per=per1+per2+per3
  14.         #print(per1,per2,per3)
  15.         if per == 300:
  16.             
  17.             if dir == 0:
  18.                 count += 0.5
  19.                 dir = 1
  20.         if per == 0:
  21.             
  22.             if dir == 1:
  23.                 count += 0.5
  24.                 dir = 0
  25.         #print(count)
  26.         cv2.putText(img, str(int(count)), (45, 460), cv2.FONT_HERSHEY_PLAIN, 7,(255, 0, 0), 8)
复制代码




【LED炫灯显示计数】
1、Pinpong库初始化
  1. from pinpong.board import Board,Pin,NeoPixel
  2. NEOPIXEL_PIN = Pin.P0
  3. PIXELS_NUM = 120 #灯数
  4. Board("microbit").begin()  #初始化
  5. npX = NeoPixel(Pin(NEOPIXEL_PIN), PIXELS_NUM)
复制代码
2、亮灯显示计数

  1. light = int(np.interp(int(count)), (0, 120), (0, 120)))
  2.         npX.rainbow(0,light,0,0x0000FF)
复制代码
【完整程序】
QQ截图20211203225033.png

  1. import numpy as np
  2. import time
  3. import cv2
  4. import PoseModule as pm
  5. from pathlib import Path
  6. import sys
  7. my_file = Path("data.txt")
  8. if not my_file.is_file():
  9.     print("没有标准数据文件")
  10.     sys.exit()
  11. else:
  12.     f = open("data.txt",encoding = "utf-8")
  13.     data=f.read()
  14.     data=data.split(",")
  15.     f.close()
  16. from pinpong.board import Board,Pin,NeoPixel
  17. NEOPIXEL_PIN = Pin.P0
  18. PIXELS_NUM = 120 #灯数
  19. Board("microbit").begin()  #初始化
  20. npX = NeoPixel(Pin(NEOPIXEL_PIN), PIXELS_NUM)
  21. cap = cv2.VideoCapture('d.mp4')
  22. cap.set(3, 640)
  23. cap.set(4, 480)
  24. detector = pm.poseDetector()
  25. count = 0
  26. dir = 0
  27. pTime = 0
  28. success=True
  29. while success:
  30.   success, img = cap.read()
  31.   if success:
  32.     img = cv2.resize(img, (640, 480))
  33.     img = detector.findPose(img, False)
  34.     lmList = detector.findPosition(img, False)
  35.    
  36.     if len(lmList) != 0:
  37.         # 双腿夹角
  38.         angle1 = detector.findAngle(img, 28, 23, 27)
  39.         # 双臂与躯干夹角
  40.         angle2 = detector.findAngle(img, 15, 11, 23)
  41.         angle3 = detector.findAngle(img, 16, 12, 24)
  42.         #print(angle1,angle2,angle3)
  43.         per1 = np.interp(angle1, (int(data[1]), int(data[0])), (0, 100))
  44.         per2 = np.interp(angle2, (int(data[3]), int(data[2])), (100, 0))
  45.         per3 = np.interp(angle3, (int(data[5]), int(data[4])), (0, 100))
  46.         
  47.         # print(angle, per)
  48.         # 计算个数
  49.         per=per1+per2+per3
  50.         #print(per1,per2,per3)
  51.         if per == 300:
  52.             
  53.             if dir == 0:
  54.                 count += 0.5
  55.                 dir = 1
  56.         if per == 0:
  57.             
  58.             if dir == 1:
  59.                 count += 0.5
  60.                 dir = 0
  61.         #print(count)
  62.         light = int(np.interp(int(count)), (0, 120), (0, 120)))
  63.         npX.rainbow(0,light,0,0x0000FF)
  64.         cv2.putText(img, str(int(count)), (45, 460), cv2.FONT_HERSHEY_PLAIN, 7,(255, 0, 0), 8)
  65.     cTime = time.time()
  66.     fps = 1 / (cTime - pTime)
  67.     pTime = cTime
  68.     cv2.putText(img, str(int(fps)), (50, 100), cv2.FONT_HERSHEY_PLAIN, 5,(255, 0, 0), 5)
  69.     cv2.imshow("Image", img)
  70.     cv2.waitKey(1)
  71. cap.release()
  72. cv2.destroyAllWindows()
复制代码
【演示视频】

【PoseModule.py】
以上文件所引用的“PoseModule.py”文件。
  1. import math
  2. import mediapipe as mp
  3. import cv2
  4. class poseDetector():
  5.     def __init__(self, mode=False, upBody=False, smooth=True,
  6.                  detectionCon=0.85, trackCon=0.5):
  7.         self.mode = mode
  8.         self.upBody = upBody
  9.         self.smooth = smooth
  10.         self.detectionCon = detectionCon
  11.         self.trackCon = trackCon
  12.         self.mpDraw = mp.solutions.drawing_utils
  13.         self.mpPose = mp.solutions.pose
  14.         self.pose = self.mpPose.Pose(self.mode, self.upBody, self.smooth,
  15.                                      self.detectionCon, self.trackCon)
  16.     def findPose(self, img, draw=True):
  17.         imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  18.         self.results = self.pose.process(imgRGB)
  19.         if self.results.pose_landmarks:
  20.             if draw:
  21.                 self.mpDraw.draw_landmarks(img, self.results.pose_landmarks,
  22.                                            self.mpPose.POSE_CONNECTIONS)
  23.         return img
  24.     def findPosition(self, img, draw=True):
  25.         self.lmList = []
  26.         if self.results.pose_landmarks:
  27.             for id, lm in enumerate(self.results.pose_landmarks.landmark):
  28.                 h, w, c = img.shape
  29.                 # print(id, lm)
  30.                 cx, cy = int(lm.x * w), int(lm.y * h)
  31.                 self.lmList.append([id, cx, cy])
  32.                 if draw:
  33.                     cv2.circle(img, (cx, cy), 5, (255, 0, 0), cv2.FILLED)
  34.         return self.lmList
  35.     def midpoint(self,img,p1,p2,draw=True):
  36.         x1, y1 = self.lmList[p1][1:]
  37.         x2, y2 = self.lmList[p2][1:]
  38.         x3=int((x1+x2)/2)
  39.         y3=int((y1+y2)/2)
  40.         if draw:
  41.          cv2.circle(img, (x3, y3), 10, (0, 0, 255), cv2.FILLED)
  42.          cv2.circle(img, (x3, y3), 15, (0, 0, 255), 2)
  43.         point={"x":x3,"y":y3}
  44.         return point
  45.     def findAngle(self, img, p1, p2, p3, draw=True):
  46.         # Get the landmarks
  47.         x1, y1 = self.lmList[p1][1:]
  48.         x2, y2 = self.lmList[p2][1:]
  49.         x3, y3 = self.lmList[p3][1:]
  50.         # Calculate the Angle
  51.         angle = math.degrees(math.atan2(y3 - y2, x3 - x2) -
  52.                              math.atan2(y1 - y2, x1 - x2))
  53.         if angle < 0:
  54.             angle += 360
  55.         # print(angle)
  56.         # Draw
  57.         if draw:
  58.             cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255), 3)
  59.             cv2.line(img, (x3, y3), (x2, y2), (255, 255, 255), 3)
  60.             cv2.circle(img, (x1, y1), 10, (0, 0, 255), cv2.FILLED)
  61.             cv2.circle(img, (x1, y1), 15, (0, 0, 255), 2)
  62.             cv2.circle(img, (x2, y2), 10, (0, 0, 255), cv2.FILLED)
  63.             cv2.circle(img, (x2, y2), 15, (0, 0, 255), 2)
  64.             cv2.circle(img, (x3, y3), 10, (0, 0, 255), cv2.FILLED)
  65.             cv2.circle(img, (x3, y3), 15, (0, 0, 255), 2)
  66.             cv2.putText(img, str(int(angle)), (x2 - 50, y2 + 50),
  67.                         cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 255), 2)
  68.         return angle
复制代码








西门吹风  学徒

发表于 2022-4-26 11:03:39

想问下, if per == 300: 这个300是什么意思的,我看了好久看不懂呢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail