自作データセットでピースサインと顔検知 +画像挿入でヒカキンになってみた【YOLOv5】

# はじめに
 - [YOLO v5](https://github.com/ultralytics/yolov5)を使ってピースサイン検出をしてみました

 https://github.com/ultralytics/yolov5

 - ピースサインの画像のデータセットがなかったのでデータセットを作成し、検出モデルを学習させて、webカメラでの検出を行いました
 - データセットの作成からwebカメラで検出するところまで、非常に簡単にできてびっくりしました
 - 興味のある方はぜひ遊んでみてください


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/69754281-059f-27e0-d1de-ac6e781fc542.png" width="800">

# やったこと
- ピースサインの画像収集
- アノテーション
- 学習
- webカメラでリアルタイム検出
- (おふざけ)検知された顔の部分に他の画像を挿入

## 開発環境
- Macbook Pro(13インチ, 2019年モデル)
- プロセッサ: 2.4 GHz クアッドコアIntel Core i5
- メモリ:    16GB

## ピースサインの画像収集
- 学習に用いるための画像を収集します
- まずGoogle画像検索で「ピースサイン」と入力すると以下のような結果が返ってきます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/8c820cfd-9f57-186b-d6a7-dc2811913144.png" width="1000">

- 次に画像検索結果を保存します、ここで形式を「ウェブページ、完全」にしてください
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/21077def-102e-4c21-245a-7938460b688c.png" width="800">

- そうすることで、簡単にgoogleの検索画像をまとめて取得することができます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/456ad491-f1d0-e007-728d-36e9b740940a.png" width="800">

- 取得した画像をそれぞれ見ていき、人間がピースしている写真のみを残しました
- その結果74枚のピースサインの画像を得ることができました

## アノテーション
- ピースサイン画像にアノテーションをしていきます
- YOLOv5のgithubによると[roboflow](https://roboflow.com/?ref=ultralytics)というwebアプリを推奨しているので、こちらを使ってアノテーションを行いました
- ログインするとroboflowの使い方のレクチャーがあるので、それに従います
- 操作自体は非常に直感的に行うことができます
- ピースサインの部分を囲って「peace-sign」というラベルをつけます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/54caa111-cdec-9332-bc61-564a85f019da.png" width="800">

- 顔の部分にも「face」というラベルをつけました
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/106b752f-bf2a-7610-a3a1-3238b9f24c81.png" width="800">

- 全ての画像にアノテーションをした後、なんとroboflowでデータ分割やリサイズ、さらに様々なデータ拡張ができます、素晴らしい！！
  - 今回は画像の反転と90度回転のデータ拡張を行いました
  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/2a3c814f-76d8-2eb5-7ef3-a58f5c6637a0.png" width="800">

- そして出力形式に「YPLO v5 Pytorch」を指定し、下のボタンは「show download code」に指定します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/d61552e4-d6cc-14a7-857d-d2d3418d68a2.png" width="800">

- ここに表示されているYour Download Codeを保存してください
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/32b263be-8de0-2ee7-044b-5b26bb160c86.png" width="800">

## 学習
- ここからコマンドライン上での作業に入ります
- アノテーションされた自作データセットを用いて、検出モデルを学習させます
- まず、YOLO v5をクローンします

```
C:\>git clone https://github.com/ultralytics/yolov5
```
- 次に必要なライブラリをインストールします
 - 様々なライブラリをダウンロードするので仮想環境でやると良いと思います [参考記事](https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e)

```
cd yolov5
C:\yolov5>pip install -r requirements.txt
```
- `yolov5/data`の中でroboflowで示されたデータのダウンロードコードを実行します

```
C:\yolov5/data>curl -L "ダウンロードURL" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip
```

- 次に自作データセットフォルダの中にある`data.yaml`ファイルの画像ファイルへのパスを変更します

```data.yaml
train: data/train/images  ##変更
val:   data/valid/images  ##変更

nc: 2
names: ['face', 'peace-sign']
```
- 次に4つのモデルの中から好きなモデルを選びます
 - 私はローカルの環境で学習させるのでパラメータの少ないYOLOv5sにしました
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/54dee4ff-6039-9cdd-9131-b460dcae5db5.png" width="800">

- そして、学習を行います

```
C:\yolov5>python train.py --img 640 --batch <バッチサイズ> --epochs <エポック数> --data <data.yalmファイルへのパス> --weights <モデル>
C:\yolov5>python train.py --img 640 --batch 16 --epochs 200 --data data/data.yaml --weights yolov5s.pt
```

- 学習が終わると`runs/train/exp/weights/best.pt`に学習済みモデルが出力されます
- 他にも`runs/train/exp/`フォルダの中にはlossの推移など学習の分析を自動でしてくれるので、それを見てるだけでも面白いですよ！

## webカメラでリアルタイム検出
- webカメラでピースサインと顔を検出をします

```
C:\yolov5>python detect.py --source 0 --weight <出力されたモデルへのパス>

C:\yolov5>python detect.py --source 0 --weight runs/exp/weights/best.pt
```
- 200枚の学習データでもそこそこ検出することができました！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/22f6ff32-8ea3-4f11-2f0f-f570ec119f43.png" width="800">

- データセットの作成からモデルを動すところまで、こんなに簡単にできるなんて驚きました

## (おふざけ)検知された顔の部分に他の画像を挿入
- 最後にピースと人間の顔が同時に検出された時に顔がヒカキンになるというシステムを作ってみました
- これはYOLOv5のフォルダにある検出を行うファイルである`detect.py`の検出した部分を囲って表示する部分と囲って表示する関数が定義されているファイルである`utils/plots.py`の2つを変更しました
- まず、`utils/plots.py`のAnotatorクラスに以下の関数を追加します

```utils/plots.py
  def face_change(self, box, face_image, label='', color=(128, 128, 128), txt_color=(255, 255, 255)):
      p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3]))
      p1, p2, p3, p4 = box[0].item(), box[1].item(), box[2].item(), box[3].item()
      FACE =cv2.resize(face_image, dsize=(int(p3)-int(p1), int(p4)-int(p2)))
      self.im[int(p2):int(p4), int(p1):int(p3)] = FACE
```
- 次に、`detect.py`を変更します
- `detect.py`の実行時のコマンドライン引数にヒカキンの顔の画像ファイルを指定できるようして、run関数内で画像ファイルを読み込み、顔とピースサインが同時に検出された場合に上で定義した関数を呼び出すことで完成します

- そして以下のように実行します

```
C:\yolov5>python detect.py --source 0 --weight best.pt --<自作の引数> <画像ファイルのパス>

C:\yolov5>python detect.py --source 0 --weight best.pt --face "./changed_faces/hikakin1.jpg"
```

- できた！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2392391/69754281-059f-27e0-d1de-ac6e781fc542.png" width="800">


## 参考文献
- [yolo v5で自作データを学習させ、PCカメラですみっコぐらしたちをリアルタイムに物体検出してみる](https://qiita.com/enya314/items/1bd053d6a81a156ff814)
- [【YOLO V5】AIでじゃんけん検出](https://qiita.com/PoodleMaster/items/5f2cc3248c03b03821b8#8-%E6%A4%9C%E5%87%BA-detect)
- [【YOLOv5】マスクしてる人・してない人を物体検出](https://qiita.com/YuyaOmori/items/ee3825d25afec8bf60ec)