【Python×MediaPipe】スティックピクチャで動作を可視化する

python

✅ スティックピクチャとは?

mediapipeに限らず、他の三次元動作解析装置から得られる結果は大抵の場合、各ランドマークの座標の位置の時系列データで提供されることがほとんどです。このままのデータの状態ではいったい動作どうなっているかというのはわかりにくく、それはたとえ時系列データの波形にしたとしても同じです。

こういった座標データを効果的に視覚化する方法には、スティックピクチャと呼ばれる描画方法を用いるのが効果的です。こういった視覚化はpythonが得意とするジャンルだといえます。

スティックピクチャはMediaPipeのような骨格推定で取得した関節座標(CSV形式)をもとに、
関節を点で、関節間を線で結んで描画する方法です。

実際のプログラミングの処理のプロセスとしては下記の流れになります。

  • グラフを描画する場所やレンジを設定
  • 関節位置 → plt.scatter() で点描画
  • 骨格ライン → plt.plot() で線描画

使用するパッケージは前回の記事(記事URL: http://ktr-project.net/?p=76)で座標を時系列データとして描画したときに使用したmatplotlibを用います。今回の記事では、以前に紹介した上肢動作の角度の数値化に使用したコード(記事URL: http://ktr-project.net/?p=57)を用いながら、実際の処理プロセスの中身を紹介していきます。


✅ 描画の対象:左上肢と頭部+肩ライン

今回は左肩・肘・手首を中心に、以下のような関係を描画します。これらの点を描画して、点の間を線で繋いでいくのをイメージしてください。

Head

Left Shoulder — Right Shoulder

Elbow

Wrist

✅ Pythonコード(描画パート)

こちらが実際のコードになります。各関節位置の座標は、縦と横の座標のそれぞれの二つが入った一次元の座標だと仮定してください。

使用するパッケージは今回の記事ではmatplotlibですが、これの前の関節座標の定義などが必要になるので、適宜numpyやpandasといった表計算のパッケージを使用しましょう。

import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6,6))
ax.set_xlim(-300, 300)
ax.set_ylim(-300, 300)
ax.set_xlabel("X (px)")
ax.set_ylabel("Y (px)")
ax.set_title("左上肢スティックピクチャ")

# 関節(点)の描画
ax.scatter(head_corr[0], head_corr[1], color='magenta', s=300, label='Head center', alpha=0.2)
ax.scatter(r_shoul_corr[0], r_shoul_corr[1], color='gray', s=100, label='Right Shoulder', alpha=0.2)
ax.scatter(l_shoul_corr[0], l_shoul_corr[1], color='gray', s=100, label='Left Shoulder', alpha=0.2)
ax.scatter(l_elb_corr[0], l_elb_corr[1], color='gray', s=100, label='Left Elbow', alpha=0.2)
ax.scatter(l_wri_corr[0], l_wri_corr[1], color='crimson', s=100, label='Left Wrist', alpha=0.2)

# 関節間(線)の描画
ax.plot([l_shoul_corr[0], r_shoul_corr[0]], [l_shoul_corr[1], r_shoul_corr[1]], color='gray', linewidth=2, alpha=0.2)
ax.plot([l_shoul_corr[0], l_elb_corr[0]], [l_shoul_corr[1], l_elb_corr[1]], color='gray', linewidth=2, alpha=0.2)
ax.plot([l_elb_corr[0], l_wri_corr[0]], [l_elb_corr[1], l_wri_corr[1]], color='gray', linewidth=2, alpha=0.2)

✅ ポイント解説

具体的な処理フローとしては、冒頭にも合った通り、①.描画範囲の設定、②.点の描画、③.線の描画の三つになります。matplotlibで主に使用する関数は以下の通りになります。

処理説明
plt.subplots()描画領域の作成
 →ここで出力される画像の大きさや縦横比を定義する。
set_xlim/ylim()見やすい中心固定の表示範囲
 →縦横比が異なる場合にはアスペクト比を考えて調整する必要がある。これをしておかないと出力されるスティックピクチャが歪みます
scatter()各関節の描画(色・大きさ・透明度指定)
plot()関節を線で結ぶことで“動作”を再現

ちなみにaxという見慣れないものがあるのがわかるとおもいます。これは一行目のfig, ax = plt.subplots(figsize=(6,6))という部分のコードで、axという名前をつけることで、以降の処理でax.○○といった感じで描画処理を加えています。この辺は慣れていきましょう。

点の描画については、ax.scatter(head_corr[0], head_corr[1])と書けば、axと定義した描画範囲に頭部のx座標とy座標を描画するという意味になります。元コードではこれ以降のalphaとかcolorとかいろいろ書いてありますが、これらを足しこむことによっていろいろと色や大きさ、透過度を変えることができます。

さらに線を描画するax.plot()では、変な二重カッコを使ってscatterとは違った書き方になっているかとおもいます。具体的に内容を説明するとこんな感じになります。

ax.plot([始点のx座標, 終点のx座標], [始点のy座標, 終点のy座標])

二重カッコをこんな感じで使うことで、特定のフレームで始点と終点を線を繋ぐことが可能になります。この書き方は今後3D座標を描画するときにも共通するので覚えておきましょう。


✅ 応用のヒント

  • 透過度(ax.alpha())を調整することで、複数のスティックピクチャを見やすく重ねることが可能になります。またある程度は透過度は薄くして方が見やすい印象です(KTR所感)
  • 各フレームのデータをループ処理で描画すれば、連続動作の流れを可視化できます。これを応用することによってgifでの保存も可能になります。
  • 3Dでの骨格座標描画も場合でも、処理には共通する部分が多いので、使っている関数などはしっかりと覚えておきましょう。今後いろいろなグラフ描画にも応用可能です。

✅ お問い合わせ

ご質問や応用相談はお気軽に X(@shmitaro_108) まで気軽にどうぞ。

コメント

タイトルとURLをコピーしました