手順としては、前のcoco-ssdと同様、[ファイルを選択]ボタンのクリックで画像ファイルを選択し、それをJavaScriptのイメージデータに変換します。そしてそれをposenetに渡します。
// PoseNetを読み込み、イメージの姿勢検出を実行
posenet.load().then((net) => {
return net.estimateSinglePose(imageData);
}).then((pose) => {
// 各部位を描画する
drawParts(context, pose);
});
posenetのestimateSinglePose()は1人の姿勢検出に使用します。このメソッドは配列を含むオブジェクトを返すので、ここではそれ(pose)を、キャンバスのコンテキストとともに、drawParts()関数に渡しています。
poseオブジェクトはkeypointsプロパティを持っています。keypointsは配列で、要素として、部位名(part)とその部位のx位置(x)、y位置(y)をプロパティに持つオブジェクトを含んでいます。
pose.keypoints[{
position.x // x位置
position.y // y位置
part // 部位名
}, ...]
drawParts()関数では、渡されたコンテキストとpose.keypointsを使って、キャンバス画像の上に丸と線を描きます。
// 頭部と上半身、下半身の部位を色別に丸で描き、左右別に線で結ぶ
const drawParts = (ctx, pose) => {
const points = pose.keypoints;
// 円の半径
const radius = 7;
// pose.keypoints配列にあるオブジェクトの情報を元に部位を円で描く
for (let i = 0; i < points.length; i++) {
// x位置
const xpos = points[i].position.x;
// y位置
const ypos = points[i].position.y;
// 部位の名前
const part = points[i].part;
// 頭部と上半身、下半身で色を分ける
if (part === 'nose' || part === 'leftEye' || part === 'rightEye' || part === 'leftEar' || part === 'rightEar') {
ctx.fillStyle = "lightgreen";
}
else if (part === 'leftShoulder' || part === 'rightShoulder' || part === 'leftElbow' || part === 'rightElbow' || part === 'leftWrist' || part === 'rightWrist') {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "blue";
}
// 円で塗る
ctx.beginPath();
ctx.arc(xpos, ypos, radius, 0, Math.PI * 2);
ctx.fill();
}
// 上半身、左右別に部位を線で結ぶ
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineWidth = 4;
// leftSholder5 - leftElbow7 - leftWrist9
ctx.moveTo(points[5].position.x, points[5].position.y);
ctx.lineTo(points[7].position.x, points[7].position.y);
ctx.lineTo(points[9].position.x, points[9].position.y);
// rightSholder6 - rightElbow8 - rightWrist10
ctx.moveTo(points[6].position.x, points[6].position.y);
ctx.lineTo(points[8].position.x, points[8].position.y);
ctx.lineTo(points[10].position.x, points[10].position.y);
// 線を描く
ctx.stroke();
// 下半身、左右別に部位を線で結ぶ
ctx.beginPath();
ctx.strokeStyle = 'blue';
// leftHip11 - leftKnee13 - leftAnkle15
ctx.moveTo(points[11].position.x, points[11].position.y);
ctx.lineTo(points[13].position.x, points[13].position.y);
ctx.lineTo(points[15].position.x, points[15].position.y);
// rightHip12 - rightKnee14 - rightAnkle16
ctx.moveTo(points[12].position.x, points[12].position.y);
ctx.lineTo(points[14].position.x, points[14].position.y);
ctx.lineTo(points[16].position.x, points[16].position.y);
ctx.stroke();
}