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

OpenCVでキャプチャした画像から、Dlibで顔と輪郭などを検出する

More than 1 year has passed since last update.

はじめに

本ページは主に下記URLの、
https://www.pyimagesearch.com/2017/04/10/detect-eyes-nose-lips-jaw-dlib-opencv-python/
の内容をフォークしたものです。主な内容は画像からの顔検出ですが、今回はOpenCVではなくDlibというツールを用いています。モジュールのインストールは、

pip install dlib

これで簡単にできました。実はこっちの方が顔検出の精度が良いです(既存のライブラリを用いた場合の話ですが)。そこらへんの議論は、
http://blog.dlib.net/2014/02/dlib-186-released-make-your-own-object.html
ここが大変参考になりました。また今回のコードの変更点は、

  • 顔や輪郭検出をPC内蔵カメラからキャプチャした画像から行えるようにした
  • スペースキーを押すことで、画像を連番の画像名で保存できるようにした

となります。

顔検出

下の二行が主に顔検出を行う処理です。

detector = dlib.get_frontal_face_detector()
dets, scores, idx detector.run(img, 0)

検出された顔部分の情報はdetsに保存されます。顔検出のアルゴリズムとしてはSVMみたいなマージン最大化とHOG特徴量を用いているっぽいです。論文が公開されてます。

輪郭などの検出

実際のところ輪郭とそれ以外にあご、目、鼻、眉、口を一気に検出してくれます。ここでは先ほどのアルゴリズムとはまた別の勾配ブースティング木というアルゴリズムを用いているそうです。また、このライブラリを用いるにはデータセットが必要ですが、iBUG 300-Wというところが公開している既存のものがございます。データセットのダウンロードは下記URLを踏んでください。
http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2.
輪郭などの検出には下記のような宣言が必要になります。

predictor_path = "./shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(predictor_path)

また、輪郭などの検出は顔検出より切り取った情報は用いるので、先ほどのdetsを用いて、

shape = predictor(img_rgb, rect)
shape = face_utils.shape_to_np(shape)

shapeに保存した後、OpenCVやnumpyで扱いやすい形に変換します。また、shapeには68個の輪郭情報が含まれていてshape[0:68]と指定するとあご、目、鼻、眉、口、全体となりますが各部位と数字は常に対応しており、

  • 口 = 48:68
  • 右眉 = 17:22
  • 左眉 = 22:27
  • 右目 = 36:42
  • 左目 = 42:48
  • 鼻 = 27:35
  • あご = 0:17

各部位をしていすることも可能です。

コード

実装してみたものが下記になります。ここでは口のみを指定して切り出しています。スペースボタンを押すことで切り出した画像を保存できます。また、ESCを押すとウィンドウを閉じることができます。

capture_face_landmarks.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
import cv2
import dlib
import numpy as np
import imutils
from imutils import face_utils

def face_shape_detector_dlib(img):
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # frontal_face_detectorクラスは矩形, スコア, サブ検出器の結果を返す
    dets, scores, idx = detector.run(img_rgb, 0)
    if len(dets) > 0:
        for i, rect in enumerate(dets):
            shape = predictor(img_rgb, rect)
            shape = face_utils.shape_to_np(shape)
            clone = img.copy()
            cv2.putText(clone, "mouth", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
            # landmarkを画像に書き込む
            for (x, y) in shape[48:68]:
                cv2.circle(clone, (x, y), 1, (0, 0, 255), -1)
            # shapeで指定した個所の切り取り画像(ROI)を取得
            (x, y, w, h) = cv2.boundingRect(np.array([shape[48:68]])) #口の部位のみ切り出し
            roi = img[y:y + h, x:x + w]
            roi = cv2.resize(roi,(100,100))
        return clone, roi
    else :
        return img, None

def main():
    predictor_path = "./shape_predictor_68_face_landmarks.dat"
    predictor = dlib.shape_predictor(predictor_path)
    detector = dlib.get_frontal_face_detector()
    cap = cv2.VideoCapture(0)
    count = 0

    while True:
        ret, frame = cap.read()
        frame = imutils.resize(frame, width=500)
        frame, roi = face_shape_detector_dlib(frame)
        cv2.imshow('img', frame)
        if roi is not None :
            cv2.imshow('roi', roi)
        else :
            cv2.destroyWindow('roi')
        c = cv2.waitKey(1)
        if c == 27:#ESCを押してウィンドウを閉じる
            break
        if c == 32:#spaceで保存
            count += 1
            cv2.imwrite('./filename%03.f'%(count)+'.jpg', roi) #001~連番で保存
            print('save done')
    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':

    main()
ufoo68
IoT関係の会社で働いています。学生のときは画像認識を使った研究をしていました。最近はAWSかLINEを使った開発に興味があります。
access
SDNからセンサ、家電、電子書籍まで。ACCESSはあらゆるレイヤのデバイス、サービスを「繋げて」いきます。
http://jp.access-company.com
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
ユーザーは見つかりませんでした