8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ポージングに対応した再生位置からMVを再生するシステムを作ってみた[Pose Mover]

Last updated at Posted at 2019-12-12

#作ったもの
Herokuにデプロイしてあります。
https://pose-mover.herokuapp.com

Posenetで骨格検出をし、検出したポージングにに対応した再生位置からMVを再生するシステムです。

「ダンスの練習などに使えます💃(いちいちPC操作して踊ってみた動画をシークさせるの面倒でしょ?)」

とそれっぽい使い方を考えてみました。

しかし、ダンスの練習に使うためにはまだまだブラッシュアップが必要です。
現段階だとオレトク作品止まりなのかもしれませんね。
(ユーザに体験してもらうと結構好感触)

この作品はヒーローズ・リーグ2019のMAリーグと学生リーグとオレトクリーグにて決勝まで残りました🙌

作品の紹介動画はこちら

#ソース
ソースはGitHubで公開しております。
https://github.com/daiking1756/PoseMoverWeb

#きっかけ

  • レッドハッカソンHIROSHIMA2019にて開発
  • 某広島出身3人組テクノポップユニットが大好きだったこと
  • ハッカソン当日が彼女たちの結成20周年の記念日だったこと
  • 情報工学を専攻しているくせに、彼女たちに関する作品を作ったことが無かったこと
  • エモみが高まったこと

つまり、エモみ駆動開発です

#Posenet
骨格検出の機械学習モデル。
計17箇所の骨格検出ができます。(口、目、耳、肩、肘、手首、腰、膝、足首)

骨格検出だとOpenPoseというライブラリが有名です。
しかし、PosenetにはWebブラウザで動作するくらい軽量という特徴があります。
ブラウザ上で動作するので、作ったシステムをWebアプリケーションとして公開することもできます。

次の記事でOpenPoseとPosenetを分かりやすく比較されています。
「OpenPose はどこまでの画像に耐えられるのか ~ Pose Estimation の紹介~」

今回はTensorFlow.jsの公式のサンプルを参考にコードを書きました。

##Posenet VS OpenPose
見る人によって意見が別れるかもしれませんが、個人的にはOpenPoseの方が骨格検出が正確な気がします。
まあ、そこまで大きな差はないので、今回はPosenetを使いました。
voice1_posenet.png
スクリーンショット 2019-12-12 14.22.29.png
voice2_posenet.png
スクリーンショット 2019-12-12 14.24.19.png

#全体のロジック
1.正解ポージング画像の骨格情報を取得
2.カメラからユーザが行ったポージングの骨格情報をリアルタイムに取得
3.ユーザの骨格情報と正解ポージング画像の骨格情報を比較
4.誤差が一定値以下ならポージングとして検出し、YouTubeのMVを対応した再生位置から再生

##正解ポージング画像の骨格情報を取得
正解ポージング画像を登録する画面です。
登録する情報は3つあります

  • 正解ポージング画像
  • 左から何人目のポーズを正解の骨格情報とするか
  • YouTubeのMVのURL

###正解ポージング画像

正解ポージング画像は現段階では直接HTML内のimgタグのsrc属性に設定しています。
(画像ファイルをユーザが追加できるようにするべきですね。)
画像が読み込まれるとPosenetの骨格検出が自動的に動作し、水色のスケルトンが描画されます。

###左から何人目のポーズを正解の骨格情報とするか

そのスケルトンを見ながら、ユーザは左から何人目のポーズを正解の骨格情報として登録するかを選択します。
(画像では左から1番目のポーズが最も正確に骨格検出できていたため、「1」と入力)

###YouTubeのMVのURL
正解ポージング画像のポーズに対応するYouTubeのMVのURLを入力します。
注意点として、パラメータに再生開始位置を表すtを含めたURLを入力するようにします。
(画像ではt=91なので、1分31秒から動画が再生されます)
YouTubeの動画を右クリックして「現時点の動画のURLをコピー」を押すと良いですね。

スクリーンショット 2019-12-12 14.34.32.png

###データの保存形式
正解データはJSON形式で保存されています

-正解ポージング画像の骨格情報
-左から

##カメラからユーザが行ったポージングの骨格情報をリアルタイムに取得
公式のサンプルのままです。

##ユーザの骨格情報と正解ポージング画像の骨格情報を比較
17箇所の骨格情報のうち、ポージングに関係しそうな箇所のみを比較していきます。
パッと思いついたのが以下の4つの線分です。

  • 肩から肘
  • 肘から手首
  • 腰から膝
  • 膝から足首

ということで、左右合わせて合計8本の線分の角度の誤差平均を比較することにしました。
計算しているコードは以下に載せておきます。

以下の記事を参考にしました。
2点間の距離と角度と座標の求め方

calc_pose_angle.js
// 正解ポーズとユーザポーズの、角度の誤差を計算
function calcAngleError(correct_pose, user_pose){
    let error = 0;

    // Shoulder - Elbow
    error += calcKeypointAngleError(correct_pose, user_pose, 5, 7);
    error += calcKeypointAngleError(correct_pose, user_pose, 6, 8);

    // Elbow - Wrist
    error += calcKeypointAngleError(correct_pose, user_pose, 7, 9);
    error += calcKeypointAngleError(correct_pose, user_pose, 8, 10);

    // // Hip - Knee
    error += calcKeypointAngleError(correct_pose, user_pose, 11, 13);
    error += calcKeypointAngleError(correct_pose, user_pose, 12, 14);

    // // Knee - Ankle
    error += calcKeypointAngleError(correct_pose, user_pose, 13, 15);
    error += calcKeypointAngleError(correct_pose, user_pose, 14, 16);

    error /= 8;

    return error
}

// 正解ポーズとユーザポーズの、ある2つのkeypoint間の角度の誤差を計算
function calcKeypointAngleError(correct_pose, user_pose, num1, num2){
    let error = Math.abs(calcKeypointsAngle(correct_pose.keypoints, num1, num2) - calcKeypointsAngle(user_pose.keypoints, num1, num2))
    if(error <= 180) {
        return error
    } else {
        return 360 - error
    }
}

// keypoint[num1]とkeypoint[num2]の角度を計算
function calcKeypointsAngle(keypoints, num1, num2){
    return calcPositionAngle(keypoints[num1].position, keypoints[num2].position);
}

// position1とposition2を結ぶ線分の角度を計算
function calcPositionAngle(position1, position2){
    return calcAngleDegrees(position1.x, position1.y, position2.x, position2.y);
}

// 2点間の角度を計算
function calcAngleDegrees(x1, y1, x2, y2) {
    return Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
}

##誤差が一定値以下ならポージングとして検出し、MV再生
YouTube Player APIというJSでiframeで埋め込んだYouTubeプレイヤーを制御できるAPIがありました。
これを使ってMVを再生しています。

  • 検出したポーズが再生中の曲のポーズならば、シーク
  • 検出したポーズが再生中の曲のポーズでないならば、MVを読み込み直し、対応する再生位置から再生

というロジックです。

#まとめ
Posenetは手軽に骨格検出ができるし、ブラウザで動くの最高すぎる。
BodyPixも使ってみたい。

自分の好きなこと駆動で開発するのは楽しい!

#参考

8
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?