SKJvillageのスクリーンショットで既存の顔のカスケード分類器を評価

# １．あらすじ
　今後の顔分類の実験の準備として、OpenCVのカスケード分類器を用いてゲーム実況系Youtubeグループ[SKJvillage](https://www.youtube.com/@SKJVillage)のスクリーンショットから顔のみを切り抜く処理を行いました。複数の分類器で顔を切り抜きを行いましたが、本件のデータに対しては分類器ごとに向き不向きがあると感じたので、今回は実際に切り抜いた画像に注目し性能評価を行いました。

# ２．改めて[SKJvillage](https://www.youtube.com/@SKJVillage)とは
 3人組のゲーム実況系YouTubeチャンネル。高校時代の親友で「早稲田・慶應・上智」大学にそれぞれ進学し、大手企業を退職後、2018年に３人でYoutube活動開始。
(https://www.youtube.com/@SKJVillage/about より参考)

# ３．顔を切り抜くためのプログラム
　今回は、Google Colaboratory上でpythonとOpenCVを用いて、SKJvillageのスクリーンショットから顔を探し、顔だけを切り抜いた画像を生成しました。

```python:SKJ_FaceClipping.ipynb
!git clone https://github.com/opencv/opencv.git

import matplotlib.pyplot as pyplt
import cv2 as cv
import os
import glob

#画像から顔を切り取りfaceのディレクトリに保存

names = ["saikatsu","sa2","shinka","sai×sa","sai×shin","sa×shin","SKJ","others"]
img_path = "/content/drive/My Drive/Colab Notebooks/SKJvillage_dataset/"
face_path = "/content/drive/My Drive/Colab Notebooks/SKJvillage_dataset/face/"

for i in range(len(names)):
    #元画像の顔部分を囲み、64×64にリサイズし、ファイル名ごとにフォルダに出力
    in_dir = img_path + names[i] + "/*.jpg"
    in_jpg = glob.glob(in_dir)
    os.makedirs(face_path + names[i], exist_ok=True)
    print(names[i])
    print(len(in_jpg))

    for num in range(len(in_jpg)):
        image=cv.imread(str(in_jpg[num]),cv.IMREAD_UNCHANGED)
        if image is None:
            print("Not open:",num)
            continue

        img_gs = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
        #分類器の選択(今回はaltかalt2かdefault)
        cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_alt.xml")
        #cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_alt2.xml")
        #cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_default.xml")
        # 顔認識の実行
        face_list=cascade.detectMultiScale(img_gs, scaleFactor=1.1, minNeighbors=2,minSize=(64,64))
        #顔が１つ以上認識できた時
        if len(face_list) > 0:
            for rect in face_list:
                x,y,width,height=rect
                image = image[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
                if image.shape[0]<64:
                    continue
                image = cv.resize(image,(64,64))
                #保存
                fileName=os.path.join(face_path+"/"+names[i],str(num)+".jpg")
                cv.imwrite(str(fileName),image)
                print(str(num)+".jpgを保存!.")
        #顔が認識できなかった時
        else:
            print("no face")
            continue
        print(image.shape)
```
## OpenCVのダウンロード
　OpenCVには、顔認識を行う分類器が数々設定されています。最初に下の1文を実行することで、github上の顔認識に関する分類器の特徴量を扱えます。

```
!git clone https://github.com/opencv/opencv.git
```

## 分類器の取得
　分類器の選択を行い、読み込みと取得をすることで既存の分類器を扱うことができる。今回は、正面を向いている顔を検出できる分類器の中で、前回の実験で性能が良かった以下の3つの分類器で実験を行います。
・haarcascade_frontalface_alt.xml
・haarcascade_frontalface_alt2.xml
・haarcascade_frontalface_default.xml

**↓前回の記事**

https://qiita.com/nyar_ramen/items/476fc53307e3f6b8e7b3

```
#分類器の選択(今回はaltかalt2かdefault)
cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_alt.xml")
#cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_alt2.xml")
#cascade = cv.CascadeClassifier("/content/opencv/data/haarcascades/haarcascade_frontalface_default.xml")

# 顔認識の実行
face_list=cascade.detectMultiScale(img_gs, scaleFactor=1.1, minNeighbors=2,minSize=(64,64))
```

## 画像の切り抜き
　選択した分類器で顔認識後に、認識した箇所を64×64にリサイズして、faceというフォルダにどんどん出力していきます。出力する際には、カテゴリ(saikatsu,sa2,shinkaなど)ごとにフォルダを生成し、jpegファイルで出力します。

```
#顔が１つ以上認識できた時
if len(face_list) > 0:
    for rect in face_list:
        x,y,width,height=rect
        image = image[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
        if image.shape[0]<64:
            continue
            image = cv.resize(image,(64,64))
            #保存
            fileName=os.path.join(face_path+"/"+names[i],str(num)+".jpg")
            cv.imwrite(str(fileName),image)
            print(str(num)+".jpgを保存!.")
#顔が認識できなかった時
else:
    print("no face")
        continue
    print(image.shape)
```
# ４．顔を切り抜いた結果
　以下の画像のように、顔部分が切り抜かれた64×64の画像を切り抜くことができました。ちゃんとメンバーの顔を切り抜けている場合もあれば、謎の画像が生成されている場合もありますね。(リトルマックイケメンすぎ問題)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128356/3c930617-5855-e666-0a89-79c977515b68.png)
　出力は以下のように、作成したデータセットのカテゴリごとに出力されます。データセット、カテゴリについては、画像の下の記事から！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128356/d11898a4-dde8-3dcb-f3b3-563421d40e90.png)

https://qiita.com/nyar_ramen/items/74694fa1eb313e002450

# ５．本件の各分類器の評価
　今回は、3つの分類器でそれぞれ実行し、顔の切り抜きを行いました。扱う分類器ごとに結果が異なっていたので、せっかくなら評価してみようかなと思いました。どれだけ顔を認識できているかを数値で評価します。
※ここでの顔は、SKJvillageのメンバー以外の顔も含めます。

## どれだけ顔を認識できているか(数値で評価)
　**出力した枚数**だけで評価するのではなく、**「何枚出力していてそのうち何枚が顔であるか」という割合**で評価を行います。割合で評価する理由としては、「出力した画像は多いけどそれらが顔ではない」「出力した画像は少ないけど一応全て顔である」といった場合が存在したからです。下の表に結果をまとめます。
　表記として、**「x(y/z)」** (**x**:顔の割合,**y**:顔の枚数,**z**:出力した画像の枚数)と表記しています。例えば、「0.5000(25/50)」と書いてある場合は、「出力した画像50枚のうち顔だったのは25枚で割合は0.5000」という意味です。割合の有効数字は4桁とします。

|  | saikatsu | sa2 | shinka | sai×sa | sai×shin | sa×shin | SKJ | others | 全体 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|  |   |   |   |   |   |   |   |   |   |
| alt | 0.8873(63/71) | 0.7222(52/63) | 0.7241(21/29) | 0.8750(14/16) | 1.000(3/3) | 0.7000(14/20) | 0.8304(93/112) | 0.5000(4/8) | **0.7952**(264/332) |
| alt2 | 0.8857(62/70) | 0.7361(53/72) | 0.6897(20/29) | 0.7895(15/19) | 1.000(4/4) | 0.6000(12/20) | 0.7674(99/129) | 0.5000(4/8) | 0.7664(**269**/351) |
| default | 0.7692(60/78) | 0.4943(43/87) | 0.5116(22/43) | 0.5909(13/22) | 0.5000(2/4) | 0.4583(11/24) | 0.6015(80/133) | 0.6000(6/10) | 0.5910(237/401) |

　結果を見ると、切り抜くことのできた顔の全体の枚数はalt2が269枚と多いですが、割合だとaltの方が0.7952と大きいようでした。カテゴリごとに見てもaltの方が割合が大きい場合が多く、**割合で見るとaltの性能が高いという結果になりました。** defaultは多くの画像の出力していますが、顔の割合は小さく性能がいいとは言えません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128356/bc271a44-e7c4-b09f-fbda-32f0f7c9c72b.png)
　棒グラフにして見ても、**割合を見た時にaltが優秀だった**のが分かりやすいですね。「安安、お前スーパーマーケットですね(?)」

# ６．終わりに
　今回、SKJvillageファンの方から収集したスクリーンショットから顔の認識を行い、認識した顔の切り抜きを行いました。切り抜いた顔は、SKJメンバーの顔に関する機会学習のために扱いたいと思います！
　**ご覧いただきありがとうございました！**


# 参考
https://qiita.com/nirs_kd56/items/bc78bf2c3164a6da1ded