読者です 読者をやめる 読者になる 読者になる

FaMirror Project

報告的なこと、技術的なこと

OpenCVを使ってWebカメラの映像の顔認識を行う【python】

備忘録 顔認識 python OpenCV

概要

Webカメラの映像をウィンドウに映し、バックグラウンドで顔認識を行います。

顔を見つけられたら、顔の部分に四角をつけて画像を保存します。

画像ファイルから顔認識を行う場合は、前回の記事を参照してください。
famirror.hateblo.jp

説明

以下のようにループを組むことでウィンドウにWebカメラの映像を映すことができます。

import cv2

cap = cv2.VideoCapture(0)

while True:
	ret, frame = cap.read()

	#frameを表示
	cv2.imshow('camera capture', frame)

	#10msecキー入力待ち
	k = cv2.waitKey(10)
	#Escキーを押されたら終了
	if k == 27:
		break

#キャプチャを終了
cap.release()
cv2.destroyAllWindows()

Escキーが押されるまで無限ループでカメラから取得した映像をウィンドウに表示し続けます。

このループの中に顔認識の手順を埋め込んでもいいのですが、処理が重くなりカメラ映像のフレームがかなり落ちたので、顔認識は別スレッドで行います。

今回は顔認識を行い、顔が存在すれば白い線をつけて保存するFaceThreadというクラスを作成しました。

import cv2
import threading
from datetime import datetime

class FaceThread(threading.Thread):
	def __init__(self, frame):
		super(FaceThread, self).__init__()
		self._cascade_path = "/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml"
		self._frame = frame

	def run(self):
		#グレースケール変換
		self._frame_gray = cv2.cvtColor(self._frame, cv2.cv.CV_BGR2GRAY)

		#カスケード分類器の特徴量を取得する
		self._cascade = cv2.CascadeClassifier(self._cascade_path)

		#物体認識(顔認識)の実行
		self._facerect = self._cascade.detectMultiScale(self._frame_gray, scaleFactor=1.2, minNeighbors=3, minSize=(10, 10))

		if len(self._facerect) > 0:
			print '顔が検出されました。'
			self._color = (255, 255, 255) #白
			for self._rect in self._facerect:
				#検出した顔を囲む矩形の作成
				cv2.rectangle(self._frame, tuple(self._rect[0:2]),tuple(self._rect[0:2] + self._rect[2:4]), self._color, thickness=2)

			#現在の時間を取得
			self._now = datetime.now().strftime('%Y%m%d%H%M%S')
			#認識結果の保存
			self._image_path = self._now + '.jpg'
			cv2.imwrite(self._image_path, self._frame)

threading.Threadのサブクラスを作ることによってpythonでマルチスレッド処理を行うことができます。

詳しくは以下のリンクを参照してください。
qiita.com

画像を保存する時は現在の時間をファイル名としてしています。

これによって、以下のようにループの中でFaceThreadを実行すればよいことになります。

while True:
	#動いているスレッドの数が1だったら顔認識実行
	if(threading.activeCount() == 1):
		th = FaceThread(frame)
		th.start()

FaceThreadが動いていない時はアクティブになっているスレッドはメインスレッドの1つなので、「threading.activeCount()」は1を返します。

この時だけFaceThreadを実行することによって、スレッドの数を制限しています。

スレッドを使って並列処理することによってかなりフレーム落ちは防げるようになりましたが、まだ時々重くなります。

C++を使って処理した方がいいかもしれません。

コード

# -*- coding:utf-8 -*-
#webカメラの映像から顔を探し白の枠線をつけて保存するプログラム

import cv2
import threading
from datetime import datetime

class FaceThread(threading.Thread):
	def __init__(self, frame):
		super(FaceThread, self).__init__()
		self._cascade_path = "/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml"
		self._frame = frame

	def run(self):
		#グレースケール変換
		self._frame_gray = cv2.cvtColor(self._frame, cv2.cv.CV_BGR2GRAY)

		#カスケード分類器の特徴量を取得する
		self._cascade = cv2.CascadeClassifier(self._cascade_path)

		#物体認識(顔認識)の実行
		self._facerect = self._cascade.detectMultiScale(self._frame_gray, scaleFactor=1.2, minNeighbors=3, minSize=(10, 10))

		if len(self._facerect) > 0:
			print '顔が検出されました。'
			self._color = (255, 255, 255) #白
			for self._rect in self._facerect:
				#検出した顔を囲む矩形の作成
				cv2.rectangle(self._frame, tuple(self._rect[0:2]),tuple(self._rect[0:2] + self._rect[2:4]), self._color, thickness=2)

			#現在の時間を取得
			self._now = datetime.now().strftime('%Y%m%d%H%M%S')
			#認識結果の保存
			self._image_path = self._now + '.jpg'
			cv2.imwrite(self._image_path, self._frame)

# カメラをキャプチャ開始
cap = cv2.VideoCapture(0)

while True:
	ret, frame = cap.read()

	#frameを表示
	cv2.imshow('camera capture', frame)

	if(threading.activeCount() == 1):
		th = FaceThread(frame)
		th.start()

	#10msecキー入力待ち
	k = cv2.waitKey(10)
	#Escキーを押されたら終了
	if k == 27:
		break

#キャプチャを終了
cap.release()
cv2.destroyAllWindows()