AI(人工知能)骨格認識によるランニングフォーム分析

昨年あたりから生成AIが急拡大、第4次AIブームと言われています。私もその波に乗り遅れまいと少しかじってみました。

先ずはフォームの現状把握。トレーニングやるにも弱点補強から。プログラミングの視点で、やってきたことを少々マニアックにご紹介したいと思います。

画像処理ライブラリのOpenCVとAIライブラリのMediaPipeというオープンソースを使って、ランニングフォームの解析をしてみた。

着地時の膝下角度

注目したのは、着地時の膝下角度(図左)。膝からの鉛直線を基準とし、膝〜足首の直線が、どれだけ開いているかです。ランニングフォームを見直そう(下半身編vol.1)で触れましたが、この角度が大きければ大きいほど踵での「ブレーキ」がかかる「ヒートストライク」。角度がゼロ、鉛直方向に着地すれば「ミッドフット」着地となり、接地時間が短くなり転がるタイヤをイメージしたような走りとなる。

膝の曲げ角度の推移/増減割合(着地時〜重心真下時)

もう1つ着目したのが膝の曲げ角度。

重心真下に足がある瞬間は、膝がある程度曲がっていて、その瞬間から蹴り出そうとしている。この「膝の曲がり」が、単に腰が沈んでいるから曲がっているのかどうかがポイントになります。

基準となるのが、着地時点での曲げ角度。それと比べて、さらに(おおよそ20%以上)曲がっていたらとしたら、おそらく着地時点で膝下を前方向に出しすぎているか。真下時点で腰が沈んでいるか。あるいはその両方かと言えそうです。

エリートランナーは、真下(図右)で160度以下まで曲がることもあるのですが、着地時での角度(図左)も、それなりに曲がっている(膝下を降り出していない)ので、相対的(差)としては10%程度に収まっている傾向にあります。着地の反発エネルギーに負けない程度に筋力と上手く調整し、そのまま蹴り出す力に変えているのだと思われます。

腰が落ちているランナーは、着地してから、その足が身体の重心真下に来た時点(図右)で、さらに大きく曲がっています。逆に尻とハムストリングで何とか踏ん張ってこの角度が維持されれば、腰高となり、体幹(バネ)を使って地面からの反発エネルギーを推進力に活かせます。沈まなければ、その分、接地時間を節約できます。また姿勢の観点からも、骨盤が地面と並行に立ち、腕の振りを活かし下半身と連携することができます。

ただ膝の曲げ角度は個人差があるのも確か。着地の反発を最大限に得られる膝の曲げ具合というのは、特にエリートランナーや経験あるランナーは意識せずとも自然と身についています。単純に曲がるから腰が落ちているということではなく、正面または真後ろからの映像から着地軸足の反対側が落ちていないか?左右差を見る必要がありそうです。この測定も今後やっていきたいと思います。

ということで、相対的な角度(真下時点の膝角度の、着地時点の膝角度に対する増減の割合)を参考指標になるのではと考えた次第です。

この2点を、可視化するため、動画の中から特定箇所を①プロットし、②数値化していく作業となります。

①についてはオープンソースとして公開されているライブラリ(冒頭のOpenCvとMediaPipe)を使ってAI認識し、

②はさまざまな手順(アルゴリズム)を踏むことになります。

2つの箇所の数値化

ここで、一番悩んだことは、この②番目「着地時点」「真下時点」をどう捕捉し、数値化するかという点です。

動画はフレームの連続であり、一般的なiphone動画(MOVファイル)では、「着地」が何フレーム目になるのか?といった具合です。ちなみに動画が5秒だとすると枚の300フレームから構成されます。

そこで、足首の高さを計測することで、その高さが最下位の位置であれば一番下に足が来ていることになり、またその直前が着地のタイミング(フレーム)だと言えそうです。その瞬間のフレームの膝の曲げ角度や膝下角度を取得します。

接地の間は、足首の高さが底辺値で推移する。→その直前が「着地のタイミング」

足首位置のサイクルの動きに着目すると、

y5=足首の高さは、一番低い位置で一定に推移する時間帯は、着地してから蹴り出すまでの「接地時間帯」である。

したがって、その直前のフレームを着地タイミングとして捉えればよさそう。

そこで、実際の足の動きをプロットし(数値化)CSVに表してみました。

  • deg_knee : 膝曲げ角度
  • deg_hizasita : 膝下の対鉛直角度
  • deg_kosi_heel : 腰から足首線の対鉛直角度
  • y5 : 画面下端から足首までの高さ。
  • x4 : 足首のx座標値
  • y5_scalede :y 5の値を1から100の分布にスケールした値

着地のタイミングは、わずか5秒の動画でも、5〜6回巡ってくるので、対象フレームを絞り込むため、次の条件を全て満たす形でフィルターリングします。

  1. y5_scaled の値を 19 未満を設定。(接地している間に限定し、宙に浮いている間は除外するため)
  2. y5 の値が次の行の y5 より大きい。(着地は、最下位値の接地よりは、少し位置が高い特性を利用する)
  3. 次の行の y5 がその次の行の y5 とほぼ(±1とする)等しい。(接地時間帯2〜3フレームは高さの変動が少ない)
#pythonコード
filtered1_df = df_deg[
                (df_deg['y5_scaled'] < 19) &
                (df_deg['y5'] > df_deg['y5'].shift(-1))+ 5 &
                ((df_deg['y5'].shift(-1) - df_deg['y5'].shift(-2)).between(-1.0, 1.0, inclusive='both'))
            ]

腰から足首に伸びる直線が、地面に対して垂直(鉛直)→真下に重心

もう1つ、真下に重心が移ったタイミングを捉えること。そのフレームの膝の角度を取得します。

上記表の「deg_kosi_heel : 腰から足首線の対鉛直角度」の値が0だと、まさしく鉛直方向に伸びています。動画は、細かくも断片静止画像の集合体なので、必ずしもピッタリ0になるとは限らないので、条件としては少し幅を持たせる形となります。

  1. deg_kosi-heel の値が-2.5度から+2.5度の範囲にあること。(動画フレームとして捕捉できる、かつ、ほぼ鉛直として許容できる範囲)
  2. x4 の値が次の行の x4 より小さい。(前から踏み込む動きに限定し、後ろから前に移動する場合は除く)
#pythonコード
filtered2_df = df_deg[
                (df_deg['deg_kosi_heel'] >= -2.5) &
                (df_deg['deg_kosi_heel'] <= 2.5) &
                (df_deg['x4'] < df_deg['x4'].shift(-1))
            ]

以上先ずは方向性は決まり一応の結果が出せるようになりました。どこをどのように指標とすべきか?という点、これはランナーの立場として視るべき点はもちろんあるのですが、併せてプログラミングとして成立するのか?という点も考慮し、行ったり来たり。

という試行錯誤でした。とはいえ、まだまだブラッシュアップせねば。

このAIの端くれソフトって使えるのか?どう活用すれば良いのか?本家本元のChat GPTさんに聞いてみよう(笑)

それから腕のAI分析の方も、別途書きたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です