face recognition with opencv and scikit-learn
DESCRIPTION
A lightweight implementation of Face Recognition system with Python. OpenCV and scikit-learn. Python, OpenCv, scikit-learnによる簡易な顔認識システムの実装. Tokyo.Scipy5にて発表。TRANSCRIPT
OpenCVと scikit-learnで楽々顔認識
杜 世橋 FreeBit@lucidfrontier45
26, January, 2013
顔認識とは?
Face Detection
Face Recognition
Lena
画像から人の顔部分を抜き取る
与えられた顔の人物を推定する
顔認識とは?Face Detection
Haar Cascade Classifier
Haar-like feature
Weak classifier
Weak classifier
Weak classifier
AdaBoost
原著論文は Paul Viola and Michael J. Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. IEEE CVPR, 2001.日本語ではこちらのスライドがわかりやすい。
+
顔認識とは?Face Recognition
EigenFaceInput PictureX (dim = d1 x d2)
PCA
Projected PictureY (dim = p < d1 x d2)
Nearest Neighbor orOther Supervised Prediction
* ちなみに PCA の代わりに Fisher 判別分析を使用した FisherFace やLPP を使用した LaplacianFace などもある。
M. Turk and A. Pentland (1991).“Face recognition using eigenfaces”.
http://scikit-learn.org/ より
実装イメージFace RecognitionFace Detection
OpenCV
NumPy
SciPy
scikit-learn
Face Detection は OpenCV の CascadeClassifierモジュールを使用。Face Recognition は scikit-learn を用いて適当に実装。( 実は OpenCV にも )
実装イメージ
Face Detection
import numpy as npimport cv, cv2
#画像ファイルを読み込んでモノクロ化&輝度を正規化img = cv2.imread(img_file) #imgはndarray型!gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)gray_img = cv2.equalizeHist(gray_img)
#顔検出器を作成cascade_file = “haarcascade_frontalface_default.xml" detector = cv2.CascadeClassifier(cascade_file)
実装イメージ
Face Detection
#検出を実行flags = cv.CV_HAAR_FIND_BIGGEST_OBJECT | cv.CV_HAAR_DO_ROUGH_SEARCHTrects = detector.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=3, minSize=(64, 64), flags=detact_flags)
#戻り値はxy座標、幅、高さ。OpenCVのndarrayは(y,x)の順なので注意x, y, w, h = rects[0]face = np.array(gray_img[y:y+h, x:x+w])
#後のためにリサイズして次元を統一しておくmin_size = (64, 64)face = cv2.resize(face, min_size, interpolation=cv.CV_INTER_AREA)
実装イメージデータの型変換
def convImgMat(img, mat_type="opencv"): shape = img.shape #まずは32bit floatに変換 img = np.asanyarray(img, dtype=np.float32) if mat_type == "opencv" and len(shape) == 1: size = int(math.sqrt(img.size)) img = np.array(img.reshape((size, size)) * 255.0, dtype=np.uint8) #0-255を0-1に正規化し、1次元に展開する elif mat_type == "numpy" and len(shape) == 2: img = img.flatten() / 255.0 else: raise ValueError("wrong format") return img
OpenCV の関数は通常は 2 次元の 8bit int の配列を返してくる。顔認識に進む前に 32bit float の 1 次元配列に変換しておく。
実装イメージFace Recognition( 学習編 )
import numpy as npfrom sklearn.decomposition import PCA
class FaceRecognizer():
def fit(face_imgs, labels)#トランスフォーマーを作成self.transformer = PCA(n_components=0.9)
#係数を学習self.transformer.fit(face_imgs)
#特徴量とラベルをセットself.features = self.transformer.transform(face_imgs)self.labels = np.array(labels)
実装イメージFace Recognition( 予測編 )
from scipy.spatial import distance
class FaceRecognizer():…def predict(face_img)
#特徴量を計算feature = self.transformer.transform(face_imgs)
#距離を計算し、最も近いものを選ぶ distances = distance.cdist(self.features, [feature]).flatten()
idx = distances.argmin()
#もし距離がしきい値以上だったら未知人物を返すif distances[idx] > MAX_DISTANCE:
return UNKNOWN_PERSONelse:
return self.labels[idx]
システム化今回作った顔認識システムの構成
-顔検出 Haar Cascade Classifier (OpenCV)-顔認識 LaplacianFace (scikit-learn独自レポジトリ )- DB Redis (redis-py経由 )- HTTPD Lighttpd (cgiは python)
学習した係数や顔画像、射影した特徴量はndarray としてRedis に保存。その際にはtostringメソッドで変換する。取り出すときには逆に np.fromstringを使用。
システム化
追加学習時には LPP 係数は学習せず、射影した特徴量のみを計算して Redis に追加。
予測時には Redis から特徴量をすべて引っ張ってきて最近傍探索を行う。
精度はまだあまりよくない ...
おわりおすすめの本Mastering Opencv with Practical Computer Vision Projects Chapter 8 が OpenCV を利用した顔認識。性能を大きく左右する前処理についても詳しく解説されている。Android や iOS で OpenCV を利用したプログラム開発もある!
おわり
今回使用作成したコード
LPP を実装した scikit-learn のレポジトリ ( そのうち本家にマージします )https://github.com/lucidfrontier45/scikit-learn/tree/lpp
PyFace レポジトリhttps://github.com/lucidfrontier45/PyFace