上のgif動画は、単眼カメラからの姿勢推定SOFTのVideoPose3Dの棒人間動画です。VideoPose3Dは時間相関を考慮した3次元姿勢推定で、ライセンスはCC-by-NCです。
1.はじめに
本記事は、cedro3さんのGitHubの2020-11-03最終変更したVideoPose3D.ipynb(参考URL1)に次の変更を加え、得られたCSVファイルから、重心位置と重心速度を求め、箱ひげ図を描き、統計的検定を行うものです。
・キーポイント抽出に利用する動画がyoutube動画だったものを、自分のgoogle driveのフォルダ(任意、ここではautotrace)に入れた動画(ファイル名=nara_0403.mp4、33sec)をキャプション可とする。
・出力が3Dテンソルのnpyファイルだったものを扱いやすいcsvファイルも出力可とする。
さらに、csvファイルの1使用方法(重心位置と重心速度の求め方、統計的検定)についても記載します。なお、コードはGoogle ColabのJyupyter notebookの作成を考慮し、変更のないステップも記載します。
(1)Google driveのマウント(変更あり)
下のコマンドを実行し、Googleアカウントを選択し、「許可」するとコードが表示されるので、Jupyter notebookにコピペする。
from google.colab import drive
drive.mount('/content/gdrive')
cedro3さん記事では、 Pytorch と Caffe2 を導入 (以下手順で、CUDA, cuDNNも併せて導入される)をしていますが、現在のGoogle colaboでは導入されているので、Caffe2のインストールチェックからコードをコピペします。以後、6まで変更がないのでコピペします。
(2)次に、Caffe2 環境が構築されているかの確認(変更なし)
# To check if Caffe2 build was successful
!python -c 'from caffe2.python import core' 2>/dev/null && echo "Success" || echo "Failure"
# To check if Caffe2 GPU build was successful
!python -c 'from caffe2.python import workspace; print(workspace.NumCudaDevices())'
(3)COCOデータセット(画像を扱う機械学習のためのデータセットの一つ)の導入(変更なし)
!apt-get install python-dev
!pip install cython
!pip install pycocotools
!git clone https://github.com/cocodataset/cocoapi.git
!cd cocoapi/PythonAPI && make install
(4) Detectron の導入(変更なし)
!rm -r detectron
!git clone https://github.com/facebookresearch/detectron
!pip install -r detectron/requirements.txt
!cd detectron && make
!python detectron/detectron/tests/test_spatial_narrow_as_op.py
(5)VideoPose3D の導入 & Video Script を Detectron Tools Folder へコピー(変更なし)
!rm -r VideoPose3D
# copy file from VideoPose3d
!git clone https://github.com/facebookresearch/VideoPose3D
!cp VideoPose3D/inference/infer_video.py detectron/tools/infer_video.py
(6)Pretrained Human3.6m Coco Model をダウンロード(変更なし)
!mkdir VideoPose3D/checkpoint
os.chdir('VideoPose3D/checkpoint')
!wget https://dl.fbaipublicfiles.com/video-pose-3d/pretrained_h36m_detectron_coco.bin
os.chdir('../..')
(7)キーポイントを抽出しようとする33秒のmp4動画をffmpegで準備します。33秒の指定は「t 00:00:33」で指定する。nara_0403.mp4は解析する33秒間の動画で、autotraceフォルダに入れてあります。(変更あり)
!rm -r videos
!mkdir videos
import os
!ffmpeg -i "/content/gdrive/My Drive/autotrace/nara_0403.mp4" -ss 00:00:00 -t 00:00:33 videos/video.mp4
(8)Detectron を用いて2D座標を計算(変更なし)
!rm -r output
!mkdir output
!python detectron/tools/infer_video.py \
--cfg detectron/configs/12_2017_baselines/e2e_keypoint_rcnn_R-101-FPN_s1x.yaml \
--output-dir output \
--image-ext mp4 \
--wts https://dl.fbaipublicfiles.com/detectron/37698009/12_2017_baselines/e2e_keypoint_rcnn_R-101-FPN_s1x.yaml.08_45_57.YkrJgP6O/output/train/keypoints_coco_2014_train:keypoints_coco_2014_valminusminival/generalized_rcnn/model_final.pkl \
videos
(9)VideoPose3Dの入力に合わせたDetectronの出力を用意(変更なし)
!rm -r ./VideoPose3D/data/detectronoutput
!mkdir ./VideoPose3D/data/detectronoutput
!cp output/video.mp4.npz VideoPose3D/data/detectronoutput/video.mp4.npz
os.chdir('VideoPose3D/data') # This script must be launched from the "data" directory
!python prepare_data_2d_custom.py -i detectronoutput -o myvideos
os.chdir('../../')
(10)VideoPose3Dを使用して3Dジョイントを計算(変更なし)
# 以下2.2で実施しないと失敗する
!pip install matplotlib==2.2
!rm -r VideoPose3D/video.mp4
!cp ./videos/video.mp4 VideoPose3D/video.mp4
os.chdir('VideoPose3D')
!python run.py -d custom -k myvideos -arc 3,3,3,3,3 -c checkpoint --evaluate pretrained_h36m_detectron_coco.bin --render --viz-subject video.mp4 --viz-action custom --viz-camera 0 --viz-video video.mp4 --viz-output output.mp4 --viz-export outputfile --viz-size 6
(11)結果の表示(ジョイントのエクスポート)(変更あり)
npyファイルはバイナリーの3dテンソルなので、2次元のcsvファイルに直してダウンロードします。5番目のコマンドのreshape(990,51)は実行例の33秒のフレーム数990を入力しています。
import numpy as np
data = np.load('outputfile.npy')
lst = data
import numpy as np #ins nara
outputvideo=data.reshape(990,51).copy() #ins nara del0308
np.savetxt('outvideo.csv',outputvideo,delimiter=',',fmt='%.10f')
for item in lst:
prit(item)
(12)結果の表示(ジョイントビデオ)(変更なし)
# display video
def show_local_mp4_video(file_name, width=640, height=480):
import io
import base64
from IPython.display import HTML
video_encoded = base64.b64encode(io.open(file_name, 'rb').read())
return HTML(data='''<video width="{0}" height="{1}" alt="test" controls>
<source src="data:video/mp4;base64,{2}" type="video/mp4" />
</video>'''.format(width, height, video_encoded.decode('ascii')))
show_local_mp4_video('output.mp4', width=960, height=720)
(13)ジョイントビデオのダウンロード(変更あり)
4番目のコマンドが追加されています。3つのファイルが「ダウンロード」フォルダにダウンロードされます。
from google.colab import files
files.download('output.mp4')
files.download('outputfile.npy')
files.download('outvideo.csv')
2.CSVファイルの使い方
2.1 重心と重心速度
CSVファイルは、33.33msec毎の1フレームごとキーポイント17点の腰を原点とするワールド座標系の3次元座標なので座標は全部で51個になります。カメラに向かって踊っている人の左手方向がX軸の正、下が、Y軸の正、後ろ方向がZ軸の正の右手座標系です。以下はCSVファイルに付加すれば使い勝手が向上するヘッダーの情報です。
2人の棒人間動画のCSVファイルから統計解析SOFT のR言語(実際に使用したのはRコマンダー)を用いて重心位置と重心速度を求め、箱ひげ図描き統計的検定をしました。重心位置は参考URL2より求めました。次の表は上のヘッダ情報のキーポイント名称と重心を求めるための各部位の重量の情報です。従って、重心の座標はキーポイント座標の重み付け平均になります。
以下はRコマンダーの重心(grv_x、grv_y、grv_z)を求めるコードです。csvファイルをクリップボードに張り付けてDatasetにインポートしています。最後に重心をDatasetにcbindしています。
l_jyouwan_x=(l_shoulder_x+l_elbow_x)/2
l_jyouwan_y=(l_shoulder_y+l_elbow_y)/2
l_jyouwan_z=(l_shoulder_z+l_elbow_z)/2
r_jyouwan_x=(r_shoulder_x+r_elbow_x)/2
r_jyouwan_y=(r_shoulder_y+r_elbow_y)/2
r_jyouwan_z=(r_shoulder_z+r_elbow_z)/2
l_zenwan_x=(l_elbow_x+l_wrist_x)/2
l_zenwan_y=(l_elbow_y+l_wrist_y)/2
l_zenwan_z=(l_elbow_z+l_wrist_z)/2
r_zenwan_x=(r_elbow_y+r_wrist_y)/2
r_zenwan_y=(r_elbow_y+r_wrist_y)/2
r_zenwan_z=(r_elbow_z+r_wrist_z)/2
l_momo_x=(l_hip_x+l_knee_x)/2
l_momo_y=(l_hip_y+l_knee_y)/2
l_momo_z=(l_hip_z+l_knee_z)/2
r_momo_x=(r_hip_x+r_knee_x)/2
r_momo_y=(r_hip_y+r_knee_y)/2
r_momo_z=(r_hip_z+r_knee_z)/2
l_leg_x=(l_knee_x+l_ankle_x)/2
l_leg_y=(l_knee_y+l_ankle_y)/2
l_leg_z=(l_knee_z+l_ankle_z)/2
r_leg_x=(r_knee_x+r_ankle_x)/2
r_leg_y=(r_knee_y+r_ankle_y)/2
r_leg_z=(r_knee_z+r_ankle_z)/2
cntr_x=3*head_x+2*spine2_x+14*spine1_x
left_x=l_shoulder_x+2*l_jyouwan_x+2*l_zenwan_x+7*l_hip_x+6*l_momo_x+3*l_leg_x
right_x=r_shoulder_x+2*r_jyouwan_x+2*r_zenwan_x+7*r_hip_x+6*r_momo_x+3*r_leg_x
grv_x=(cntr_x+right_x+left_x)/61
cntr_y=3*head_y+2*spine2_y+14*spine1_y
left_y=l_shoulder_y+2*l_jyouwan_y+2*l_zenwan_y+7*l_hip_y+6*l_momo_y+3*l_leg_y
right_y=r_shoulder_y+2*r_jyouwan_y+2*r_zenwan_y+7*r_hip_y+6*r_momo_y+3*r_leg_y
grv_y=(cntr_y+right_y+left_y)/61
cntr_z=3*head_z+2*spine2_z+14*spine1_z
left_z=l_shoulder_z+2*l_jyouwan_z+2*l_zenwan_z+7*l_hip_z+6*l_momo_z+3*l_leg_z
right_z=r_shoulder_z+2*r_jyouwan_z+2*r_zenwan_z+7*r_hip_z+6*r_momo_z+3*r_leg_z
grv_z=(cntr_z+right_z+left_z)/61
Dataset<-cbind(Dataset,grv_x)
Dataset<-cbind(Dataset,grv_y)
Dataset<-cbind(Dataset,grv_z)
重心速度は、Datasetをダウンロードし、エクセルで計算し、再度Rにアップしました。
2.2 箱ひげ図と統計的検定
以下の6つの図は、Rで書いた箱ひげ図で、最初の3つはそれぞれx、y、zの重心位置、次の3つはx、y、zの重心速度です。
以下は、統計的検定結果です。重心位置はクラスカルウォリスのχ2乗で検定し、いずれもお中央値は5%で有意差ありとなった。重心速度は、分散比のF検定を行い、y方向の重心速度を除いて危険率5%で有意差ありとなった。
3.おわりに
皆さんも、GoogleColaboでCSVファイルを出力して、Rで遊んでください。
謝辞
TKさんには、動画の提供とディスカッションをしていただきました。ここに謝意を表します。
参考URL
1.https://github.com/cedro3/others/blob/master/VideoPose3D.ipynb
2.https://www.ieice.org/publications/conference-FIT-DVDs/FIT2009/pdf/J/J_014.pdf