OpenCVで顔認証をやってみました
使った画像がよくなかったのか精度がイマイチでちょっと残念な結果に。。。
環境
顔画像抽出
今回、アイドルの写真やアニメ画像での顔認識を試していたので、学習用の顔写真を集めます
inとなる画像は複数人が掲載されておりそこから一人一人に分割します
import time from datetime import datetime from pathlib import Path import os import cv2 root = os.getcwd() classifier = cv2.CascadeClassifier(root + '/haarcascade_frontalface_default.xml') # classifier = cv2.CascadeClassifier(root + '/lbpcascade_animeface.xml') output_dir = root + '/out' if not os.path.exists(output_dir): os.makedirs(output_dir) p = Path(root + "/in") list = list(p.glob("*")) for file in list: print(file) # 顔の検出 image = cv2.imread(str(file)) # グレースケールで処理を高速化 gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) faces = classifier.detectMultiScale(gray_image) for i, (x, y, w, h) in enumerate(faces): now = time.time() utc = datetime.utcfromtimestamp(now) # 一人ずつ顔を切り抜く face_image = image[y:y+h, x:x+w] output_path = os.path.join(output_dir, '{0}_{1}.jpg'.format(i, datetime.now().timestamp())) cv2.imwrite(output_path, face_image) for x,y,w,h in faces: # 四角を描く cv2.rectangle(image, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=3) cv2.imwrite(output_dir + '/' + str(file), image)
顔認識モデルは2種類使っています
用途に合わせて切り替えてください
顔認識できた座標で切り取り新たな画像を作成します
ここで作られた画像が個別認識用の学習画像となります
個別認識
抽出した画像を元に個別認識を行います
認識率が高いものが出てくると思うのですが、100%以上であっても一致してないことがあり、何がイケないのか悩ましいところです。。
いろいろな画像を試してみて検証する必要がありそうです
import cv2 import os import numpy as np root = os.getcwd() train_path = root + '/out' test_path = root + '/in' cascadePath = root + "/haarcascade_frontalface_default.xml" # cascadePath = root + "/lbpcascade_animeface.xml" faceCascade = cv2.CascadeClassifier(cascadePath) # LBPH recognizer = cv2.face.LBPHFaceRecognizer_create() def get_images_and_labels(path): images = [] labels = [] files = [] for f in os.listdir(path): # 画像のパス image_path = os.path.join(path, f) image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale(image) # 検出した顔画像の処理 for (x, y, w, h) in faces: roi = cv2.resize(image[y: y + h, x: x + w], (200, 200), interpolation=cv2.INTER_LINEAR) images.append(roi) # ファイル名からラベルを取得 "0_xxxxx.jpg みたいなファイル名を想定している" names = f.split("_") labels.append(int(names[0])) files.append(f) return images, labels, files # トレーニング画像を取得 images, labels, files = get_images_and_labels(train_path) # トレーニング実施 recognizer.train(images, np.array(labels)) # テスト画像を取得 test_images, test_labels, test_files = get_images_and_labels(test_path) i = 0 while i < len(test_labels): label, confidence = recognizer.predict(test_images[i]) print("Test Image: {}, Predicted Label: {}, Confidence: {}".format(test_files[i], label, confidence)) i += 1 cv2.destroyAllWindows()
get_images_and_labels
メソッドで学習用画像や判定画像を読み込み、 recognizer.train
で学習しています
recognizer.predict
で予測を行い顔認証を行っています
まとめ
僅かなコードで簡単に顔認証を行うことができましたが、画像の選定や学習用ファイルの精度が大事な感じです
ネットで拾った画像ではなく自分で撮った写真で試してみたいと思います
今回使ったソースはGitHubに上がっています