マスクをつけた顔画像の検出
自分の時はググってもあまり情報が出てこなかったので、一応ブログに残しておく。
先に結論
MTCNNそのまま使えばOKだった。
やりたいこと
ある画像に対して、
- マスクを着けている顔領域を検出する
- 更にランドマークを検出し、目が水平になるように画像を回転する
を実行したい。
やったこと
1にdlibのsimple_object_detectorを、2にdlibのshape_predictorをそれぞれ学習させた。 学習データは下記のリポジトリから画像データセットを拝借した。 アノテーションは手動で行い(pygameでアノテーション用GUIを作った)、100枚弱の画像データを作成した。
dlibのsimple_object_detectorやshape_predictorの学習は以下を参考にした。
ちなみにsimpel_object_detectorの方が過学習して結構困った。(optionのupsample_limitを大きくして対策した)
1については以下のリポジトリにマスク顔検出モデル(物体検出のSSDっぽい)があったので、こちらも試した。 github.com
結果
1にsimple_object_detector、2にshape_predictorを使った場合(顔領域の検出がダメ)
1にSSD、2にshape_predictorを使った場合(ランドマークの位置がずれている)
色々な画像で試してみた感じ、やっぱり1にSSDを使った方が精度はよかった。 特に2についてdlibの精度があまり向上しなかったので、ダメ元でMTCNN(facenet_pytorch)につっこんでみたら、かなりの精度で検出できてしまった。
まあ確かにMTCNNはCNNなのでちゃんと顔領域以外の情報も使っているので、それはそうだった…。dlibの方はそもそもデータが少ないとか、学習パラメータが適切でないとかはありそう。(前にアニメ顔の検出を学習させたときはかなり上手くできた)
一応コード
設定をいじりたい時はmodels/mtcnn.pyのMTCNNの引数を見てみるといいと思います。
import cv2 from facenet_pytorch import MTCNN img = cv2.imread("img.jpg") detector = MTCNN() boxes, _, points = detector.detect(img, landmarks=True) # デフォルトでは顔領域が最大面積の顔が出力される (models/mtcnn.pyのselect_largestの引数を参照) x0, y0, x1, y1 = boxes[0] # 検出した顔の矩形描画 cv2.rectangle(img, (int(x0), int(y0)), (int(x1), int(y1)), (255, 0, 0), 3) for i in range(4): x,y = points[0][i] # 検出したランドマークの丸描画 cv2.circle(img, (int(x), int(y)), 6, (255,0,0), -1) cv2.imwrite("result.png", img)