ブラウザに表示される画像や、PCカメラからブラウザに映る人間の姿を姿勢推定する「TensorflowJS Posenet」。
ブラウザで動くものを、なぜわざわざNodeJSで動作させたいのか、というと、クライアント側の処理負荷を抑えたい、ということがあります。あと、PHPやMySQLなどのWEB環境と連動しやすくしたいこともあります。
まず、Macを使用し、特定のフォルダに置いてある画像で、NodeJSで姿勢推定が出来るか、試してみました。
必要なライブラリなど
すみません、細かい解説は割愛します。
node-canvas
node-canvas を動かすためのライブラリのインストール
$ brew install pkg-config cairo pango libpng jpeg giflib
node-canvasインストール
$ npm install --save canvas botkit
TensorFlowJS NodeJS
npmでインストールします。
$ npm install --save rollup
$ npm install --save @tensorflow/tfjs@^1.1.0
$ npm install --save @tensorflow-models/posenet
$ npm install --save @tensorflow/tfjs-node
GPUの場合
$ npm install --save @tensorflow/tfjs-node-gpu
注意点
1.tfjsではなく、tfjs-nodeを使うこと。
//const tf = require('@tensorflow/tfjs');
const tf = require('@tensorflow/tfjs-node');
2.画像はCanvasに投影後、テンソル型にして、estimateSinglePose()を実行すること。
NodeJSをバッチで走らすとDOMは無いですが、「node-canvas」でCanvasタグをDOMのように扱えます。
var imageScaleFactor = 0.5;
var outputStride = 16;
var flipHorizontal = false;
// モデルのロード
var net = await posenet.load(0.75);
const img = new Image();
img.src = './hoge.jpg';
const canvas = createCanvas(img.width, img.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// Tensor型に変換
const input = tf.browser.fromPixels(canvas);
// 姿勢JSON取得
const pose = await net.estimateSinglePose(input, imageScaleFactor, flipHorizontal, outputStride);
console.log(pose);
結果
{
score: 0.8253553825266221,
keypoints: [
{ score: 0.9589502215385437, part: 'nose', position: [Object] },
{ score: 0.6782095432281494, part: 'leftEye', position: [Object] },
{ score: 0.9743408560752869, part: 'rightEye', position: [Object] },
{ score: 0.3834344744682312, part: 'leftEar', position: [Object] },
{ score: 0.9573087692260742, part: 'rightEar', position: [Object] },
{
score: 0.9608330726623535,
part: 'leftShoulder',
position: [Object]
},
{
score: 0.970580518245697,
part: 'rightShoulder',
position: [Object]
},
{
score: 0.5824703574180603,
part: 'leftElbow',
position: [Object]
},
{
score: 0.8478972911834717,
part: 'rightElbow',
position: [Object]
},
{
score: 0.4102041721343994,
part: 'leftWrist',
position: [Object]
},
{
score: 0.43626463413238525,
part: 'rightWrist',
position: [Object]
},
{ score: 0.9976338148117065, part: 'leftHip', position: [Object] },
{ score: 0.9926899671554565, part: 'rightHip', position: [Object] },
{ score: 0.9901325702667236, part: 'leftKnee', position: [Object] },
{
score: 0.9896235466003418,
part: 'rightKnee',
position: [Object]
},
{
score: 0.9450682401657104,
part: 'leftAnkle',
position: [Object]
},
{
score: 0.9553994536399841,
part: 'rightAnkle',
position: [Object]
}
]
}
あとは、この座標に準じて、キーポイントをcanvasに描画して、Canvasごとfs.writeFile()でアウトプットするだけです。
サーバにアップロードされた複数の画像に、姿勢推定ラインが付けられるようになりますね。
ffmpegでmp4スロー動画を1秒1フレームで切り出し、40枚の画像を処理するのに3分ほど。。この辺りはやはりGPUじゃないと厳しいのかな。
こうして生成したキーポイントとボーンの付いた画像から、さらにffmpegでキーポイント・ボーン付き動画を作ることは出来ますね。JSONファイルに書き出しや、canvasでキーポイント・ボーンだけの動画を生成することも可能。サーバ上のTensorFlow・Posenetで、Openposeに引けを取らない仕様に出来そうです。処理速度は早くないと思いますが。。
CentOSやUbuntuでも同じように出来ると思います。