【CSDN 編者按】自己在家鍛煉時,我們很難知道自己的動作是否標準。本文作者用Python寫了一個可以檢測俯臥撐動作是否標準的程序,一起來看看他是怎么做的。
原文鏈接:https://aryanvij02.medium.com/push-ups-with-python-mediapipe-open-a544bd9b4351
https://github.com/aryanvij02/PushUpCounter
本文為CSDN翻譯,轉載請注明來源出處。
在新加坡軍隊中,有一種測試叫做IPPT(個人身體素質測試)。這個測試的困難不在于它對體力的要求有多高,而在于用來計算做俯臥撐和仰臥起坐次數的電子機器。
和大多數人一樣,我的俯臥撐動作總是不達標(根據機器的意見)。此外,由于缺乏參照機器標準的練習,許多NSMen(已經完成兩年強制性服役的人)在IPPT測試中都難以取得好成績。
因此,我決定使用mediapipe和OpenCV創建一個程序,跟蹤我們的俯臥撐動作,確保我們每一個俯臥撐動作都達標。
由mediapipe姿勢模塊檢測到的肢體關節
import cv2
import mediapipe as mp
import math
class poseDetector() :
def __init__(self, mode=False, complexity=1, smooth_landmarks=True,
enable_segmentation=False, smooth_segmentation=True,
detectionCon=0.5, trackCon=0.5):
self.mode = mode
self.complexity = complexity
self.smooth_landmarks = smooth_landmarks
self.enable_segmentation = enable_segmentation
self.smooth_segmentation = smooth_segmentation
self.detectionCon = detectionCon
self.trackCon = trackCon
self.mpDraw = mp.solutions.drawing_utils
self.mpPose = mp.solutions.pose
self.pose = self.mpPose.Pose(self.mode, self.complexity, self.smooth_landmarks,
self.enable_segmentation, self.smooth_segmentation,
self.detectionCon, self.trackCon)
def findPose (self, img, draw=True):
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.pose.process(imgRGB)
if self.results.pose_landmarks:
if draw:
self.mpDraw.draw_landmarks(img,self.results.pose_landmarks,
self.mpPose.POSE_CONNECTIONS)
return img
def findPosition(self, img, draw=True):
self.lmList = []
if self.results.pose_landmarks:
for id, lm in enumerate(self.results.pose_landmarks.landmark):
#finding height, width of the image printed
h, w, c = img.shape
#Determining the pixels of the landmarks
cx, cy = int(lm.x * w), int(lm.y * h)
self.lmList.append([id, cx, cy])
if draw:
cv2.circle(img, (cx, cy), 5, (255,0,0), cv2.FILLED)
return self.lmList
def findAngle(self, img, p1, p2, p3, draw=True):
#Get the landmarks
x1, y1 = self.lmList[p1][1:]
x2, y2 = self.lmList[p2][1:]
x3, y3 = self.lmList[p3][1:]
#Calculate Angle
angle = math.degrees(math.atan2(y3-y2, x3-x2) -
math.atan2(y1-y2, x1-x2))
if angle < 0:
angle += 360
if angle > 180:
angle = 360 - angle
elif angle > 180:
angle = 360 - angle
# print(angle)
#Draw
if draw:
cv2.line(img, (x1, y1), (x2, y2), (255,255,255), 3)
cv2.line(img, (x3, y3), (x2, y2), (255,255,255), 3)
cv2.circle(img, (x1, y1), 5, (0,0,255), cv2.FILLED)
cv2.circle(img, (x1, y1), 15, (0,0,255), 2)
cv2.circle(img, (x2, y2), 5, (0,0,255), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (0,0,255), 2)
cv2.circle(img, (x3, y3), 5, (0,0,255), cv2.FILLED)
cv2.circle(img, (x3, y3), 15, (0,0,255), 2)
cv2.putText(img, str(int(angle)), (x2-50, y2+50),
cv2.FONT_HERSHEY_PLAIN, 2, (0,0,255), 2)
return angle
def main():
detector = poseDetector()
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, img = cap.read() #ret is just the return variable, not much in there that we will use.
if ret:
img = detector.findPose(img)
cv2.imshow('Pose Detection', img)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
以上是這個程序的代碼。
上面的代碼來源于PoseModule.py,有以下幾個功能:
激活mediapipe的姿勢檢測模塊。
檢測人體。
根據模型找到人體上不同肢體關節的位置。(肢體顯示在上面的圖片中)。
查找關節之間的角度(取決于你選擇的關節)。對于我的俯臥撐程序,我選擇找到肘部、肩部和臀部的角度,因為這些對俯臥撐動作的標準至關重要。
接下來是實際的俯臥撐計數的代碼。我們使用PoseModule并確定一個俯臥撐合格與否的標準。
import cv2
import mediapipe as mp
import numpy as np
import PoseModule as pm
cap = cv2.VideoCapture(0)
detector = pm.poseDetector()
count = 0
direction = 0
form = 0
feedback = "Fix Form"
while cap.isOpened():
img = cap.read() #640 x 480
#Determine dimensions of video - Help with creation of box in Line 43
width = cap.get(3) # float `width`
height = cap.get(4) # float `height`
# print(width, height)
img = detector.findPose(img, False)
lmList = detector.findPosition(img, False)
# print(lmList)
if len(lmList) != 0:
elbow = detector.findAngle(img, 11, 13, 15)
shoulder = detector.findAngle(img, 13, 11, 23)
hip = detector.findAngle(img, 11, 23,25)
#Percentage of success of pushup
per = np.interp(elbow, (90, 160), (0, 100))
#Bar to show Pushup progress
bar = np.interp(elbow, (90, 160), (380, 50))
#Check to ensure right form before starting the program
if elbow > 160 and shoulder > 40 and hip > 160:
form = 1
#Check for full range of motion for the pushup
if form == 1:
if per == 0:
if elbow <= 90 and hip > 160:
feedback = "Up"
if direction == 0:
count += 0.5
direction = 1
else:
feedback = "Fix Form"
if per == 100:
if elbow > 160 and shoulder > 40 and hip > 160:
feedback = "Down"
if direction == 1:
count += 0.5
direction = 0
else:
feedback = "Fix Form"
# form = 0
print(count)
#Draw Bar
if form == 1:
(580, 50), (600, 380), (0, 255, 0), 3)
(580, int(bar)), (600, 380), (0, 255, 0), cv2.FILLED)
f'{int(per)}%', (565, 430), cv2.FONT_HERSHEY_PLAIN, 2,
0, 0), 2)
#Pushup counter
(0, 380), (100, 480), (0, 255, 0), cv2.FILLED)
str(int(count)), (25, 455), cv2.FONT_HERSHEY_PLAIN, 5,
0, 0), 5)
#Feedback
(500, 0), (640, 40), (255, 255, 255), cv2.FILLED)
feedback, (500, 40 ), cv2.FONT_HERSHEY_PLAIN, 2,
255, 0), 2)
counter', img)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
有個需要注意的地方在第17-21行。確定從相機捕捉到的圖像的分辨率,并在繪制俯臥撐計數的矩形時調整像素值,等等。(第68-82行)。
我們完成了!一個能確保動作標準的俯臥撐計數軟件。沒有完全俯下?不算數! 膝蓋放在了地上?不算數!
快樂的做俯臥撐吧!
《新程序員003》正式上市,50余位技術專家共同創作,云原生和數字化的開發者們的一本技術精選圖書。內容既有發展趨勢及方法論結構,華為、阿里、字節跳動、網易、快手、微軟、亞馬遜、英特爾、西門子、施耐德等30多家知名公司云原生和數字化一手實戰經驗!
大家好,這里是正經游戲,我是正經小弟。
S7世界總決賽剛剛落下帷幕,LOL全明星賽即將來臨。對于職業選手來說,常常會與各個服務器職業選手的進行對練,來調整自己的狀態。那么語言不通的情況下,他們是如何交流的呢?其實只要掌握這些老外才懂的游戲梗,你也可以在LOL外服中實現無障礙交流,甚至在他們噴你的時候華麗地懟回去。當然你也可以在國服假裝自己是一名老外擺脫噴子們的糾纏。
進入到游戲之中一般會有一個等待全兵出擊的時間,這個時候美服玩家都會互相閑聊問個好,順便展示一下自己得手速以及秀一下皮膚特效之類的!對話框會打很多問好,如果你不說話的話,他們就會開始質疑你的身份!或者覺得你不合群!
一般他們會打:hiho、holla這兩個都代表你好的問好的意思,有時候也會打LOL這個其實就是哈哈哈大笑的意思,這個時刻打這個一般也就是隨便笑笑沒什么,要不然就是你的皮膚太搞笑了。當然你也可以操作你的英雄,做出各種動作或者使用技能擊打你的隊友,這個時候他們可能會打:sup,這個代表:what’s up也就是嘿老兄你在干嘛的意思!
最通俗的也是使用率最高的就是nice,在LPL的比賽視頻中你也會經常看見隊員們在語音交流中使用nice,但是在美服大家一般會打N1或者是n1,也就是nice one的縮寫。
當你的操作非常亮眼的時候他們會打:OMG!這個不是咱們LPL的戰隊OMG,這個表示oh my god!表示吃驚。當你做出不為常人所理解時的舉動時他們也會說OMFG,這個是英文oh my fXXking god的縮寫,等同于咱們著的666。當然永久了也會有嘲諷的意味,多像是自嘲!也有可能你的操作出現重大失誤的時候,隊友也可能給你發這兩句!
而最樸實贊揚你實力強勁的話語就是:zzz是英文rullz的縮寫表示強大!當然zzz也有可能表示他要去睡覺了!就要看你們當時的游戲進程了!
這里的LOL自然不是指英雄聯盟,而是英文laughing out loud的縮寫表示大笑,各種情況都可,多數是嘲笑的意味,但其實也就是隨便笑笑!而Lmao是laughing my ass off的意思,表示滑稽的笑,多為嘲笑隊友的意思!比如你在游戲中使用了什么蹩腳的操作時,別人可能就會打Lmao來表示嘲笑你,而你的其他隊員可能就會附議LOLOLOLOL!
Rofl:是roll on floor laughing的意思,表示笑翻天了,這個多會用到嘲笑對方滑稽操作的時刻,比如你正在追一個人,然后他閃現撞墻了,你就可以打rofl表示笑翻天了!
w00t就是woot、what的意思!主要表示what和yeah的意思,例如驚嘆和興奮。這個詞大多數是你在做了較為華麗的錯誤操作之后隊友對你的質問,或者是敵方對你的嘲笑!
pffffff=whatever=隨便,可以理解為愛咋咋地!有時候英雄聯盟在進入游戲的時候會選擇位置,一旦確定進入游戲后就不能更改,這樣就會讓原本在該位置的玩家感到反感!這個時候就會打這個pffffff,你越是難受越是討厭這個人的話,f的個數就會越多!
n00b是英文newbie的縮寫意思是新人,不過事實上就是在說你菜!
玩游戲有的時候就難免會情緒激動,特別是當你的屏幕總是灰白色的時候,對于一個玩家來說簡直人生都慘淡了!特別是這個情況還是因為隊友而造成的時候就更加難以抒發自己郁悶的心情了!
比較常用的就是AFK:Away From Keyboard我不玩了的意思,我掛機!隊友不給力只能扔鍵盤!而有的玩家則會用Pls- Please請求你做一件事的意思,所以這種情況下你也可以請求你的隊友卸載游戲!最常見是"Pls delete your game"也可以理解為,你這種人就不配玩這個游戲!一般憤怒了都會這么說!
Delete:也是指刪除游戲的意思!不過單獨打Delete的話可能會表達自己的愧疚,就好比,我的鍋,這波我沒操作好,我刪除游戲!
WTF:這個就是大家所理解的那三個單詞啦!What the fXXK,如果團戰輸了是因為別人操作不當,你就可以打這個,表示:你看看你都做了什么!
NP:No Problem團戰不利,或者最后整局比賽盡力了之后但是仍舊輸了!你可以打NP來鼓勵隊友,表示你并不在意輸贏!盡力就好!OMW:On My Way正趕來,有時候團戰不期而遇,大家準備不充分,你也剛從基地水晶出來,這時候局面看似是劣勢你可以安慰隊友說你馬上就到!意思是你可以力挽狂瀾!
而Ty:Thank you就是謝謝的縮寫,Gj:Good Job干得好和n1的意思一樣!
小弟有話說:有了這本游戲交流寶典,在外服你也可以怒懟外國大神,再也不用看天書打架!也可以在國服假裝自己是一名老外,擺脫噴子們的糾纏。
那么問題來了:你還知道哪些老外才知道的梗和常見用語呢?
文/17173_筱筱