けやみぃアーカイブ

CV勉強中の大学生のアウトプットです

マスクをつけた顔画像の検出

自分の時はググってもあまり情報が出てこなかったので、一応ブログに残しておく。

先に結論

MTCNNそのまま使えばOKだった。

やりたいこと

ある画像に対して、

  1. マスクを着けている顔領域を検出する
  2. 更にランドマークを検出し、目が水平になるように画像を回転する

を実行したい。

やったこと

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)