WEBカメラの映像をPythonとOpenCVで顔認識して遊ぶ

投稿日:

ハラショー!!今日ハ肉ノ日デスネ!!

というわけで、以下の記事等を参考にWEBカメラの映像をPythonとOpenCVで顔認識して遊んでみました。

これらを試したいきさつは最後に書くとして、とりあえず何を作ったのかを書いていきます。

何を作ったのか

  • WEBカメラの映像から顔と目を検出して目にはモザイクをかけるやつ
    • 目をつぶったら close your eyes と表示する
  • 目をつぶったら画面キャプチャを終了するやつ
    • 目が開いている時間をカウントダウン表示
    • ちょっとしたゲーム感覚

を作りました。

環境

Mac, Windows ともに下記環境で試しました。

Python

  • 3系です
    1
    2
    $ python -V
    Python 3.6.6

OpenCV(OpenCVPython)

PythonからOpenCVを使うにはOpenCVPythonなるものが必要なようなのでインストールします。

1
$ pip install opencv-python

確認

1
2
$ pip freeze | grep opencv
opencv-python==3.4.2.17

カスケード型分類器

顔認識させるにはカスケード型分類器なるものが必要なようなので
GitHub – opencv/opencv: Open Source Computer Vision Library
をcloneするなり落としてきて、 https://github.com/opencv/opencv/tree/master/data/haarcascades の各種.xmlを用意しておきます。

後述するサンプルでは、

  • haarcascades/haarcascade_frontalface_alt2.xml
  • haarcascades/haarcascade_eye_tree_eyeglasses.xml

を利用しました。
(カスケードっていうバンド昔いたよね)

WEBカメラの映像から顔と目を検出して目にはモザイクをかけるやつ

こんな感じです

検出した顔の周りに四角を描画、目の部分にモザイク処理を行っています。
少し分かりづらいかもしれませんが、目がつぶられたら画面にclose your eyesと表示しています。

目をつぶっている状態は、顔の検出が出来ているのに目の検出が出来ていない状態の時をそれとしました。

ソース

face_and_eye_recognition.py

import sys
import cv2 # OpenCV のインポート
'''
参考
@link http://ensekitt.hatenablog.com/entry/2017/12/19/200000
@link https://note.nkmk.me/python-opencv-face-detection-haar-cascade/
@link https://note.nkmk.me/python-opencv-mosaic/
@link http://workpiles.com/2015/04/opencv-detectmultiscale-scalefactor/
'''
# VideoCaptureのインスタンスを作成する。
# 引数でカメラを選べれる。
cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
print("can not open camera")
sys.exit()
# 評価器を読み込み
# https://github.com/opencv/opencv/tree/master/data/haarcascades
cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_alt2.xml')
eye_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_eye_tree_eyeglasses.xml')
def mosaic(src, ratio=0.1):
small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)
def mosaic_area(src, x, y, width, height, ratio=0.1):
dst = src.copy()
dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width], ratio)
return dst
while True:
# VideoCaptureから1フレーム読み込む
ret, frame = cap.read()
# そのままの大きさだと処理速度がきついのでリサイズ
frame = cv2.resize(frame, (int(frame.shape[1]*0.7), int(frame.shape[0]*0.7)))
# 処理速度を高めるために画像をグレースケールに変換したものを用意
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 顔検出
facerect = cascade.detectMultiScale(
gray,
scaleFactor=1.11,
minNeighbors=3,
minSize=(100, 100)
)
if len(facerect) != 0:
for x, y, w, h in facerect:
# 顔の部分(この顔の部分に対して目の検出をかける)
face_gray = gray[y: y + h, x: x + w]
# くり抜いた顔の部分を表示(処理には必要ない。ただ見たいだけ。)
show_face_gray = cv2.resize(face_gray, (int(gray.shape[1]), int(gray.shape[0])))
cv2.imshow('face', show_face_gray)
# 顔の部分から目の検出
eyes = eye_cascade.detectMultiScale(
face_gray,
scaleFactor=1.11, # ここの値はPCのスペックに依存するので適宜修正してください
minNeighbors=3,
minSize=(15, 15)
)
if len(eyes) == 0:
# 目が閉じられたとみなす
cv2.putText(
frame,
'close your eyes',
(x, y - 10), # 位置を少し調整
cv2.FONT_HERSHEY_PLAIN,
2,
(0, 255,0),
2,
cv2.LINE_AA
)
else:
for (ex, ey, ew, eh) in eyes:
# 目の部分にモザイク処理
frame = mosaic_area(
frame,
int((x + ex) - ew / 2),
int(y + ey),
int(ew * 2.5),
eh
)
# 顔検出した部分に枠を描画
cv2.rectangle(
frame,
(x, y),
(x + w, y + h),
(255, 255, 255),
thickness=2
)
cv2.imshow('frame', frame)
# キー入力を1ms待って、k が27(ESC)だったらBreakする
k = cv2.waitKey(1)
if k == 27:
break
# キャプチャをリリースして、ウィンドウをすべて閉じる
cap.release()
cv2.destroyAllWindows()

目をつぶったらキャプチャを終了するやつ

こんな感じです

遊び方

  • 起動したら、画面frameにフォーカスを合わせておきます
  • 顔をカメラに向け目をクワッと開けます
  • sを押します
    • 顔認識中かつまだスタートしていない場合、少しカクつく(キー入力を待っている)のでキー入力待ちが分かるかと思います
  • 目が開いている状態の場合、1秒ずつカウントダウン表示します
  • 目が閉じられたら画面キャプチャを終了します
    • 目が閉じられたとみなされたタイミングが最後の画面キャプチャとなります
  • escを押して終了です

ソース

blink_game.py

view raw blink_game.py hosted with ❤ by GitHub

実行方法

こういうディレクトリ構成だとします。

1
2
3
4
5
6
sample/
    haarcascades/
        haarcascade_frontalface_alt2.xml
        haarcascade_eye_tree_eyeglasses.xml
    face_and_eye_recognition.py
    blink_game.py
  • WEBカメラの映像から顔と目を検出して目にはモザイクをかけるやつ
    1
    $ python face_and_eye_recognition.py
  • 目をつぶったらキャプチャを終了するやつ
    1
    $ python blink_game.py

注意点

正直、OpenCVをはじめてさわったのでなんとも言えないですが処理性能はマシンのスペックに依存しそうです。
※ 処理の最適化をしていないとかそういうのは抜きで
あっちのPCではサクサク認識していたのに、こっちのPCだとなんかちょっとモッサリ。みたいな。

特に今回のサンプルでは、目をつぶったのに判定してくれないとか目の開閉判定がマシンのスペックによってチマチマでした。
ですので、サンプルを試して目の開閉判定にストレスがある場合、目の検出に用いているdetectMultiScale()scaleFactorの値を少し大きくしたりするとまぁまぁいい感じになったりします。
※ これでもだめならminSizeも少し大きくしてみたり、顔の位置を変えてみたり(近づく/離れる)、場所を変えてみたり(背景が白いとことか)とかしてみてください

1
2
3
4
5
6
7
# 顔の部分から目の検出
eyes = eye_cascade.detectMultiScale(
    face_gray,
    scaleFactor=1.31, # 1.1から1.31に変更
    minNeighbors=3,
    minSize=(15, 15)
)

特に、子供と遊ぼうとなった時に上記には注意が必要です。
(自分がそうだった!!)

追記

上記問題を少し改善したバージョンを書いてみました。
PythonとOpenCVを使ったまばたき検知ゲームの(プチ)改善 – Shimabox Blog

いきさつ

ここ最近、画像認識・画像解析とはどんな感じなのだろうかという名目のもと、Amazon Rekognitionを使って遊んでいます(一応業務)。

Webカメで撮っている映像をcanvasに描画 → サーバーにPOST → 解析 → サーバーから解析結果を返す → 解析結果をcanvasに重ねる

みたいなところまでは簡単にできました。
が、Webカメで撮っている映像に対してほぼリアルタイムで解析(検出)結果を重ねてみたいなぁとなるとちょっとめんどくさそうです。
(定期的にPOSTするん?とか、Amazon Kinesis Video Streamsとか、AWS DeepLensとかを使うん?とかサクッと試せる感が無いし、そもそもリアルタイムが無理じゃね?みたいな)

少し途方に暮れてなんか似た感じのやつないかなぁとpython webカメ 顔認識で調べてみると、ローカルでやる分には山程サンプルがあるじゃないですか!!みんなすごい!!
AWS SDK for Python (Boto3)を使っていたこともあり出来ればPythonで探していた

そもそも、画像認識・画像解析とはどんな感じなのだろうかというふわっとした目的なので、手段は問わず試してみたというのが今回のいきさつです。
少し調べてみると、jsでもリアルタイムで顔認識できるようなので近い内に試してみます。

試してみました

clmtrackr.jsやpico.jsで顔認識して遊ぶ | Shimabox Blog

おわりに

はじめてPython(OpenCVも)をさわったので正直戸惑いましたが、慣れてくるとワクワクするというかなんというか忘れていた何かを思い出したような気がしました。

今回のサンプルは最初にあげた記事を参考(ほぼ丸パクリ)にして書いただけなので自身でイケてるものを作れるように勉強していきたいです。と意識高い系の言葉で締めます。

Python楽しい!!

作成者: shimabox

Web系のプログラマをやっています。 なるべく楽しく生きていきたい。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.