これはTensorFlow.jsのfacemeshで3D座標から顔向き推定の実証実験。
前回はOpenCVのSolvePnPとRodriguesで回転行列(rotation matrix)を求めました。
今回はアプローチを変えてfacemeshの3D座標から直接回転行列を求めます。
回転行列の求め方(コード紹介)
行列演算はTensorFlow.jsを利用しました。
TensorFlow.jsでは演算子をサポートしていないのでとても見辛いです。
TensorFlow.js API
※ 使ったメモリはdisposeやTidyで解放が必要です
参考までに
- div .. 割り算
- sub .. 引き算
- mul .. 掛け算
コードでは、顔の適当な3D座標(元コードでは全ての座標、今回は適当に選択した座標:輪郭のみ)と輪郭の端の4点と目の位置の引数からスケールを取得し、中心を求めています。
let fecePoints = tf.tensor(faces);
let eye1 = tf.tensor1d(rightEye);
let eye2 = tf.tensor1d(leftEye);
let scales = fecePoints.div(tf.norm(eye1.sub(eye2))).mul(0.06);
let centered = scales.sub(scales.mean(axis=0));
let c00 = centered.slice(0,1).as1D();
let c09 = centered.slice(9,1).as1D();
let c18 = centered.slice(18,1).as1D();
let c27 = centered.slice(27,1).as1D();
3x3のrotation matrixを求めます。
let rotate0 = c18.sub(c00).div(tf.norm(c18.sub(c00)));
let rotate1 = c09.sub(c27).div(tf.norm(c09.sub(c27)));
let rotate = tf.concat([rotate0, rotate1]).arraySync();
let m00 = rotate[0];
let m01 = rotate[1];
let m02 = rotate[2];
let m10 = rotate[3];
let m11 = rotate[4];
let m12 = rotate[5];
// cross product
let m20 = m01*m12 - m02*m11;
let m21 = m02*m10 - m00*m12;
let m22 = m00*m11 - m01*m10;
rotation matrixが解れば、Rotation Matrix to Euler Anglesで変換します。
製作物
顔向き推定のオンラインデモを公開しました。良ければお試しください。
— o2 (@mb_otsu) May 26, 2020
あと、今回の実装について簡単にまとめました。https://t.co/OXEvQENpCmhttps://t.co/jnKMpUnFIS#facemesh #TensorFlow pic.twitter.com/ZjgDfwzocg
オンラインデモ
おわりに
facemeshの三次元座標で顔の向きを推定しました。
AIで三次元座標が解ることで、簡単に顔の向きが推定出来るようになり、よく使われるSolvePnPの手法が必須ではなくなりました。
これまで当然として使われていた処理が使われなくなるのは感慨深いものがあります。
今後も、定期的に自身の情報をアップデートしていければと思います。