見出し画像

レガシーAIシリーズ(1) 高精度アニメ顔検出


はじめに


人間の顔の検出は様々な方法で、実装されています。これらの実装を用いてアニメ顔の検出を行うと、検出精度が極端に悪化します。アニメ顔の検出は長らく、Nagadomi氏による lbpcascade_animeface が利用されていました。


ただ、このソフトエアも検出精度については決して高いわけではなく、最近の画風のアニメ顔では50%以下の場合もあります。そこで私達は最近のアニメ顔を用いて深層学習を行い、90%を超える高精度なアニメ顔検出AIを開発しました。学習データへのタグ付けでは
girl
boy
small
big
を定義してイます。
AIのアーキテクチャはSSDです。
今回の実装では単体で動かす実装とAPIサーバ化も行いました。

環境設定

リポジトリをクローンし、ディレクトリにあるrequirements.txtを用います。

仮想環境作成

python3.11 -m venv tkh
source tkh/bin/activate

その後、リポジトリのディレクトリに移動して環境を整えます。

pip install -r requirements.txt

テスト

python face_d.py

このような結果が得られます。
data_confidence_level= 0.5
[array([715.51153564, 551.3989563 , 883.10192871, 678.04962158]), array([144.3817749 , 374.29866028, 327.38531494, 509.09394836]), array([354.35580444, 143.80113602, 519.19592285, 277.49780273]), array([517.37347412, 40.60820389, 684.95288086, 183.29874802])] [0, 0, 0, 0] [0.9151747, 0.8857878, 0.8198777, 0.68608177]

[0.9151747, 0.8857878, 0.8198777, 0.68608177] この部分が検出コンフィデンスレベルを表し、高い精度でアニメ顔であると推定してイます。
またその前の [0, 0, 0, 0] ですが0はgirlを表し4人の顔が全てgirlであったことを示します。

face_d.pyでは入力イメージフォルダの指定などが行えます。ソースコード冒頭を参照下さい。

AnimeFaceDetectクラス

アプリからの呼び出しに便利なようにクラスを行っています。
face_d_api_class.py

import torch
from utils.ssd_model import SSD
from utils.ssd_predict_show import SSDPredictShow
import cv2

class AnimeFaceDetect:
    def __init__(self, weight_path='./weights/ssd_best8.pth'):
        # 初期設定: クラス分類とネットワーク設定
        self.voc_classes = ['girl', 'girl_low', 'man', 'man_low']
        self.ssd_cfg = {
            'num_classes': 5,  # 背景クラスを含めたクラス数
            'input_size': 300,  # 入力画像サイズ
            'bbox_aspect_num': [4, 6, 6, 6, 4, 4],  # DBoxのアスペクト比
            'feature_maps': [38, 19, 10, 5, 3, 1],  # 特徴マップのサイズ
            'steps': [8, 16, 32, 64, 100, 300],  # DBoxのサイズを決定
            'min_sizes': [21, 45, 99, 153, 207, 261],  # 最小サイズ
            'max_sizes': [45, 99, 153, 207, 261, 315],  # 最大サイズ
            'aspect_ratios': [[2], [2, 3], [2, 3], [2, 3], [2], [2]]
        }
        self.net = SSD(phase="inference", cfg=self.ssd_cfg)
        net_weights = torch.load(weight_path, map_location={'cuda:0': 'cpu'})
        self.net.load_state_dict(net_weights)
        print('ネットワーク設定完了:学習済みの重みをロードしました')

    def face_det(self, img_data, confidence_level):
        # 基本的な顔検出を行うメソッド
        ssd = SSDPredictShow(eval_categories=self.voc_classes, net=self.net)
        rgb_img, predict_bbox, pre_dict_label_index, scores = ssd.ssd_predict(img_data, confidence_level)
        dnum = len(pre_dict_label_index)
        return dnum, rgb_img, predict_bbox, pre_dict_label_index, scores

APIサーバ

上記クラスを用いてAPIサーバを準備しました。
face_d_api_server.py

python face_d_api_server.py

サーバ起動後、クライント側からアクセスするクラスが
face_d_api_class_client.py
です。

python face_d_api_client_test.py --test 3

実行後、以下の出力と画像が得られます。
dnum= 4 bbox= [array([715.51153564, 551.3989563 , 883.10192871, 678.04962158]), array([144.3817749 , 374.29866028, 327.38531494, 509.09394836]), array([354.35580444, 143.80113602, 519.19592285, 277.49780273]), array([517.37347412, 40.60820389, 684.95288086, 183.29874802])] label= [0, 0, 0, 0] score= [0.9151747, 0.8857878, 0.8198777, 0.68608177]

dnum= 4とは検出が4体出会ったと言う意味です。続いて検出位置のアレイ、ラベルと続きます。またイメージにはバウンディングboxが書き込まれています。

提供するファンクションはソースコードにコメントで詳しく説明しています。
face_det(img_data,level)
img_dataからアニメ顔を検出する。ssdのオリジナル出力を得る
face_det_sq(img_data,level)
img_dataからアニメの顔部分を検出。顎から眉毛あたりまでの正方形を得る。
face_det_head(img_data,ratio,shift,level)
img_dataからアニメ頭全体を検出する

まとめ

このAIで画像中にキャラクタがいるかどうかの判定が高精度で可能になりました。アップロードファイルの自動判定などでも利用可能です。なおここでは触れていませんが、全身検出用のウエイトも学習済みです。

謝辞
タグ付けと学習、及び基本的な検出コードの作成をしてくれたK.A君に感謝いたします。