ishigenの技術ブログ

卓球 機械学習 競ぷろ

フォームの可視化と再現性の計算②

今回は前回の続きという形です。

ishigentech.hatenadiary.jp


前回は可視化する部分でグラフにプロットしていましたが、わかりにくいと思うので、GIF動画を作ってみます。

下記ページを参考にさせていただきました。
stmind.hatenablog.com

作成した動画

7つのスイングを重ねてGIF動画にしています。

コードについて


importと後々使う変数の定義

import json
import numpy as np
import matplotlib.pyplot as plt
import os
from pylab import *
from PIL import Image, ImageDraw
import numpy as np
import matplotlib.pyplot as plt

#全表示
#pairList = np.array([0,1,1,2,2,3,3,4,1,5,5,6,6,7,1,8,8,9,9,10,1,11,11,12,12,13,0,14,14,16,0,15,15,17])
#目と耳削除
pairList = np.array([0,1,1,2,2,3,3,4,1,5,5,6,6,7,1,8,8,9,9,10,1,11,11,12,12,13])
pairList = pairList.reshape(int(len(pairList) / 2), 2)
index = np.array([139,208,277,343,415,487,558])
colors = [(255.,     0.,    85.),
          (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.), 
          (255.,     0.,   170.), 
          (170.,     0.,   255.), 
          (255.,     0.,   255.), 
          (85.,     0.,   255.)]

ファイルを開いて変数に格納

data = np.array([])
path = 'パス'
files = os.listdir(path)
files = sort(files)
for file in files:
    filename = path + file
    f = open(filename)
    val = json.load(f)
    f.close()
    val = np.array(val['people'][0]['pose_keypoints_2d'])
    data = np.append(data, val)
data = data.reshape(len(files), 18, 3)

GIF動画を作成する関数の定義

def generateGIF(swing, path):
    images = []
    xlim = int(np.max(swing[:, :, :, 0]))
    ylim = int(np.max(swing[:, :, :, 1]))
    for i in range(len(swing[0, :, :, :])):
        im = Image.new('RGB', (xlim, ylim))#, (128, 128, 128))
        draw = ImageDraw.Draw(im)
        for d in swing:
            for pair in pairList:
                pt1 = (int(d[i, pair[0], 0]), int(d[i, pair[0], 1]))
                c1 = d[i, pair[0], 2]
                pt2 = (int(d[i, pair[1], 0]), int(d[i, pair[1], 1]))
                c2 = d[i, pair[1], 2]
                # 信頼度0.0の関節は無視
                if c1 == 0.0 or c2 == 0.0:
                    continue
                # 関節の描画
                color = tuple(list(map(int, colors[pair[0]])))        
                draw.line((pt1, pt2), fill=color, width=2)
                for line in range(1, 3):
                    draw.line((0,int(ylim/3)*line, xlim, int(ylim/3)*line), fill=(50,50,50), width=1)
                for line in range(1, 3):
                    draw.line((int(xlim/3)*line, 0, int(xlim/3)*line, ylim), fill=(50,50,50), width=1)
        images.append(im)
    images[0].save(path,
                   save_all=True, append_images=images[1:], optimize=False, duration=500, loop=0)

全体のデータからスイング部分を切り出し、両骨盤の平均位置を原点に調整して、GIF動画を作成

swingperframe = 20
swing = np.array([])
for i in index:
    swing = np.append(swing, data[i:i+swingperframe,:,:])
swing = swing.reshape(len(index),swingperframe, 18, 3)
    
for i, ivalue in enumerate(swing):
    for k, kvalue in enumerate(ivalue):
        originx = np.mean([kvalue[8, 0], kvalue[11, 0]])
        originy = np.mean([kvalue[8, 1],kvalue[11, 1]])
        swing[i, k, :, 0] -= originx
        swing[i, k, :, 1] -= originy
        for t, tvalue in enumerate(kvalue):
            if tvalue[2] == 0:
                swing[i, k, t, 0] = 0
                swing[i, k, t, 1] = 0
        
swing[:, :, :, 0] -= np.min(swing[:, :, :, 0])
swing[:, :, :, 1] -= np.min(swing[:, :, :, 1])

generateGIF(swing, 'ファイル名.gif')


以上です。やってることは簡単なことしかやっていませんが、グラフなんかよりは見やすくなったと思います。