#はじめに
openposeで姿勢推定が単眼カメラ&CPUでできる!との噂を聞きつけ、早速やってみたくなりました。
tf-pose-estimation(https://github.com/ildoonet/tf-pose-estimation)
を使って、様々な記事を参考にしながら色々いじっていました。
動画から検出した骨格の情報を使って分析できないか(スポーツだったらフォームが正しいかだとか)と3Dの推定結果を出力したりしていましたが、どうも精度が出なかったので、2Dの推定結果(画像の上に描かれている節そのものの座標)を取り出して、分析出来る環境を作ることにしました。
#目次
- 環境設定
- 動画の2D姿勢推定データ出力
- 姿勢推移のグラフ化
- 今後の方針
- ご参考サイト
#環境設定
tf-pose-estimationの公式インストール手順(README)が参考になるかと思います(割愛)。
#動画の2D姿勢推定データ出力
大元のコードをforkして以下に公開しています。
「run_2dpose_get_data.py」が追加しているコードで、これを実行します。
事前にmovie > data というディレクトリを作成しておきます(ここに出力される)。
実行するときは以下のように行います。この場合では、toy.mp4という動画データを、1280x720にリサイズ、cmuモデルで実行、全体時間の80%まで処理、5frame間隔で処理、名前にcmuを付ける、となってます。
python run_2dpose_get_data.py --movie=./movie/toy.mp4 --resize 1280x720 --model cmu --frame 0.8 --frameterm 5 --dataname cmu
出力されるcsvのカラムは、「frame(nframe目の画像), human(どの人間か), point(節のID), x(画像のx座標), y(画像のy座標)」となっています。
(上記gifのようなnframe目の画像を出力するコードも中にあります。必要なければコメントアウトして下さい。)
frame | human | point | x | y |
---|---|---|---|---|
0 | 1 | 0 | 886 | 216 |
0 | 1 | 1 | 900 | 270 |
節のIDですが、以下のようになっているようです。
Nose = 0
Neck = 1
RShoulder = 2
RElbow = 3
RWrist = 4
LShoulder = 5
LElbow = 6
LWrist = 7
RHip = 8
RKnee = 9
RAnkle = 10
LHip = 11
LKnee = 12
LAnkle = 13
REye = 14
LEye = 15
REar = 16
LEar = 17
Background = 18
#姿勢推移のグラフ化
jupyter notebook環境で出力した2D推定結果をグラフ化をしました。
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from pylab import rcParams
rcParams['figure.figsize'] = 9, 5
%matplotlib notebook
#出力された2d推定結果を読み込み
df= pd.read_csv('_cmu_toy_2ddata.csv')
#2d推定座標をプロット
for i in range(19):
df1 = df[(df['human'] ==1) & (df['point'] == i)]
plt.plot(df1['x'], -df1['y'], label=i,marker = 'o')
plt.legend()
plt.show()
冒頭のイチロー君動画の各節の座標推移をグラフ化しました(縦軸、横軸は画像のピクセル座標)。確かに移動した方向に推移していることが確認できました。
注意点としては、複数人がいるような動画だとhumanのIDがframeによってはたまに入れ違いになったりとかします。
さらに何frame目かを横軸にして、縦軸をx,yから算出した距離($\sqrt{x^2 + y^2 }$)としたグラフを書きました。
少し下に下がっていくような傾向で、これは画像の左上が原点座標ですがここに近づいていることを示しています。
この例では単純な横移動ですが、人間の動きをこういったグラフで分析していく所存です。
for i in range(19):
df1 = df[(df['human'] ==1) & (df['point'] == i)]
y = np.sqrt((df1['x'])**2 + (df1['y'])**2)
plt.scatter(df1['flame']/30, y, label=i)
plt.show()
#学べたこと
- 実際に動かしてみると、動画によっては検出が難しいものもあったり(人が重なっているとか小さいとか)と色々学びがある
- コアな部分はディープラーニングで作られているものだが、そこから検出した座標なりをうまくエンジニアリングして、動作分析できるような使い方したい
- githubの使い方
#ご参考にさせていただいたサイト