こんにちは。
今回は、顔認識をしてみようというお話です。
今何かと話題の「VTuber」。デジタル世界に自分専用の分身をつくるというのは誰しもやってみたいことだと思います。(個人の感想です)
ただそれを専用のソフトウェアでつくるのもいいですが、processingを始めた人なら自分でソフトからつくってみるというのも面白いと思います。
目次
ライブラリの導入
まずは、今回使うライブラリを導入します。
顔認識用に「OpenCV」、カメラ用に「Video」を使います。
OpenCVはインテルが開発したというオープンソースのライブラリらしく、かなりの機能があります。
カメラの機能もOpenCVにあるようなことが書いてあるものもありましたが、カメラの使用時はVideoライブラリの方がお世話になることが多いであろうということでVideoライブラリでやってみます。
導入は、上の方にある「スケッチ」から「ライブラリをインポート」「ライブラリの追加…」を選び、「OpenCV」や「Video」と検索して「Install」すれば完了です。
使用時は、以下のようにしてライブラリを読み込めば使えるようになります。
import processing.video.*; import gab.opencv.*;
カメラを使う
まずはVideoライブラリの使い方を知りましょう。
パソコンに接続されているカメラにどんなものがあるかみてみます。
import processing.video.*; String[] cameras = Capture.list(); for(int i = 0; i < cameras.length; i ++){ println("[" + i + "] " + cameras[i]); } /* 実行結果 Processing video library using GStreamer 1.16.2 [0] FJ Camera [1] UCAM-C0220F */
Capture.list()でカメラの名前を探し、camerasという配列に収納しています。
cameras.lengthはカメラの数で、カメラの数の分だけfor文で繰り返してカメラの名前を表示しています。
このパソコンでは内蔵カメラ(0番)といつ買ったかもわからないウェブカメラ(1番)が接続されていることがわかりました。
では、カメラの映像を表示してみます。
import processing.video.*; Capture cam; String[] cameras = Capture.list(); void setup(){ size(640, 480); cam = new Capture(this, cameras[1]); cam.start(); } void draw(){ if(cam.available() == true){ cam.read(); } image(cam, 0, 0); }
Captureクラスを呼び出してcamと名付けておき、1番のカメラを使うように設定します。(Capture cam = new Capture(this, cameras[1]))
ウィンドウのサイズは、カメラの解像度がわかればその大きさに、わからなければ適当に設定して合うように調整すれば良いです。
cam.start()でキャプチャーを開始し、次の映像が使える(cam.available() == true)のときにcam.read()でキャプチャー映像を読み込み、image()で表示しています。
(映像は画像をすばやく変えて動いているように見せているものなので、cam.read()で画像をつくってimage()で描画する、を繰り返す感じです。)
撮った結果がこれです。(gifの生成には以前に紹介したものを使いました。)

顔を認識する
いよいよ顔認識をしてみます。
流れとしては、
解析したい画像を選ぶ
カスケードファイルを読み込む
解析
それに応じた処理
というような順です。
カスケードファイルは、検出したい物体の特徴が入ったもので、OpenCVを導入したときに一緒にダウンロードされています。検出したい物体に応じて読み込むファイルを変え、顔以外にも目や口、歩行者などが検出できるみたいです。
では、顔を検出したら四角で囲うようにしてみます。
import processing.video.*; import gab.opencv.*; import java.awt.*; Capture cam; String[] cameras = Capture.list(); OpenCV opencv; Rectangle[] faces; void setup(){ size(640, 480); cam = new Capture(this, cameras[1]); cam.start(); opencv = new OpenCV(this, cam); opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE); } void draw(){ if(cam.available() == true){ cam.read(); } image(cam, 0, 0); opencv.loadImage(cam); faces = opencv.detect(); for(int i = 0; i < faces.length; i ++){ noFill(); stroke(255, 0, 0); rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height); } }
opencv = new OpenCV(this, cam)で解析したい画像を選び、
opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE)でカスケードファイルを読み込み、
opencv.loadImage(cam)で解析したい画像を読み込んで、faces = opencv.detect()で解析、
for文以下でそれに応じた処理(顔の位置に赤い四角を描く)を行っています。
opencv = new OpenCV(this, cam)とopencv.loadCascade(OpenCV.CASCADE_FRONTALFACE)をdraw()内に入れればopencv.loadImage(cam)で読み込む必要はありませんが、カスケードファイルを読み込むたびに「読み込んだよ」という内容の文が表示されるのでかなりうるさいです。
また、解析した結果はRectangleというクラスで四角形として返され、RectangleクラスはJavaのAWTというライブラリを読み込まなければ使えないようなので、import java.awt.*;で読み込んでいます。(インストールは不要です)
顔をいくつか描いて認識するか試してみました。

目が丸くて口が二次元的に広がっていると顔となっている感じがします。
ちなみに、camの代わりにPImage img = loadImage("ファイル名");などで指定したimgを使うと、任意の画像に対しても顔認識をかけることができます。
まとめ
ということで、今回はprocessingで顔を認識させる方法について書いてみました。
ここまできたらあとはデジタル世界での体をつくれば完成です。
動かし方はいろいろと注意が必要そうですが…。
自分もデジタル世界で受肉しようかとも思いましたが、力尽きました。