加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入

基于計算機視覺(opencv)的運動計數(shù)(運動輔助)系統(tǒng)-源碼+注釋+報告

08/22 11:42
1284
服務(wù)支持:
技術(shù)交流群

完成交易后在“購買成功”頁面掃碼入群,即可與技術(shù)大咖們分享疑惑和經(jīng)驗、收獲成長和認(rèn)同、領(lǐng)取優(yōu)惠和紅包等。

虛擬商品不可退

當(dāng)前內(nèi)容為數(shù)字版權(quán)作品,購買后不支持退換且無法轉(zhuǎn)移使用。

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論
放大
實物圖
相關(guān)方案
  • 方案介紹
    • 基于計算機視覺(opencv)的運動計數(shù)系統(tǒng)
  • 相關(guān)文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

基于計算機視覺(opencv)的運動計數(shù)系統(tǒng)

Notice:本文的源碼均為開源代碼,(由于文章篇幅有限,文章中的源碼均是偽代碼),需要源碼的小伙伴可以先關(guān)注我,私信或評論與我聯(lián)系,大家一起學(xué)習(xí)

1、項目簡介

1.1研究背景及意義

隨著全民健身熱潮的興起,越來越多的人積極參加健身鍛煉,但由于缺乏科學(xué)的運動指導(dǎo),使健身難以取得相應(yīng)的效果。據(jù)市場調(diào)查顯示,沒有產(chǎn)品可以自動分析健身運動并提供指導(dǎo)。而近年深度神經(jīng)網(wǎng)絡(luò)在人體姿態(tài)識別上已經(jīng)取得了巨大的成功,針對這個現(xiàn)象,本課程設(shè)計制作了一個基于MediaPipe的運動計數(shù)系統(tǒng)。該系統(tǒng)主要內(nèi)容包括對于單人人體關(guān)鍵點的檢測,關(guān)鍵點的連接,以及運動健身關(guān)鍵點的角度變化來實現(xiàn)對俯臥撐和深蹲的計數(shù)。

1.2項目設(shè)計方案

系統(tǒng)框架如下圖所示,本系統(tǒng)將視頻或者攝像頭實時捕捉的俯臥撐或者深蹲的視頻一步步進行處理,首先我們獲得俯臥撐和深蹲的訓(xùn)練樣本,之后將訓(xùn)練樣本轉(zhuǎn)換為k-NN分類訓(xùn)練集,將預(yù)測的landmarks轉(zhuǎn)移儲存至CSV文件中,之后進行KNN算法分類。最后實現(xiàn)重復(fù)計數(shù)將結(jié)果顯示在面板中。
在這里插入圖片描述

具體方案如下:
(1)收集目標(biāo)練習(xí)的圖像樣本并對其進行姿勢預(yù)測
(2)將獲得的姿態(tài)標(biāo)志轉(zhuǎn)換為適合 k-NN 分類器的數(shù)據(jù),并使用這些數(shù)據(jù)形成訓(xùn)練集
(3)執(zhí)行分類本身,然后進行重復(fù)計數(shù)
(4)面板顯示結(jié)果
在這里插入圖片描述

2、程序設(shè)計

2.1 程序設(shè)計方案
2.1.1 建立訓(xùn)練樣本

為了建立一個好的分類器,應(yīng)該為訓(xùn)練集收集適當(dāng)?shù)臉颖荆豪碚撋厦總€練習(xí)的每個最終狀態(tài)大約有幾百個樣本(例如,俯臥撐和深蹲的“向上”和“向下”位置),收集的樣本涵蓋不同的攝像機角度、環(huán)境條件、身體形狀和運動變化,這一點很重要,能做到這樣最好。但實際中如果嫌麻煩的話每種狀態(tài)15-25張左右都可以,然后拍攝角度要注意多樣化,最好每隔15度拍攝一張。
具體代碼如下:

訓(xùn)練樣本圖片格式
 Required structure of the images_in_folder:
   fitness_poses_images_in/
     squat_up/
       image_001.jpg
       image_002.jpg
       ...
     squat_down/
       image_001.jpg
       image_002.jpg
2.1.2 獲取歸一化landmarks

要將樣本轉(zhuǎn)換為 k-NN 分類器訓(xùn)練集,在給定圖像上運行 BlazePose 模型,并將預(yù)測的landmarks轉(zhuǎn)儲到 CSV 文件中。此外,Pose Classification Colab (Extended)通過針對整個訓(xùn)練集對每個樣本進行分類,提供了有用的工具來查找異常值(例如,錯誤預(yù)測的姿勢)和代表性不足的類別(例如,不覆蓋所有攝像機角度)。之后,能夠在任意視頻上測試該分類器。fitness_poses_csvs_out文件夾里面的csv文件就是使用拍攝的訓(xùn)練樣本提取出來的深蹲和俯臥撐的訓(xùn)練集文件,有了該文件后就可以直接運行本項目。生成的CSV文件如圖:
在這里插入圖片描述
具體代碼如下:

class FullBodyPoseEmbedder(object):
    Converts 3D pose landmarks into 3D embedding."""
    def __init__(self, torso_size_multiplier):
         
           乘數(shù)應(yīng)用于軀干以獲得最小的身體尺寸
        
    def __call__(self, landmarks):
        
           Normalizes pose landmarks and converts to embedding
           獲取 landmarks.歸一化姿勢landmarks并轉(zhuǎn)換為embedding
           具有形狀 (M, 3) 的姿勢embedding的 Numpy 數(shù)組,其中“M”是“_get_pose_distance_embedding”中定義的成對距離的數(shù)量。
           return embedding
    def _normalize_pose_landmarks(self, landmarks):
           Normalizes landmarks translation and scale.歸一化landmarks的平移和縮放
      
          return landmarks
    def _get_pose_center(self, landmarks):
          Calculates pose center as point between hips.將姿勢中心計算為臀部之間的點。
          return center
    def _get_pose_size(self, landmarks, torso_size_multiplier):
           Calculates pose size.計算姿勢大小。
           它是下面兩個值的最大值:
              * 軀干大小乘以`torso_size_multiplier`
              * 從姿勢中心到任何姿勢地標(biāo)的最大距離
           這種方法僅使用 2D landmarks來計算姿勢大小分別計算
           臀部中心、兩肩中心、軀干尺寸作為最小的身體尺寸到姿勢中心的最大距離.
           return max(torso_size * torso_size_multiplier, max_dist)
    def _get_pose_distance_embedding(self, landmarks):
           Converts pose landmarks into 3D embedding.
           將姿勢landmarks轉(zhuǎn)換為 3D embedding.
           我們使用幾個成對的 3D 距離來形成姿勢embedding。 所有距離都包括帶符號的 X 和 Y 分量。
           我們使用不同類型的對來覆蓋不同的姿勢類別。 Feel free to remove some or add new.
2.1.3 使用KNN算法分類

用于姿勢分類的 k-NN 算法需要每個樣本的特征向量表示和一個度量來計算兩個這樣的向量之間的距離,以找到最接近目標(biāo)的姿勢樣本。
為了將姿勢標(biāo)志轉(zhuǎn)換為特征向量,使用預(yù)定義的姿勢關(guān)節(jié)列表之間的成對距離,例如手腕和肩膀、腳踝和臀部以及兩個手腕之間的距離。由于該算法依賴于距離,因此在轉(zhuǎn)換之前所有姿勢都被歸一化以具有相同的軀干尺寸和垂直軀干方向。
可以根據(jù)運動的特點選擇所要計算的距離對(例如,引體向上可能更加關(guān)注上半身的距離對)。
在這里插入圖片描述
為了獲得更好的分類結(jié)果,使用不同的距離度量調(diào)用了兩次 KNN 搜索:
首先,為了過濾掉與目標(biāo)樣本幾乎相同但在特征向量中只有幾個不同值的樣本(這意味著不同的彎曲關(guān)節(jié)和其他姿勢類),使用最小坐標(biāo)距離作為距離度量,然后使用平均坐標(biāo)距離在第一次搜索中找到最近的姿勢簇。
最后,應(yīng)用指數(shù)移動平均(EMA) 平滑來平衡來自姿勢預(yù)測或分類的任何噪聲。不僅搜索最近的姿勢簇,而且計算每個姿勢簇的概率,并將其用于隨著時間的推移進行平滑處理。

class PoseSample(object):
    獲取捕捉到的圖像landmarks
class PoseClassifier(object):
    根據(jù)捕捉到圖像的landmarks,對圖像進行分類
       *根據(jù)提供的訓(xùn)練圖片,將訓(xùn)練的圖片分類,例如蹲起或者俯臥撐,分為兩類,放入不同文件夾
       *根據(jù)不同類別的圖片分別生成.csv的文件
    訓(xùn)練圖片的文件結(jié)構(gòu):
          neutral_standing.csv
          pushups_down.csv
          pushups_up.csv
          squats_down.csv
          ...
    csv文件結(jié)構(gòu):
          sample_00001,x1,y1,z1,x2,y2,z2,....
          sample_00002,x1,y1,z1,x2,y2,z2,....
        return pose_samples
    def find_pose_sample_outliers(self):
        針對整個數(shù)據(jù)庫對每個樣本進行分類
           *找出目標(biāo)姿勢中的異常值
           *為目標(biāo)找到最近的姿勢
           *如果最近的姿勢具有不同的類別或多個姿勢類別被檢測為最近,則樣本是異常值
        return outliers
    def __call__(self, pose_landmarks):
        對給定的姿勢進行分類。
        分類分兩個階段完成:
           *按 MAX 距離選取前 N 個樣本。 它允許刪除與給定姿勢幾乎相同但有一些關(guān)節(jié)在向一個方向彎曲的樣本。
           *按平均距離選擇前 N 個樣本。 在上一步移除異常值后, 我們可以選擇在平均值上接近的樣本。
           *按平均距離過濾,去除異常值后,我們可以通過平均距離找到最近的姿勢
        return result
2.1.4 計數(shù)實現(xiàn)

為了計算重復(fù)次數(shù),該算法監(jiān)控目標(biāo)姿勢類別的概率。深蹲的“向上”和“向下”終端狀態(tài):
當(dāng)“下”位姿類的概率第一次通過某個閾值時,算法標(biāo)記進入“下”位姿類。
一旦概率下降到閾值以下(即起身超過一定高度),算法就會標(biāo)記“向下”姿勢類別,退出并增加計數(shù)器。
為了避免概率在閾值附近波動(例如,當(dāng)用戶在“向上”和“向下”狀態(tài)之間暫停時)導(dǎo)致幻像計數(shù)的情況,用于檢測何時退出狀態(tài)的閾值實際上略低于用于檢測狀態(tài)退出的閾值。

動作計數(shù)器
class RepetitionCounter(object):
    # 計算給定目標(biāo)姿勢類的重復(fù)次數(shù)

    def __init__(self, class_name, enter_threshold=6, exit_threshold=4):
        self._class_name = class_name

        # 如果姿勢通過了給定的閾值,那么我們就進入該動作的計數(shù)
        self._enter_threshold = enter_threshold
        self._exit_threshold = exit_threshold

        # 是否處于給定的姿勢
        self._pose_entered = False

        # 退出姿勢的次數(shù)
        self._n_repeats = 0

    @property
    def n_repeats(self):
        return self._n_repeats

    def __call__(self, pose_classification):
        # 計算給定幀之前發(fā)生的重復(fù)次數(shù)
        # 我們使用兩個閾值。首先,您需要從較高的位置上方進入姿勢,然后您需要從較低的位置下方退出。
        # 閾值之間的差異使其對預(yù)測抖動穩(wěn)定(如果只有一個閾值,則會導(dǎo)致錯誤計數(shù))。

        # 參數(shù):
        #   pose_classification:當(dāng)前幀上的姿勢分類字典
        #         Sample:
        #         {
        #             'squat_down': 8.3,
        #             'squat_up': 1.7,
        #         }

        # 獲取姿勢的置信度.
        pose_confidence = 0.0
        if self._class_name in pose_classification:
            pose_confidence = pose_classification[self._class_name]

        # On the very first frame or if we were out of the pose, just check if we
        # entered it on this frame and update the state.
        # 在第一幀或者如果我們不處于姿勢中,只需檢查我們是否在這一幀上進入該姿勢并更新狀態(tài)
        if not self._pose_entered:
            self._pose_entered = pose_confidence > self._enter_threshold
            return self._n_repeats

        # 如果我們處于姿勢并且正在退出它,則增加計數(shù)器并更新狀態(tài)
        if pose_confidence < self._exit_threshold:
            self._n_repeats += 1
            self._pose_entered = False

        return self._n_repeats
2.1.5 界面實現(xiàn)

利用Python的QtDesinger來進行設(shè)計界面,添加攝像頭捕捉區(qū)域,以及捕捉到的圖像的最高點和最低點的變化曲線區(qū)域,和計算運動次數(shù)并顯示的區(qū)域。整體采用了水平的布局,添加按鈕以及界面關(guān)閉提示。攝像頭則采用英文狀態(tài)下,輸入“q”來進行退出,方法很簡單。具體運行結(jié)果如下圖:
在這里插入圖片描述

class Ui_MainWindow(object):
    def __init__(self):
        self.RowLength = 0

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1213, 680)
        設(shè)置窗體固定大小
        MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        圖片區(qū)域
        self.centralwidget.setObjectName("centralwidget")
        設(shè)置窗口大小
        self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_1)
設(shè)置布局
        設(shè)置窗口大小及顏色
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(6)
        設(shè)置1列的寬度
        設(shè)置2列的寬度
        設(shè)置3列的寬度
        設(shè)置4列的寬度
        設(shè)置5列的寬度
        設(shè)置6列的寬度
        self.tableWidget.setRowCount(self.RowLength)
        隱藏垂直表頭
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.raise_()
        self.scrollArea_4.setWidget(self.scrollAreaWidgetContents_4)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
獲取當(dāng)前工程文件位置
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        設(shè)置UI界面標(biāo)題為:基于姿態(tài)估計的運動計數(shù)系統(tǒng)
        設(shè)置左側(cè)UI界面橫坐標(biāo)為:最高點與最低點高度變化曲線
        設(shè)置左側(cè)UI界面標(biāo)題為:攝像頭捕捉
        設(shè)置右側(cè)UI界面標(biāo)題為:計數(shù)區(qū)域
        self.scrollAreaWidgetContents_1.show()
2.1.6 入口函數(shù)main

有兩種選擇模式,可以從本地上傳視頻進行檢測,也可以調(diào)用攝像頭進行實時檢測。具體的模式選擇可以通過輸入選擇的數(shù)字進行選擇:

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    調(diào)用主窗口函數(shù)
    調(diào)用UI界面
    while True:
        menu = int(input("請輸入檢測模式(數(shù)字):1. 從本地導(dǎo)入視頻檢測t2. 調(diào)用攝像頭檢測n"))
        if 輸入數(shù)字為1:
            flag = int(input("請輸入檢測的運動類型(數(shù)字):1. 俯臥撐t2. 深蹲n"))
            video_path = input("請輸入視頻路徑:")
            tp.trainset_process(flag)
            vp.video_process(video_path, flag)
            continue
        elif 輸入數(shù)字為2:
            flag = int(input("請輸入檢測的運動類型(數(shù)字):1. 俯臥撐t2. 深蹲n"))
            print("n按英文狀態(tài)下的q或esc退出攝像頭采集")
            tp.trainset_process(flag)
            vc.process(flag)
            continue
        elif 輸入數(shù)字為3:
            break
        else:
            print("輸入錯誤,請重新輸入!")
            continue
    sys.exit(app.exec_())

3、成果展示

由我們組成員分別對系統(tǒng)的鏡頭采集功能和視頻采集功能進行了實驗,當(dāng)選擇鏡頭采集功能時,利用opencv調(diào)用電腦攝像頭進行采集畫面。
在這里插入圖片描述
如圖所示為打開攝像頭界面,左邊是攝像頭的捕捉區(qū)域,并附帶檢測屏幕中人體最高點和最低點的曲線變化圖;當(dāng)曲線發(fā)生階躍性突變,且達到一定的峰值,攝像頭中的右上方的數(shù)字就會進行計數(shù)。上圖選擇的模式為蹲起計數(shù),同時我們也添加了俯臥撐計數(shù)的模式,只需在模式選擇下進行調(diào)整即可。模型會根據(jù)選擇的模式,自動進行分類。
在這里插入圖片描述
上圖可以清晰的看出測試者在經(jīng)過蹲起測試之后截下的圖片,一共測試了16次蹲起,曲線形象的記錄下了每一次的過程,藍色表示最高點的變化,黃色表示最低點的變化。
在這里插入圖片描述

上圖采用的是對視頻中的運動進行計數(shù),與攝像頭調(diào)用是類似的方法,此方法可以直接生成結(jié)果視頻,可視化的效果對計數(shù)結(jié)果進行驗證。

4、結(jié)論及展望

本設(shè)計實現(xiàn)的人體姿態(tài)識別網(wǎng)絡(luò)模型雖然可以在一般設(shè)備上運行,并且基本達到了實時檢測的效果,但總體來說檢測速度還是偏慢。目前所達到的水平還有待提升,需要在保證精度的情況下,進一步進行輕量化。

本文中的人體姿態(tài)識別的過程中攝像頭不移動并且固定在一個位置,因此只能檢測到特定區(qū)域的人體動作姿態(tài),如果人體所在位置超出該攝像頭的覆蓋范圍,那么系統(tǒng)就無法識別人體的動作姿態(tài)。所以下一步可以考慮將攝像機安裝在機器人上,通過激光雷達和目標(biāo)跟蹤等技術(shù)控制機器人對人體進行實時跟蹤,通過移動的攝像頭實時捕捉人體的動作姿態(tài),可以在更大范圍內(nèi)更加有效的識別人體動作姿態(tài)。

至此,文章主要內(nèi)容介紹完畢,項目除上述主要模塊以外,還包含訓(xùn)練數(shù)據(jù)集等文件,需要源碼的朋友關(guān)注再私信與我聯(lián)系,本人看到一定回復(fù)?。。?!

博客主頁:https://blog.csdn.net/weixin_51141489,需要源碼或相關(guān)資料實物的友友請關(guān)注、點贊,私信吧!

  • 聯(lián)系方式.txt

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
LTC6991HS6#TRPBF 1 Linear Technology LTC6991 - TimerBlox: Resettable, Low Frequency Oscillator; Package: SOT; Pins: 6; Temperature Range: -40&deg;C to 125&deg;C
$15.23 查看
AD9361BBCZ 1 Analog Devices Inc RF Agile Transceiver

ECAD模型

下載ECAD模型
$269.47 查看
NC7S14M5X 1 onsemi TinyLogic HS Inverter with Schmitt Trigger Input, 3000-REEL

ECAD模型

下載ECAD模型
$0.28 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜