大量の写真から顔を切り抜いてデータセットをつくりたい--OpenCVで自動処理

#OpenCVで顔を切り抜く手法です

#機械学習のデータセットを作りたい
コンピュータビジョンのタスクには、人間の顔を含む画像をデータセットとするものがたくさんあります。
そのようなデータセットを作るために、大量の画像から顔を検出して切り抜きたい時があります。

#dlibの顔検出が使える
pythonを使えば、特別な設定なしで顔を切り抜けます。

#コード

今回はこちらの画像を切り抜きます。
<img src="https://user-images.githubusercontent.com/23278992/150853128-534f2676-2398-4d76-bdfe-344a68214a15.jpg", width=768>

顔検出機をインポートします。

```python
import dlib

faceDetector = dlib.get_frontal_face_detector()
```

顔検出機で画像内の顔の四角形座標を取ります。

```python
img = cv2.imread(img_path)
faces = faceDetector(img, 0)
```

検出した顔ごとに、元画像から切り抜きます。

```python
if len(faces) > 0:
    for i in range(0, len(faces)):      
      face_img = img[int(faces[i].top()):int(faces[i].bottom()),int(faces[i].left()):int(faces[i].right())]
```

<img src="https://user-images.githubusercontent.com/23278992/150853164-00b52b21-2f4f-43e6-812e-8b1867cbb193.png", width=256> <img src="https://user-images.githubusercontent.com/23278992/150853153-bdf105a9-ccf1-45dd-bf3e-6114557c2a5e.png", width=256> <img src="https://user-images.githubusercontent.com/23278992/150853146-94b03889-a5b6-49c5-801d-9ac3b93c9fd8.png", width=256>

もう少し広めに切り抜きたい場合は、顔の四角形にパディングを加えます。

```python
rect_top = int(faces[i].top()) - (face_h * padding)
if rect_top < 0:
   rect_top = 0
rect_bottom = int(faces[i].bottom()) + (face_h * padding)
if rect_bottom > img_h:
   rect_bottom = img_h
rect_left = int(faces[i].left()) - (face_w * padding)
if rect_left < 0:
   rect_left = 0
rect_right = int(faces[i].right()) + (face_w * padding)
if rect_right > img_w:
   rect_right = img_w

face_img = img[int(rect_top):int(rect_bottom),int(rect_left):int(rect_right)]
```

顔の四角形*1のパディングを四方に取ると、だいたいバストアップの画像が取れました。

<img src="https://user-images.githubusercontent.com/23278992/150856846-672de4f2-bf15-487a-b81e-2f0349093198.png", width=256> <img src="https://user-images.githubusercontent.com/23278992/150856833-ee70659c-335d-4d5e-ba38-57c7a3b762e1.png", width=256> <img src="https://user-images.githubusercontent.com/23278992/150856804-23931a06-801d-4d95-9cd5-09c2b436f550.png", width=256>

コード全体。

```python
import dlib
import cv2

def crop_face(path, write_path, padding):

   faceDetector = dlib.get_frontal_face_detector()
   img = cv2.imread(path)
   faces = faceDetector(img, 0)
  
   if len(faces) > 0:
      for i in range(0, len(faces)):
         img_h, img_w, c = img.shape
         face_h = int(faces[i].bottom() - faces[i].top())
         face_w = int(faces[i].right() - faces[i].left())

         rect_top = int(faces[i].top()) - (face_h * padding)
         if rect_top < 0:
            rect_top = 0
         rect_bottom = int(faces[i].bottom()) + (face_h * padding)
         if rect_bottom > img_h:
            rect_bottom = img_h
         rect_left = int(faces[i].left()) - (face_w * padding)
         if rect_left < 0:
            rect_left = 0
         rect_right = int(faces[i].right()) + (face_w * padding)
         if rect_right > img_w:
            rect_right = img_w

         face_img = img[int(rect_top):int(rect_bottom),int(rect_left):int(rect_right)]
         cv2.imwrite(write_path, face_img)
```

#自動処理で大量のデータを切り抜けます

上記コードで元データをループ処理すれば、自動で大量の画像を切り抜くことができます。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)