LoginSignup
1
1

More than 3 years have passed since last update.

PyTorchのfacenetモデルで同一人物を判定→年齢・性別判定

Last updated at Posted at 2021-03-20

カメラに映っている限り同一人物でも判別し続けてしまう問題

UTKFaceデータセットを使って
・性別判断
・年代を推測(10代、20代、30代...)
する学習モデルを作成し、カメラに映った人物を判定するプログラムを作りましたが、同一人物でも何回も同じ判別結果を出してしまう状態では実用的とは言えないなという事で。
少し工夫しようとPyTorchのfacenetモデルを利用し実装してみました。

ライブラリやその機能を使うための準備

from tensorflow.python.keras.models import load_model

model = load_model('./Gender_judgment_fullmodel.h5', compile=False)
model_men = load_model('./men_Age_judgment_model.h5', compile=False)
model_women = load_model('./women_Age_judgment_model.h5', compile=False)

ディープラーニング学習済モデルの読み出しです。
Gender_judgment_fullmodel.h5 は性別を判定
men_Age_judgment_model.h5 は男性の年齢を判定
women_Age_judgment_model.h5 は女性の年齢を判定します。

import cv2
import numpy as np

face_cascade_path = './opencv/haarcascade_frontalface_default.xml'
eye_cascade_path = './opencv/haarcascade_eye.xml'
face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)

OpenCVの検出器を保存した場所からデータを読み出しています。
haarcascade_frontalface_default.xml は顔を検出
haarcascade_eye.xml は瞳を検出してくれます。

from facenet_pytorch import MTCNN, InceptionResnetV1

mtcnn = MTCNN(image_size=160, margin=10)
resnet = InceptionResnetV1(pretrained='vggface2').eval()

同一人物を判別するためのモデルを読み出します。

同一人物を判定するための関数を定義

def cos_similarity(p1, p2):
    return np.dot(p1, p2) / (np.linalg.norm(p1) * np.linalg.norm(p2))

img_st = []
def sameface(img1):
    if len(img_st) == 0:
        img_st.append(img1)
        return 0
    else:
        samecount = 0
        img_cropped1 = mtcnn(img1)
        img_embedding1 = resnet(img_cropped1.unsqueeze(0))
        p1 = img_embedding1.squeeze().to('cpu').detach().numpy().copy()

        for img2 in img_st:
            img_cropped2 = mtcnn(img2)
            img_embedding2 = resnet(img_cropped2.unsqueeze(0))
            p2 = img_embedding2.squeeze().to('cpu').detach().numpy().copy()

            img1vs = cos_similarity(p1, p2)

            if img1vs > 0.6:
                samecount = 1
        if samecount == 0:
            img_st.append(img1)
        return samecount

関数samefaceに入力された画像「img1」とそれまでに記録された画像から1枚ずつ抜き出した「img2」の
2枚の画像データを比較し、同一人物か判定するものです。
img1vs = cos_similarity(p1, p2) この値が高いほど同一人物である可能性が高くなります。

同一人物であれば年齢・性別判定は実行しない

n = 0
cap_interval = 0
cap = cv2.VideoCapture(0)
while True:
    if cap_interval == 100:
        cap_interval = 0
        ret, img = cap.read()
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
        for x, y, w, h in faces:
            facecut = img[y - 100: y + h + 100, x - 50: x + w + 50]
            face_gray = gray[y: y + h, x: x + w]
            eyes = eye_cascade.detectMultiScale(face_gray)
            if len(eyes) != 0:
                for (ex, ey, ew, eh) in eyes:
                    if sameface(facecut) == 0:
                        facecut2 = cv2.resize(facecut, (299, 299))
                        facecut2 = np.asarray(facecut2)
                        facecut2 = facecut2[None, ...]
                        preds = model.predict(facecut2)
                        facecut3 = facecut2.astype('float32') / 255
                        if np.argmax(preds) == 0:
                            sex = "men"
                            preds2 = model_men.predict(facecut3)
                        else:
                            sex = "women"
                            preds2 = model_women.predict(facecut3)
                        print(preds2)

                        if preds2 < 0.8:
                            age = "10代"
                        elif preds2 < 1.8:
                            age = "20代"
                        elif preds2 < 2.8:
                            age = "30代"
                        elif preds2 < 3.8:
                            age = "40代"
                        elif preds2 < 4.8:
                            age = "50代"
                        elif preds2 < 5.8:
                            age = "70代"
                        elif preds2 < 6.8:
                            age = "80代"
                        elif preds2 < 7.8:
                            age = "90代"
                        cv2.imwrite('{}_{}.{}'.format('data/temp/' + sex + age , n, "jpg"), facecut)
                        n += 1
                        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.imshow('video image', img)
    cap_interval += 1



    key = cv2.waitKey(10)
    if key == 27:  # ESCキーで終了
        break

cap.release()
cv2.destroyAllWindows()

実行すると落ちるようになったのでカメラのキャプチャ頻度を下げましたm(_ _)m
瞳を検出した時点で同一人物か判定し後処理をするようにしています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1