博客專欄

        EEPW首頁 > 博客 > 教你一招!如何用技術實現時序羽毛球動作預測

        教你一招!如何用技術實現時序羽毛球動作預測

        發布人:AI科技大本營 時間:2022-01-16 來源:工程師 發布文章

        作者 | 李秋鍵

        出品 | AI科技大本營(ID:rgznai100)

        引言:隨著計算機視覺領域中視頻動作識別技術的發展,體育動作識別研究在統計運動動作特點、運動學研究、體育教學展示等方面的應用越來越廣泛。對于各種球類比賽,依據比賽類型,  可以將它們的結構特征分為時間和比分兩種類型。時間類型的體育項目如籃球、足球和橄欖球等,在比賽過程中沒有屬于某一方球員專門的區域,雙方球員在位置上處于混合交錯狀態,在一定時間間隔內通過團隊合作來取得比賽的勝利。比分類型的項目包括網球、羽毛球、乒乓球等,比賽時雙方球員始終在屬于自己的區域內運動,和對手在位置上處于對峙狀態,這種類型通常是球員經過自身水平的發揮來贏取比賽。觀看該類比賽時,觀眾往往會關注球員的動作特點。

        在羽毛球比賽中,運動員的動作姿態信息可為理解比賽過程、發現球員動作特點提供重要線索。羽毛球運動與排球、網球和乒乓球運動特點相似,均滿足馬爾可夫過程條件,比賽中運動員的每次擊球動作在瞬間完成。為了更好地輔助教練或觀眾理解并把握羽毛球視頻中球員動作等關鍵信息,實現對羽毛球運動員的動作智能識別是有意義的。

        目前計算機視覺技術在視頻動作識別方向的相關研究已經取得重大突破,但大多是針對不同日常動作的廣義性動作識別,缺乏針對羽毛球視頻動作識別的相關研究。若能對羽毛球視頻中的擊球動作進行時序定位并且能比較準確地判斷出羽毛球視頻中的擊球動作類型,則可為觀眾提供各類擊球動作類型的視頻集錦。此外,在體育視頻分析領域中,也可根據羽毛球的動作分類遷移至網球等項目,因它們的比賽形式與羽毛球有許多相同之處,更容易進行運動特征的遷移。

        故今天我們將使用torch搭建LSTM實現對羽毛球動作的實時訓練并預測,本文將其分為數據集制作、數據處理、模型搭建以及可視化幾個步驟,模型在訓練2000輪實現效果如下如下(左側為當前動作,右側為預測出的未來10幀后的羽毛球動作): 

        1.png


        羽毛球動作識別發展介紹

        針對羽毛球的擊球動作識別,Chu 等人采用了基于姿態識別的方法,從球員的邊界框提取方向梯度直方圖 HOG,并在 HOG 基礎上基于支持向量機 SVM對擊球動作進行分類,但其使用的訓練和測試數據是擊球瞬間的單個圖像,而對于擊球姿態十分相似的不同擊球動作很可能會混淆,如殺球與高遠球,平抽與吊球。Careelmont對壓縮羽毛球視頻的鏡頭進行分類,并通過檢測羽毛球的移動軌跡來識別擊球動作。Ramasinghe 等提出了一種基于密集軌跡和軌跡對齊的 HOG 特征的羽毛球視頻動作識別方法,將球員擊球動作分為正手擊球、反手擊球、殺球和其他類型,但 HOG 本身不具有尺度不變性,且由于梯度的性質,HOG 對噪點相當敏感。楊靜等人在體育視頻時常具有像素品質欠佳、非靜態視頻及圖像的分辨率較低的問題背景下,提出一種基于光流的運動描述符,并通過檢測關鍵音頻元素捕獲球員的揮拍擊球圖像,最后采用支持向量機,對運動員的三種典型揮拍動作——上揮拍、左揮拍、右揮拍進行分類。Wang 等提出了一種基于身體傳感器網絡的雙層隱馬爾可夫模型分類算法來識別羽毛球擊球類型,但其針對于傳感器捕獲的擊球狀態數據,并不適用于對視頻中的羽毛球動作進行有效識別。Rahmad 等人比較了 AlexNet、GoogLeNet、VggNet-16 和 VggNet-19 四種不同的深度卷積預訓練模型在對羽毛球比賽圖像進行分類時的表現,以識別運動員的不同動作,最終表明 GoogLeNet 的分類準確率最高,但其針對的仍是羽毛球比賽擊球瞬間的靜態圖像,未能對羽毛球動作元視頻進行動作分類識別。


        羽毛球動作預測搭建

        為了更好的研究對羽毛球視頻動作識別,我們這里實現對羽毛球視頻球員擊球動作進行時域定位。

        這里程序的設計分為以下幾個步驟,分別為數據集制作、數據處理、模型搭建以及可視化幾個步驟。

        2.1 骨骼數據集提取

        這里我們將準備好的視頻素材放置項目文件下,使用data_deal.py提取骨骼點存儲。針對2.mp4視頻文件使用openpose逐幀提取骨骼數據并存入txt文件中。代碼如下:

        parser = argparse.ArgumentParser(description='Action Recognition by OpenPose')
        parser.add_argument('--video', help='Path to video file.')
        args = parser.parse_args()
        # 導入相關模型
        estimator = load_pretrain_model('VGG_origin')
        # 參數初始化
        realtime_fps = '0.0000'
        start_time = time.time()
        fps_interval = 1
        fps_count = 0
        run_timer = 0
        frame_count = 0
        # 讀寫視頻文件
        cap =cv.VideoCapture("2.mp4")
        #video_writer = set_video_writer(cap, write_fps=int(7.0))
        # 保存關節數據的txt文件,用于訓練過程(for training)
        f = open('origin_data.txt', 'a+')
        num=0
        while cv.waitKey(1) < 0:
            has_frame, show = cap.read()
            if has_frame:
                fps_count += 1
                frame_count += 1
                # pose estimation
                humans = estimator.inference(show)
                # get pose info
                pose = TfPoseVisualizer.draw_pose_rgb(show, humans)  # return frame, joints, bboxes, xcenter
                #video_writer.write(show)
                if len(pose[-1])==36:
                    num+=1
                    print(num)
                    # 采集數據,用于訓練過程(for training)
                    joints_norm_per_frame = np.array(pose[-1]).astype(np.str)
                    f.write(' '.join(joints_norm_per_frame))
                    f.write('\n')
                cv.imshow("tets",show)
                cv.waitKey(1)
            else:
                break
        cap.release()
        f.close()

        2.png

        2.2 數據處理

        通過對數據觀察發現,由于拍攝的視頻遮擋較多,部分肢體提取為0會較大的影響模型效果,這里將這幾個部位去除。代碼如下:

        f=open('origin_data.txt')
        text=f.read()
        f.close()
        datasets=[]
        text=text.split("\n")
        for i in text:
            temp=i.split(" ")
            temp1=[]
            state=True
            for j in range(len(temp)):
                try:
                    temp1.append(float(temp[j]))
                except:
                    pass
            if len(temp1) == 36:
                temp1.pop(28)
                temp1.pop(28)
                temp1.pop(30)
                temp1.pop(30)
                for t in temp1:
                    if t==0.:
                        state=False
                if state:
                    datasets.append(temp1)
        flap=30#
        x_data = datasets[:-1-flap]
        y_data=datasets[flap:-1]
        n=len(x_data)

        2.3 LSTM模型搭建和訓練

        這里設置LSTM層神經元64,設置損失函數為為MSE誤差函數,優化器為adam優化器,迭代次數為100輪,并將其損失圖動態繪制。代碼如下:

        times=[]
        losss=[]
        nums=0
        Epoch=100
        correct=0
        for k in range(Epoch):
            for i in range(n):
                x_np=np.array(x_data[i],dtype='float32')#此時x的維度為1維
                y_np=np.array(y_data[i],dtype='float32')
                #需要把x維度擴充到三個維度,[batch,time_step,input_size]
                x=variable(torch.from_numpy(x_np[np.newaxis,:,np.newaxis]))
                y=variable(torch.from_numpy(y_np[np.newaxis,:,np.newaxis]))
                prediction=rnn(x)
                if prediction.flatten().data.numpy().any==y.flatten().data.numpy().any:
                    correct+=1
                loss=loss_func(prediction,y)
                optim.zero_grad()
                loss.backward()
                optim.step()
                nums += 1
                accuracy=float(correct/nums)
        print("|Epoch:",k,"|step:",nums,"|loss:",loss.data.numpy(),"|accuracy:%.4f"%accuracy)
                times.append(nums)
                losss.append(float(loss.data))
                plt.plot(times,losss)
                plt.pause(0.05)

        3.png

        2.4 模型可視化

        根據預測出的骨骼坐標,定義基本骨骼連接方法和顏色,同時這里還要考慮到已經去除的骨骼,最終代碼如下:

        import cv2
        def draw(test):
            back=cv2.imread("back.jpg")
            image_h, image_w ,c= back.shape
            centers = {}
            CocoColors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0],
                          [0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255],
                          [170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85], [255, 0, 85]]
            CocoPairs = [
                (1, 2), (1, 5), (2, 3), (3, 4), (5, 6), (6, 7), (1, 8), (8, 9), (9, 10), (1, 11),
                (11, 12), (12, 13), (1, 0), (0, 14), (14, 15),  (5, 15)
            ]#修改了
            for pos in range(0,16):
                center = (int((test[2*pos] * (image_w//2) + 0.5)), int((test[2*pos+1] * (image_h//2) )))
                centers[pos] = center
                cv2.circle(back, center, 3, CocoColors[pos], thickness=3, lineType=8, shift=0)
            for pair_order, pair in enumerate(CocoPairs):
                cv2.line(back, centers[pair[0]], centers[pair[1]], CocoColors[pair_order], 3)

        4.png

        完整代碼:

        https://download.csdn.net/download/qq_42279468/72398200

        李秋鍵,CSDN博客專家,CSDN達人課作者。碩士在讀于中國礦業大學,開發有taptap競賽獲獎等。

        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。

        紅外遙控器相關文章:紅外遙控器原理
        聲控燈相關文章:聲控燈原理


        關鍵詞: AI

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 鸡西市| 青浦区| 板桥市| 本溪市| 隆子县| 大悟县| 聂拉木县| 武平县| 江孜县| 靖州| 临安市| 宁德市| 莱阳市| 丹江口市| 宁乡县| 蒙山县| 南安市| 涟水县| 蒙城县| 鄂尔多斯市| 兰考县| 南陵县| 青阳县| 朝阳区| 金川县| 衡东县| 宿松县| 达日县| 武宁县| 宜君县| 象山县| 云南省| 抚州市| 辽中县| 武穴市| 林芝县| 铜川市| 榆社县| 诸暨市| 邹城市| 桂阳县|