暗視カメラで睡眠時間帯の計測(3)

概要

posenetとopenposeの比較した結果、やはりopenposeを使わなければならないことになりました。

顔認識を書き込む実験に、face_recognitionのlibraryを用いることで、結構簡単なコードで、良く顔を認識できた。

PosenetとOpenposeの比較

PosenetやOpenposeを実装して、それぞれの出力を可視化します。

Openpose
Posenet

結果は以上の図になります、左側のがOpenpose、右側はPosenetです。

画像の様子を見ると、Posenetのkeypoint検出は不安定と感じる。
動きは小さくても、出力は変わる。また、常に複数の検出できないkeypointがある。

openposeだと、出力は安定だし、keypointもより多く検出できる。

以上より、openposeの効果はposenetより大幅に超えると考えられる。

現在開発しているデモ版では、keypointを基にして、手作りのルールを加わって、人の睡眠状態の判別を行うので、keypointの正しさは非常に重要だと考えられて、Posenetを使わないにします。

ただし、Posenetの利点としては、スビートが速い(fpsは何百を超える)とgpuのramの占有率が低いの二つが挙げられる

顔認識を書き込む

今回顔認識には、face_recognition libraryを使っています。
このlibraryの仕組みはまだ習っていないけど、一応実装して、結果を見たいと思います。

face_recognition

face_recogntionのセットアップはここに参考します

以下のコードを例として、このlibraryの使い方を簡単に説明する。

import face_recognition
import glob
import os
import pickle
import cv2
import numpy as np
import time
from tqdm import tqdm

class Face_wrapper:
    def __init__(self,dir):
        self.dir = dir
        self.known_face_names = []
        self.known_face_encodings = []
        self.process_this_frame = 0
        self._encoding()

    def _encoding(self):
        print('*** encoding face ***')
        image_paths = glob.glob(os.path.join(self.dir,'*.jpg'))

        names = [os.path.basename(path)[:-4] for path in image_paths]

        encoding_file_path = os.path.join(self.dir,'face_encondings.pkl')

        try:
            with open(encoding_file_path,'rb') as f:
                encoding_dict = pickle.load(f)
        except FileNotFoundError as e:
            encoding_dict = {}
        finally:
            for idx,name in tqdm(enumerate(names)):

                if name not in encoding_dict:
                    img = face_recognition.load_image_file(image_paths[idx])
                    try:
                        encoding_dict[name] = face_recognition.face_encodings(img)[0]
                    except IndexError as e:
                        print("*** can not recognize a face from :{}  skipping ***".format(image_paths[idx]))

        with open(encoding_file_path,'wb') as f:
            pickle.dump(encoding_dict,f)
        
        for key,value in encoding_dict.items():
            self.known_face_names.append(key)
            self.known_face_encodings.append(value)

    def recognize(self,image,image_to_draw,resize_ratio=1):
        small_img = cv2.resize(image,(0,0),fx=1,fy=1)
        rgb_small_img = cv2.cvtColor(small_img,cv2.COLOR_BGR2RGB)
        
        if self.process_this_frame%3 == 0:
            print('detect')
            time1=time.time()
            self.face_locations = face_recognition.face_locations(rgb_small_img,model='cnn')
            print(time.time()-time1)
            face_encodings = face_recognition.face_encodings(rgb_small_img,self.face_locations)

            self.face_names = []
            for face_encoding in face_encodings:

                matches = face_recognition.compare_faces(self.known_face_encodings,face_encoding)
                name = "Unknown"

                face_distances = face_recognition.face_distance(self.known_face_encodings,face_encoding)
                best_match_index = np.argmin(face_distances)
                if matches[best_match_index]:
                    name = self.known_face_names[best_match_index].split('_')[0]
                
                self.face_names.append(name)

        self.process_this_frame += 1

        print(self.face_names)

        for (top, right, bottom, left), name in zip(self.face_locations, self.face_names):

            cv2.rectangle(image, (left, top), (right, bottom), (0, 0, 255), 2)

            # Draw a label image a name below the face
            cv2.rectangle(image_to_draw, (left, bottom), (right, bottom+35), (0, 0, 255), cv2.FILLED)
            cv2.putText(image_to_draw, name, (left + 6, bottom + 15), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)

        return  image_to_draw

まず _encoding()を使って、認識したい人の画像を長さが128のエンコーディングに変換する。

encoding_dict[name] = face_recognition.face_encodings(img)[0]

そして、認識したい画像を入力とし、recognize()で顔認識を行う。
入力画像に顔の位置をみつかる。

self.face_locations = face_recognition.face_locations(rgb_small_img,model='cnn')

次に、その位置を利用して、入力画像に存在する顔をエンコーディングに変換する

face_encodings = face_recognition.face_encodings(rgb_small_img,self.face_locations)

そのエンコーディングを既存のエンコーディングと比較して、最も合うのが認識の結果になる。

matches = face_recognition.compare_faces(self.known_face_encodings,face_encoding)

実装結果

10人の顔写真を用意して、実装してみます。

結果は以下のURLで見られる。

https://youtu.be/6W2ULZxxLFg

説明すると、ラベルの数字1から10までは10人の氏名を示して、'me'は本人を示している。

結果を見ると、人が横になる時、顔が非常に小さいと見えても、ほとんど正しく認識できる。

横顔の場合に、誤認識や顔検出できないなどのことがあるけど、実験の結果(載せていない)によって、認識したい人の横顔写真もデータベースに入れると、誤認識の発生率を減らせる。

今後やりたいこと

  • デモ版を別の環境で実験する
  • いただいた顔認識コードを実行
  • 食事している人の検出のAIの検討

你可能感兴趣的:(暗視カメラで睡眠時間帯の計測(3))