粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

pythonマルチスレッド + ビデオ取得からの顔認識&切り出し

pythonでマルチスレッドが思ったよりも簡単にできるっぽいので試してみました。

手順

以下のサイトに親切な説明が付いています。
Pythonでマルチスレッド処理 - Qiita

  • threading.Threadのサブクラスを作る.
  • threading.Threadのインスタンスを作る.

ふむふむ。ってどの事だかよくわかりませんね。(ザコ並の感想)

以下自分用メモですが言い直すと

  • サブクラスの作成:

class hoge(threading.Thread)とすることでhogeはthreading.Threadを継承したサブクラスになる。ということ。

runで定義される関数を作ることで、hoge.startでその関数を実行できるということ。

動画からの画像読み出し

cap = cv2.VideoCapture(0)

でデフォルトのカメラデバイスをオープンします。0のところをファイル名にしたら動画ファイルも読めるのかな?(憶測)

画像をcapから取得するのは

ret, frame = cap.read()

と書け、frameにイメージが。retに成功したかのflagが保存されます。
正直、以下のように書くことが多いのでほとんど気にしないかとは思いますが。

while(cap.isOpened()):

コード

例のごとく様々なところを参考にしています。
cascade_pathのところは過去記事を参照してください。

# -*- 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 = "haarcascade_frontalface_alt.xml"
		self._frame = frame

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

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

		#物体認識(顔認識)の実行 -> each rectangle coordinate of face is in _facerect
		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 = 'faces/' + self._now + '.jpg'
				#切り出し
				self.x = self._rect[0]
				self.y = self._rect[1]
				self.width = self._rect[2]
				self.height = self._rect[3]
				self.dst = self._frame[self.y:self.y+self.height, self.x:self.x+self.width]	
				#認識結果の保存				
				cv2.imwrite(self._image_path, self.dst)



# main


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

ret, frame = cap.read()

while(cap.isOpened()):
	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キー or'q' を押されたら終了
	if k == 27:
		break
	if k == ord('q'):
		break

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

結果と反省

結果うまくマルチスレッドを機能させることに成功しました。
すべて一つのコードで書いていた時よりも目に見えて実行速度は向上したと思います。

これで顔領域をたくさん切り取って学習なんかに使えそうですね。

ただ、秒単位でしか名前をつけていないのでいくつかデータを無駄に捨てているのがやや問題でしょうか、
あと、意外と顔以外の領域もキャプチャしてきます。これも学習をするならどける必要がありそうです。