前回の記事から、スマフォカメラを使って、映像の上にボーンを重ねる実験を行いました。
i
phone8 Safariブラウザです。
HTML
tfjs posenetのdemos camera.htmlに、横幅170pxのcanvasを追加。
Videoタグ、Canvas id=output のwidthともに、js側で横340px、縦240pxにします。
<video id="video" playsinline style=" -moz-transform: scaleX(-1);
-o-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
display: none;">
</video>
<canvas id="output"></canvas>
<canvas id="canvas" width="170" height="240"></canvas>
CSS
追加したcanvasが、映像の中央に来るように調整。
#canvas{
position: absolute;
left: 85px;
top: 0;
background-color: yellow;
opacity: 0.4;
z-index:100;
}
Javascript
追加したcanvasに、あらかじめ取得したボーン座標を描画します。
実は、tensoleflow.jsで取得した座標には、少しズレがあったので、learnOpenCVのOpenPoseImage.pyで出力しました。tfjsのposebetに合うよう、JSONを生成するように改修しています。
const canvas_t = document.getElementById('canvas');
const ctx_t = canvas_t.getContext('2d');
ctx_t.clearRect(0, 0, 170, 240);
let poses = [];
// Head – 0, Neck – 1, Right Shoulder – 2, Right Elbow – 3, Right Wrist – 4,
// Right Knee – 9, Right Ankle – 10, Left Hip – 11, Left Knee – 12,
// Left Ankle – 13, Chest – 14, Background – 15
var template_pose = {"score": 1,
"keypoints":[
{"score":1, "part":0, "position": {"x":81.30434782608695,"y":15.652173913043478}},
{"score":1, "part":1, "position": {"x":81.30434782608695,"y":46.95652173913044}},
{"score":1, "part":2, "position": {"x":66.52173913043478,"y":52.17391304347826}},
{"score":1, "part":3, "position": {"x":73.91304347826087,"y":83.47826086956522}},
{"score":1, "part":4, "position": {"x":88.69565217391305,"y":114.78260869565217}},
{"score":1, "part":5, "position": {"x":103.47826086956522,"y":41.73913043478261}},
......
]
};
poses.push(template_pose);
poses.forEach(({score, keypoints}) => {
drawKeypoints(keypoints, ctx_t);
drawSkeleton(keypoints, ctx_t);
});
結果
夜だったので、背景はPC映像でご勘弁を。近々に外で実際のゴルフのアドレスで試してみて、この記事の整理と所感を記載します。端折った内容ですみません。
*estimateSinglePose()には、映像反転を制御するflipHorizontalがありますが、iOS Safariでtrueにしてもfalseにしても、反転したままなのです。。なぜ?
↓
flipHorizontalは、特徴点を反転させるようで、映像自体の反転ではないようです。
detectPoseInRealTime(video, net)関数の中のflipHorizontalをfalseとし、
if (guiState.output.showVideo) {
ctx.save();
//ctx.scale(-1, 1);
//ctx.translate(-videoWidth, 0);
ctx.drawImage(video, 0, 0, videoWidth, videoHeight);
ctx.restore();
}
とscaleとtranslateをコメントアウトしたら、うまく動作しました。いいのかな。
次は
どのくらい離れれば実際の映像に合うのかどうか。
もっと大きな映像にしたいのですが、やり方を模索中。。
フォーム判定のロジック組み込み。