LoginSignup
3
2

More than 5 years have passed since last update.

スポーツをITする(3)簡単なフォームチェック tensoleflow.js

Last updated at Posted at 2018-11-02

前回の記事より、簡単なフォームチェックのロジックを追加してみました。

ボーン座標のズレ

ブラウザのgetusermediaを使って、TensoleJS posenet を適当にVideoタグで表示すると、映し出された映像に描画するボーン座標にズレが生じます。
これは、縦横比の問題であろうと思われ、試行錯誤の結果、iPhone8の場合、横幅340px、縦幅380pxでズレが最小限に抑えられるようです。以下はズレた例です。

IMG_0398.jpg

フォームチェックのテンプレート

某一流プロゴルファーのボーン座標を写真から取得しました。
ゴルフのアドレス(構え)としては、ちょっとおかしい感じがありますね。
写真を横幅170px、縦380pxにリザイズして、画面上に合うように手作業しました。
スクリーンショット 2018-11-02 11.25.19.png

どうやら、少し大きめの画像でないと、誤認識するようです。以下、元画像を横幅を340pxに拡大してボーン座標を取得してみました。少しまともになったかな。
スクリーンショット 2018-11-02 19.21.26.png

フォームチェックのロジック

とりあえず最初は簡単な方法で、と思い、
・テンプレートの目と耳以外の13箇所それぞれの位置と写した映像のそれぞれの位置の距離を測る。
・その距離が10ピクセル以下なら1、でなければ0とする。
・最大13箇所中、何箇所が1になっているか、を百分率する。これを一致率としてみる。

estimateSinglePose()を実行している関数poseDetectionFrame()の中にある、poses.forEach(({score, keypoints}) に、判定のロジックを入れます。

poses.forEach(({score, keypoints}) => {
    if (score >= minPoseConfidence) {
        if (guiState.output.showPoints) {
            drawKeypoints(keypoints, minPartConfidence, ctx);
        }
        if (guiState.output.showSkeleton) {
            drawSkeleton(keypoints, minPartConfidence, ctx);
        }
        if (guiState.output.showBoundingBox) {
            drawBoundingBox(keypoints, ctx);
        }
    }
    make_video_bone(keypoints) // 追加
});

キーポイントを配列に分割します。

function make_video_bone(keypoints) {
    for (let i = 0; i < keypoints.length; i++) {
        const keypoint = keypoints[i];
        video_bone[keypoint.part] = keypoint.position;
    }

    if (templates_bone.nose && video_bone.nose) {
        calc_distance(templates_bone, video_bone);
    }
}

テンプレートと比較して一致率を計算します。

function calc_distance(tb, vb) {
    var cnt = 0;
    var max = 13;

    var temp = Math.sqrt(Math.pow((tb.nose.x - vb.nose.x),2) + Math.pow((tb.nose.y - vb.nose.y),2));
    if (temp < 10) {
        cnt++;
    }
    var temp = Math.sqrt(Math.pow((tb.leftShoulder.x - vb.leftShoulder.x),2) + Math.pow((tb.leftShoulder.y - vb.leftShoulder.y),2));
    if (temp < 10) {
        cnt++;
    }
・・・・・

    var rs = cnt / max * 100;

// 画面上に一致率を表示
    $('.pa').html(Math.round(rs));
}

もっといい判定方法は無いかな、と思っています。

検証

スマホでは手ブレが激しいので、13箇所がうまく判定出来ず、常に一致率は0%。
逆に言うと、手ブレがわかるほどスムーズなライブ再生で性能が良い、ということですね。

軸にしてみるとか、もう少しチューニングが必要。
以下、ブルーの線がライブ、赤い線がテンプレート(模範)です。なかなか一致しない。。
IMG_0402.jpg

3
2
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
3
2