Face01_list 1.1.2 の呼び出し方について解説します

Face01_list は顔認証技術を使って人数をカウントするアプリケーションです。
1.1.2 から呼び出し方が変わりました。
# coding utf-8
print('Start test_script')
import face01_list_112 as f
from multiprocessing import Pool, Process
import threading
(kaoninshoDir, outputDIR) = f.home()
p1 = Process(target=f.faceCrop, args=(
kaoninshoDir,
10,
'test.mp4'
)) # frame_skip, input
thread = threading.Thread(
target=f.openDIR,
args=([
outputDIR,
0.5,
1,
1,
'cnn',
'large'
])
) # tolerance, upsampling, jitters, mode, model
thread.start()
p3 = Process(target=f.person_count, args=(outputDIR,))
p1.start()
p3.start()
'''
各変数
frame_skip frame をスキップする回数
input 動画入力元を指定。test.mp4 か usb 。usb は Web カメラ
tolerance 閾値
upsampling アップサンプリング値。0: 80x80pixel, 1: 40x40pixel, 2: 20x20pixel
jitters ゆらぎ値
mode CNN or HOG
model small or large. small: 5-points method, large: 68-points method.
'''
コメントにもあるように、それぞれの関数に与える引数を自由に変えられるようになりました。これによって呼び出す側に自由度を与えますが、反対に顔認証のアルゴリズムや各々の変数の働きが分かっていないと期待しない動作になってしまいます。
ですので内部があまりよく理解できていない場合は「変数を指定しない」というのも一つの手です。デフォルトの動作として変数を与えなくても内部でよろしくやってくれるようになっています。ただしマスクをした人物も考慮する場合はきちんと働きを知っておく必要があります。
参考文献として「顔認証、マスクをつけたらどうなるの?」を最初にお読みになってください。
では一つづつ変数を確認していきましょう。
目次
各変数の働き
jitters
dlib を git clone した場所、私の場合なら $HOME/dlib/python_examples/ ディレクトリの face_jitter.py ファイルを参照してください。そこには以下のように記述してあります。
It takes an input image and disturbs the colors as well as applies random translations, rotations, and scaling.
「入力画像を受け取り、色を乱し、ランダムな移動、回転、スケーリングを適用します。」
jitters の値を大きくするほどランダムな変換の平均値をとるようになります。
しかしながら大きな値をとることによって入力画像が不確かなものになっていくこと、処理時間が長くなることが懸念されます。
通常は 0 ~ 2 あたりが良いように感じます。
upsampling
How many times to upsample the image looking for faces. Higher numbers find smaller faces.
「顔を探して画像をアップサンプリングする回数。 数値が大きいほど顔が小さくなります。」
具体的には upsampling が 0 の時 80×80 ピクセル、1 の時に 40×40 ピクセル、2 の時に 20×20 ピクセルの範囲で顔を探索します。処理時間とトレードオフになります。
下の例では 80x80px で良好な結果を出します。ですので upsampling=0 にします。

mode
CNN 形式または HOG 形式のどちらかを選びます。
CNN: Convolutional Neural Network
HOG: Histogram of Oriented Gradients
速度は HOG が速く CNN で同等の速度を出そうとすれば NVIDIA Titan X GPU が必要になります。
( $HOME/dlib/python_examples/dnn_mmod_face_detection_ex.cpp 参照)
GPU が使えない状況下にあっては HOG 形式を使うほうが現実的でしょう。
マスクをした顔の場合は CNN 形式が良好な結果を出力します。
model
small: 5-points method
large: 68-points method
となります。
マスクをはめたまま顔認証するときには small を選んでください。顔の半分が布で覆われているからです。
tolerance
0.6 を基準としてトレーニングしてあります。これより大きければ他人と判断されます。
アジア人の場合、0.45〜0.55 くらいに設定しましょう。
実際にはこの値次第で性能が変わってきてしまうくらい重要な値です。
何度か確かめてみるのが常套手段です。
frame_skip
フレームドロップの割合です。入力が 30fps の場合 frame_skip=2 では 15fps となります。処理するコンピュータの性能によってさばけるフレーム数は異なります。また mode に cnn を選んだ時などマシンに負荷がかかって処理が遅くなってしまう場合この引数を使ってフレームを手動でドロップします。
一般に mode では CNN 形式よりも HOG 形式のほうが負荷が軽く、model では large より small の方が負荷が軽くなります。
input
動画入力元をテスト用の test.mp4 と USB カメラの 2 種類から選ぶ事が出来ます。test.mp4 は 同一ディレクトリに配置してください。
mode と model の使い分け
まず各関数がどのような働きをしているか簡単に説明します。
faceCrop() 関数
入力される動画のサイズを適正に調整、顔の位置を特定して output フォルダへ顔画像ファイルをどんどん放り込みます。
また表示される動画に対し白枠で顔の周りを囲みます。
入力動画を停止する場合は「 q 」を押してください。
frame_skip ( 手動によるフレームドロップ ) はここで指定します。
openDIR() 関数
output フォルダを監視して与えられる引数 ( tolerance, upsampling, jitters, mode, model ) によって顔画像を同一人物かどうか振り分けていきます。
一つ一つの顔画像に対して 128D 顔識別子でエンコードして他の全てのファイルと比較します。同じ人物と評価された顔画像は same_person フォルダへと移動させます。
マスクの有り無しで考慮する場合には
mode: cnn
model: small
マスクを考慮に入れなければ
mode: hog
model: large
を指定してください。ただし mode の項で触れたとおり cnn を選択する場合は速度とトレードオフになることに注意してください。十分な性能の NVIDIA 製 GPU を搭載していれば速度的には問題になりません。
またチェックされる画像の照明の当たり具合や焦点ボケが発生している場合、cnn 形式でないと顔を認識できない場合があります。
次の person_count() 関数で素早く正しい人数を表示したいときには適切な NVIDIA 製の GPU が必要になります。
person_count() 関数
output フォルダを常に監視しています。3 秒毎に今いくつの顔画像ファイルがあるか標準出力します。
デフォルト値
face_crop() 関数の場合
p1 = Process(target=faceCrop, args=(
kaoninshoDir,
30,
'test.mp4'
)) # frame_skip, input
frame_skip は 30 。入力が 30ftp の場合一秒間に一回フレームを評価します。
input は動画入力元を指定します。テスト用の test.mp4 と usb を選べます。usb は Web カメラになります。
openDIR() 関数の場合
thread = threading.Thread(
target=openDIR,
args=([
outputDIR,
0.5,
1,
1,
'cnn',
'large'
])
) # outputDir, torelance, upsampling, jitters, mode, model
tolerance ( 閾値 ) は 0.5 、upsampling は 40×40 ピクセル。upsampling は 0 で80×80 ピクセル。jitters ( ゆらぎ値 ) は 1 、CNN 形式、68-points method です。マスクを考慮せず CPU のみで処理を前提としています。
person_count() 関数
p3 = Process(target=person_count, args=(outputDIR,))
特に引数は指定しません。
マスクを考慮する場合には
openDIR() 関数の場合
thread = threading.Thread(
target=openDIR,
args=([
outputDIR,
0.5,
1,
1,
'cnn',
'small'
])
) # outputDir, torelance, upsampling, jitters, mode, model
mode を cnn 、 model を small 、upsampling を 1 ( 40×40 ピクセル ) にします。
まとめ
上記リンク先も参照してください。
今回の変更により、現場でマスクあり・なしの状況変化や使用するコンピュータの負荷、テスト使用か Web カメラ入力かに柔軟に対応できるようにいたしました。
反面では変更できる変数や関数の働きを理解しないといけないものになっています。
今までは model や mode などごとに違うアプリケーションとしてご用意させていただいておりましたが、現場で柔軟に変えられたほうが良いだろう…という考えがありました。
もし疑問点・不明な点があればお問い合わせからご連絡いただけると幸いです。
検証動画
検証環境: Python 3.6.9, Ubuntu 18.04.3 LTS, Linux 4.15.0-66-generic, AMD Ryzen 5 1400, MemTotal: 16421236 kB, GeForce GT 710

GPU が最安値の物 ( GT 710 ) を使っているので顔のエンコードに時間がかかっています。最適な GPU を使えばリアルタイムで人数が表示されます。