「ラズパイとOpenCvを使って女優の顔認識をしてみる」を前回行いました。
そこではソースコードの解読を行わなかったので、本記事では詳しく解説していきます!
「顔認識に必要なライブラリまとめ(cv2. os. PIL)」と一緒に見ていただくと、理解が深まります。
では早速始めましょう。
顔認識ソースコード解説
以前の記事とソースコードは全く同じです。
01_face_detaset.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import cv2 import os cam = cv2.VideoCapture(0) cam.set(3, 640) # set video width cam.set(4, 480) # set video height face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # For each person, enter one numeric face id face_id = input('\n enter user id end press <return> ==> ') print("\n [INFO] Initializing face capture. Look the camera and wait ...") # Initialize individual sampling face count count = 0 while(True): ret, img = cam.read() img = cv2.flip(img, -1) # flip video image vertically gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_detector.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2) count += 1 # Save the captured image into the datasets folder cv2.imwrite("datasets/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w]) cv2.imshow('image', img) k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video if k == 27: break elif count >= 30: # Take 30 face sample and stop video break # Do a bit of cleanup print("\n [INFO] Exiting Program and cleanup stuff") cam.release() cv2.destroyAllWindows() |
1~2 | ライブラリインストール |
3 | 動画ファイル読み込み用のcamインスタンスを生成 |
4~5 | フレームの大きさを設定横480、高さ640ピクセル(下図参照) |
6 | カスケード分類器の読み込み |
8~9 | id入力待機 |
12~ | 無限ループ |
13 | 動画で得た画像ファイルの読み込み(imgに画像データ格納) |
14~15 | 取得画像を左右上下反転、白黒に |
16 | カスケード分類器を用いて正面の顔を識別 |
17~18 | OpenCVで画像(img)中に長方形を描画する際は、左上のx,y座標(x,y),と右下のx,y座標(x+w,y+h)がそれぞれ必要である。 x,y,w,hと4つ指定しているのは、facesに格納される戻り値がx軸,y軸,w(横幅),h(高さ)であるため |
19 | 画像取得分のcountをインクリメント |
21~22 | 取得した画像を指定したディレクトリに保存し、画面に表示する |
23~27 | waitkey(100)で100ミリ秒キーが押されるまで待つ。 ESCキー(キー番号27)が押される、もしくは30枚写真を取得したらループから抜ける |
29~31 | 動画ファイルを開放して、画像表示の画面を閉じる |
設定したフレームはこのようなイメージです。

02_face_detaset.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import numpy as np from PIL import Image import os import cv2 # Path for face image database path = 'datasets' recognizer = cv2.face.LBPHFaceRecognizer_create() detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml"); # function to get the images and label data def getImagesAndLabels(path): imagePaths = [os.path.join(path,f) for f in os.listdir(path)] faceSamples=[] ids = [] for imagePath in imagePaths: PIL_img = Image.open(imagePath).convert('L') # convert it to grayscale img_numpy = np.array(PIL_img,'uint8') id = int(os.path.split(imagePath)[-1].split(".")[1]) faces = detector.detectMultiScale(img_numpy) for (x,y,w,h) in faces: faceSamples.append(img_numpy[y:y+h,x:x+w]) ids.append(id) return faceSamples,ids print ("\n [INFO] Training faces. It will take a few seconds. Wait ...") faces,ids = getImagesAndLabels(path) recognizer.train(faces, np.array(ids)) # Save the model into trainer/trainer.yml recognizer.write('trainer/trainer.yml') # recognizer.save() worked on Mac, but not on Pi # Print the numer of faces trained and end program print("\n [INFO] {0} faces trained. Exiting Program".format(len(np.unique(ids)))) |
1~4 | 必要なライブラリをインストール |
6 | パスを定義(画像へのアクセス用) |
7 | 識別機の訓練に使用するLBPHFaceRecognizerをインスタンス化 |
8 | カスケード分類器の読み込み |
10~ | 別フォルダから画像とidを取得する関数 |
11 | datasetsに格納されている画像一覧をリストとして取得。listdir()はリストでファイル(ディレクトリ)を返すので、for文でそれらをfに格納。そのfをパス(datasets)と一つずつつなげている。 |
12~13 | 認識した顔、idを格納するリストを定義 |
14~ | 各画像に操作を施す |
15~16 | 白黒で画像をオープン、配列にし、uint8型に変更(通常、画像は符号なし8ビット整数で符号化される。) |
17 | ファイル名からidを抜き出す処理 |
18 | 取得した画像の顔を検出する |
19~22 | リストに長方形(y:y+h,x:x+w)を格納し2つの戻り値を返す |
24 | faces,idsに戻り値(リスト)を格納 |
25 | 取得した画像を訓練する(Local Binary Patternの抽出) |
27 | モデルをtrainerフォルダに保存 |
03_face_detaset.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import cv2 import numpy as np import os recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read('trainer/trainer.yml') cascadePath = "haarcascade_frontalface_default.xml" faceCascade = cv2.CascadeClassifier(cascadePath); font = cv2.FONT_HERSHEY_SIMPLEX #iniciate id counter id = 0 # names related to ids: example ==> Marcelo: id=1, etc names = ['None', 'Name'] # Initialize and start realtime video capture cam = cv2.VideoCapture(0) cam.set(3, 640) # set video widht cam.set(4, 480) # set video height # Define min window size to be recognized as a face minW = 0.1*cam.get(3) minH = 0.1*cam.get(4) while True: ret, img =cam.read() img = cv2.flip(img, -1) # Flip vertically gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale( gray, scaleFactor = 1.2, minNeighbors = 5, minSize = (int(minW), int(minH)), ) for(x,y,w,h) in faces: cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2) id, confidence = recognizer.predict(gray[y:y+h,x:x+w]) # Check if confidence is less them 100 ==> "0" is perfect match if (confidence < 100): id = names[id] confidence = " {0}%".format(round(100 - confidence)) else: id = "unknown" confidence = " {0}%".format(round(100 - confidence)) cv2.putText(img, str(id), (x+5,y-5), font, 1, (255,255,255), 2) cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1) cv2.imshow('camera',img) k = cv2.waitKey(10) & 0xff # Press 'ESC' for exiting video if k == 27: break # Do a bit of cleanup print("\n [INFO] Exiting Program and cleanup stuff") cam.release() cv2.destroyAllWindows() |
1~3 | ライブラリインストール |
4~8 | 識別機を読み込み、フォント(画像に記述する際の)を定義 |
12 | 読み取った画像に表示する名前をリストに格納する、各idと対応している id=0,None id=1,Name |
14~16 | 動画ファイル読み込みの設定 |
18~19 | 最小の横幅(0.1*640=64)と高さ(0.1*480=48)を定義 |
20~30 | 01と同様なので省略 |
31~ | 顔認識を行うfor文 |
32 | 長方形を描画(0,255,0)は色、2は線の太さ |
33 | predictで取得した画像を予測、戻り値としてconfidenceに確度を格納(確度が小さいほうが正答率が高い) |
35~40 | confidenceが100より小さければ認識している、大きければ(分散が大きい)別人 |
42~43 | 名前と確度を画面に表示する(画像を入れたい) |
45 | 画像(動画)を表示 |
46~ | 以下、重複するため省略 |
理解を深めていただけたでしょうか?
分からないところがあれば、コメントしていただければお答えします!