MediaPipeのFacemeshを使用してネコ目になってみた。
野良ハックチーム(ざっきー)と申します。
前回のねこIoTLT vol.6から2ヶ月が過ぎてしまいました。
次回のねこIoTLTのLT登壇ネタ(第二弾)を考えてみました。
NARUTO -ナルト- に登場する写輪眼は特異体質の一つで、さまざまな種類・能力・技(瞳術)があり、MediaPipeのFacemeshを使用して虹彩部分に写輪眼を表示するプログラムに感化されました。
まずはサンプルプログラムを試してみます。
Raspberry Pi 4(メモリ4GB)とUSBカメラ(Logicool HD WEBカメラ C270)を使用して写輪眼を表示させてみました。
$ sudo pip3 install pip --upgrade
$ pip3 install mediapipe==0.8.8
$ pip3 install mediapipe-rpi4==0.8.8
$ git clone https://github.com/Kazuhito00/NARUTO-Sharingan-Iris-Overlay
$ cd NARUTO-Sharingan-Iris-Overlay/
$ python3 demo.py
USBカメラを指定して実行する場合はデバイスリストを表示して番号を確認します。(私の場合は/dev/video1がUSBカメラでした)
$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
/dev/video18
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
VirtualCam (platform:v4l2loopback-000):
/dev/video0
UVC Camera (046d:0825) (usb-0000:01:00.0-1.3):
/dev/video1
/dev/video2
また、写輪眼としてネコ目画像を用意します。
(私の場合はimageディレクトリにeye05.pngというファイル名でネコ目画像を保存しました)
USBカメラのデバイス番号と写輪眼にネコ目画像を指定してサンプルプログラムを実行する例です。
$ python3 demo.py --device 1 --eye image/eye05.png
実際に試したところ、Raspberry Pi 4では5 FPSくらいの性能でした。
誰でも簡単に試せるようにブラウザ(MediaPipeのJavascript版)での実装を試してみます。
参考にしたのは@youtoyさんのMediaPipeとp5.jsを組み合わせて簡素化した実装です。
まずは、虹彩のランドマーク(位置番号)を確認します。
サンプルページへアクセスして、スライドバーを動かして位置番号を変更します。
実際に確認した虹彩の位置番号を記録しておきます。(虹彩の位置番号は469〜477でした)
index.html(Javasscript)と写輪眼(ネコ目)の画像ファイルだけで実装することができました。
少しだけソースコードの説明をします。
虹彩の情報を取得するためにsetOptionsでrefineLandmarksをtrueに設定します。
faceMesh.setOptions({
maxNumFaces: 1,
refineLandmarks: true,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
keypointsFaceに格納されたfaceMeshの情報から左目と右目の情報を取得してオブジェクトへ格納します。
const indexLeftIris = {
center: keypointsFace[0][468],
right: keypointsFace[0][469],
up: keypointsFace[0][470],
left: keypointsFace[0][471],
down: keypointsFace[0][472],
};
const indexRightIris = {
center: keypointsFace[0][473],
right: keypointsFace[0][474],
up: keypointsFace[0][475],
left: keypointsFace[0][476],
down: keypointsFace[0][477],
};
左目と右目の虹彩にネコ目画像を表示します。
drawEye(indexLeftIris, displayWidth, displayHeight);
drawEye(indexRightIris, displayWidth, displayHeight);
表示する関数 drawEye() は主に2つの処理を行なっています。
1. 虹彩の上下左右の位置をもとに、表示するネコ目画像の大きさを決定する
2. 虹彩の中心にネコ目画像を表示する
function drawEye(position, inputWidth, inputHeight) {
push();
imageMode(CENTER);
tint(255, 128);
const x_width = Math.sqrt(Math.pow(position.right.x - position.left.x, 2) + Math.pow(position.right.y - position.left.y, 2));
const y_width = Math.sqrt(Math.pow(position.up.x - position.down.x, 2) + Math.pow(position.up.y - position.down.y, 2));
image(
imagePNG,
(1 - position.center.x) * inputWidth,
position.center.y * inputHeight,
imagePNG.width * x_width * 5,
imagePNG.height * y_width * 3
);
pop();
}
実際に試した様子です。
ぜひ、ねこ娘になってみてください!(笑
この記事が気に入ったらサポートをしてみませんか?