MATLABとWebカメラで簡易顔検出(その1)

我が家では、3Dプリンタで作った治具をドアの錠前に貼り付けて、モータでオートロック/暗証番号解錠しています。
ドア外にカメラを貼り付けて、顔認証で解錠してぇな~~と思っていまして、先日に購入したMATLABで顔認証ソフトを作ろうとしています。

認証機能の前に、まずは顔の検出から。
MATLABでカメラ映像内の人の顔を検出するチュートリアルです。

本記事のスクリプトを実行する上で、Computer Vision Toolboxというオプションを追加で購入しています。

カメラ映像内の顔検出(単発)

スクリプト実行時にカメラ入力から1フレーム取得し、映像フレーム上に人の顔があれば、顔を検出した位置に黄色い枠を描画します。

参考ページ

スクリプト全体

ライブスクリプト全体を下記に示します。

webcamlist
%webcameraオブジェクト取得
cam = webcam(1)

%接続したcamera映像表示
preview(cam)
videoFrame = snapshot(cam); %スクリプト実行時点のスクショを1枚取得
imshow(videoFrame)

%顔検出器コンストラクト
%CascadeObjectDetectorには、顔の正面を検出できる事前学習済みの分類器を内臓
% (https://jp.mathworks.com/help/vision/ug/train-a-cascade-object-detector.html)
faceDetector = vision.CascadeObjectDetector(); %デフォルトで初期化→顔正面の検出器

%faceDetectorのアルゴリズムをVideoFrameに対して実行し、顔領域ボックスを取得
% ※bbox型:ボックスの(x座標,y座標,幅,高さ)を格納
boundingBox = step(faceDetector, videoFrame)

%結果確認
%もとのスクショに、顔位置のbboxデータを頂点とした長方形を描画
videoFrame_withBox = insertShape(videoFrame, 'Rectangle', boundingBox);

%作成した画像を表示
imshow(videoFrame_withBox)
実行結果

スクリプトを実行すると、カメラ入力から1フレーム取得して処理を行い、顔を検出した位置に黄色枠が追加されます。背景にモノが写り込んでても正しく顔を検出してますね。ちなみに、検出できるのは、あくまで正面よりで顔が傾いていない時のみのようです。正面を向いていても、顔が斜めに傾いていたら標準では検出できませんでした。

スクリプト解説

実行するコードを順番に解説していきます。

カメラ一覧表示
webcamlist


webcamlistコマンドを実行すると、利用可能なカメラデバイスの一覧を表示してくれます。1行目は皆さまお馴染みのlogicool C270を指しています。2行目は、スマホをwebカメラ化するためにインストールしたツールを指しています。iVCamはC270が届くまでのツナギで使っていました。

後述のスクリプトでカメラを選択できるように、利用可能なカメラの一覧を最初に確認するようにしましょう。

カメラ接続+動作確認
%webcameraオブジェクト取得
cam = webcam(1)

%接続したcamera映像表示
preview(cam)

webcamlistで使いたいカメラデバイスのインデックスを確認しました。ここでは、1行目に認識されているC270を使うことにします。

webcam関数の引数として1を与えると、webcamlistで1行目に認識していたC270に関連づいたカメラオブジェクトを取得できます。
(※MATLAB言語では、配列・行列のインデックスは0ではなく1始まりな点に注意!)

preview関数に取得したカメラオブジェクトを与えると、カメラからの入力映像を確認できます。preview関数を実行しているのは、あくまでデバイスの動作確認のためです。ですので、正常動作していることを確認できたら、preview関数の行はコメントアウトしておくとよいでしょう。

人の顔の検出

videoFrame = snapshot(cam); %スクリプト実行時点のスクショを1枚取得
imshow(videoFrame)

%顔検出器コンストラクト
%CascadeObjectDetectorには、顔の正面を検出できる事前学習済みの分類器を内臓
% (https://jp.mathworks.com/help/vision/ug/train-a-cascade-object-detector.html)
faceDetector = vision.CascadeObjectDetector(); %デフォルトで初期化→顔正面の検出器

%faceDetectorのアルゴリズムをVideoFrameに対して実行し、顔領域ボックスを取得
% ※bbox型:ボックスの(x座標,y座標,幅,高さ)を格納
boundingBox = step(faceDetector, videoFrame)

%結果確認
%もとのスクショに、顔位置のbboxデータを頂点とした長方形を描画
videoFrame_withBox = insertShape(videoFrame, 'Rectangle', boundingBox);

%作成した画像を表示
imshow(videoFrame_withBox)

snapshot関数にカメラオブジェクトを与えることで、スクリプト実行時のカメラ映像の1フレームを取得できます。フレームデータはimshow関数に与えることで表示できます。ここでは比較用にオリジナルを表示しておきましょう。

MATLABでは、人の顔を検出できる分類器がデフォルトで用意されていて、vision.CascadeObjectDetector()をデフォルト(引数無し)で実行することで、人の顔の検出器を取得できます。

そして、step関数に検出器と画像を入力します。step関数とは、第1引数に受け取るSystem Object型のオブジェクト(ここでは顔検出器)のアルゴリズムを、第2引数に受けるデータ(ここでは映像フレーム)に対して実行させる関数です。今回では、顔が画像中にあれば、顔位置をbbox型のデータで返してくれます。
 ※bbox型:ボックスの(x座標,y座標,幅,高さ)を格納

なお、System Objectのアルゴリズムを実行する上では、下記のどれでもよいそうで。「検出器のアルゴリズム実行する」という意味合いだと、個人的には2番目のオブジェクト指向言語風の書き方が好きですが、世の中的には1番目の記法が主流なんですかね。

boundingBox = step(faceDetector, videoFrame);
boundingBox = faceDetector.step(videoFrame);
boundingBox = faceDetector(videoFrame)

確認のために、もとの画像の上に、検出した顔領域を描画します。insertShape関数でもとの映像フレーム上に顔領域の四角形を描画し、imshow関数で表示させます。すると、実行結果の画像のように元の映像フレームの上に顔領域のボックスを描画してくれます。

おまけ

メガネ・グラサンをかけててもいけました。

ちなみにこの写真のマスクは、今回の記事用にAmazonでYoutuberマスクを買って肌色でスプレーしました。

まとめ

公式の顔検出サンプルを一部改造して、カメラ入力映像中の顔位置を検出するサンプルを作成しました。

顔認証で使う際は、カメラ映像から入力顔画像を切り取る時に使えますね。あとは、顔を撮影した動画から教師データを作成したりする時などにも。

記事中のサンプルで、動作確認用のコードを除いた正味の処理は実質5行です。このテの画像処理は初体験だったのですが、すぐに動いてめっちゃ便利ですね。

コメント