Help us understand the problem. What is going on with this article?

PythonのOpenCVで顔認識

概要

PythonのOpenCVで顔認識をしたい人に向けた記事です。
本記事では画像、カメラの映像,mp4ファイルから顔を検出する方法、画像から顔だけを切り取って保存する方法を解説します。

環境

macOS Catalina 10.15.4
Python 3.7.5
opencv-python 4.2.0.34
numpy 1.18.2

OpenCVのインストール

$ pip install opencv-python

ディレクトリ構成

.
├── cascades
│  └── haarcascade_frontalface_default.xml
├── image_detect.py
├── images
│  └── 001.jpg
├── trimmed
└── venv

ディレクトリ構成はこのようになっている。
cascadesフォルダの中の顔検出用の検出器はPythonがインストールされているディレクトリまたは仮想環境のディレクトリのlib/python3.7/site-packages/cv2/dataにある。

顔を検出して矩形で囲む

画像から検出

image_detect.py
import cv2

cascade_path =  "./cascades/haarcascade_frontalface_default.xml"
img_path = "./images/001.jpg"
color = (255, 255, 255) #検出した顔を囲む四角形の色

src = cv2.imread(img_path,0)
gray = cv2.cvtColor(src,cv2.cv2.COLOR_BAYER_BG2GRAY)
cascade = cv2.CascadeClassifier(cascade_path)
rect = cascade.detectMultiScale(gray)
if len(rect) > 0:
    for x, y, w, h in rect:
        cv2.rectangle(src, (x, y), (x+w, y+h), color)

cv2.imshow('detected', src)
cv2.waitKey(0)
cv2.destroyAllWindows()


x, y, w, h は 顔の左上のx座標、顔の左上のy座標、顔の横幅、顔の高さに対応している。
また、OpenCVに限ったことではないがxy座標の原点は画像の左上である。

カメラの映像から検出

image_detect.py
import cv2

cascade_path = "./cascades/haarcascade_frontalface_default.xml"
cascade = cv2.CascadeClassifier(cascade_path)
color = (255, 255, 255) #検出した顔を囲む四角形の色
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    rect = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30))
    if len(rect) > 0:
        for x, y, w, h in rect:
            cv2.rectangle(frame, (x, y), (x+w, y+h), color)
    cv2.imshow('detected', frame)
    key = cv2.waitKey(1)
    if key == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

cv2.VideoCapture()の引数をカメラのデバイス番号にするとカメラの映像を取得できるが、mp4ファイルなどへのパスを入力することで動画ファイルも扱うことができる。

顔を検出してトリミング、保存する

画像が一枚のとき

image_detect.py
import cv2

cascade_path =  "./cascades/haarcascade_frontalface_default.xml"
img_path = "./images/001.jpg"
out_path = "./trimmed/"


src = cv2.imread(img_path,0)
gray = cv2.cvtColor(src,cv2.cv2.COLOR_BAYER_BG2GRAY)
cascade = cv2.CascadeClassifier(cascade_path)
rect = cascade.detectMultiScale(gray)
if len(rect) > 0:
    for i,[x, y, w, h] in enumerate(rect):
        img_trimmed = src[y:y + h, x:x + w]
        file_name = "{}.jpg".format(i)
        file_path = out_path + file_name
        cv2.imwrite(file_path, img_trimmed)

for文でenumerateを使うことでループカウントとrectの中身を同時に取得できる
トリミングをするときはスライスで取り出す。

複数の画像からまとめて検出したいとき

image_detect.py
import cv2
import os

cascade_path =  "./cascades/haarcascade_frontalface_default.xml"
img_path = "./images/"
out_path = "./trimmed/"

files = os.listdir(img_path)
cascade = cv2.CascadeClassifier(cascade_path)

for file in files:
    src = cv2.imread(img_path+file,0)
    gray = cv2.cvtColor(src,cv2.cv2.COLOR_BAYER_BG2GRAY)
    rect = cascade.detectMultiScale(gray)
    if len(rect) > 0:
        for i,[x, y, w, h] in enumerate(rect):
            img_trimmed = src[y:y + h, x:x + w]
            file_name = "{}_{}".format(i,file)
            file_path = out_path + file_name
            cv2.imwrite(file_path, img_trimmed)

imagesフォルダにトリミングしたい画像を入れて実行すると"{顔のインデックス番号}_{元のファイル名}"の形式でtrimmedフォルダに保存される。

まとめ

OpenCVって便利だね

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした