はじめに
顔認証による入退室管理のWebアプリケーションのプロトタイプを作ってみたので記事にしてみました。
コード
import streamlit as st
import cv2
import face_recognition
import numpy as np
import os
def load_known_faces(directory="known_faces"):
known_faces = []
known_names = []
for filename in os.listdir(directory):
path = os.path.join(directory, filename)
image = face_recognition.load_image_file(path)
encoding = face_recognition.face_encodings(image)[0]
known_faces.append(encoding)
known_names.append(os.path.splitext(filename)[0])
return known_faces, known_names
def main():
st.title("入室")
# カメラを開く
video_capture = cv2.VideoCapture(0)
# 事前に保存された顔の情報を読み込む
known_faces, known_names = load_known_faces()
# Streamlit上で表示する画像と名前を格納する変数
st_image = st.empty()
st_name = st.empty()
# 入室のボタン
entry_button = st.button("入室")
while True:
# カメラからフレームを取得
ret, frame = video_capture.read()
# 顔認識の処理
face_locations = face_recognition.face_locations(frame)
face_encodings = face_recognition.face_encodings(frame, face_locations)
# 画像に顔の枠を描画
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
# 保存された顔との照合を行う
matches = face_recognition.compare_faces(known_faces, face_encoding)
name = "Unknown"
# 照合が成功した場合、名前を取得
face_distances = face_recognition.face_distance(known_faces, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
# 近似度が一定以下の場合、"Unknown"を表示
if face_distances[best_match_index] > 0.4:
name = "Unknown"
st_name.text(name)
else:
name = known_names[best_match_index]
# 照合が成功したらボタンを表示
st_name.text(name)
entry_clicked = entry_button
if entry_clicked:
st.text("入室しました")
# Streamlit上で画像を表示
st_image.image(frame, channels="BGR", width=640)
if __name__ == "__main__":
main()
説明
現状の処理はかなり簡単なものとなっており、
def load_known_faces(directory="known_faces"):
known_faces = []
known_names = []
for filename in os.listdir(directory):
path = os.path.join(directory, filename)
image = face_recognition.load_image_file(path)
encoding = face_recognition.face_encodings(image)[0]
known_faces.append(encoding)
known_names.append(os.path.splitext(filename)[0])
return known_faces, known_names
で同フォルダ内にあるknown_facesから人物画像を読み込み、それぞれの人物の顔の特徴量を抽出します。
その後、
while True:
# カメラからフレームを取得
ret, frame = video_capture.read()
# 顔認識の処理
face_locations = face_recognition.face_locations(frame)
face_encodings = face_recognition.face_encodings(frame, face_locations)
# 画像に顔の枠を描画
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
# 保存された顔との照合を行う
matches = face_recognition.compare_faces(known_faces, face_encoding)
name = "Unknown"
# 照合が成功した場合、名前を取得
face_distances = face_recognition.face_distance(known_faces, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
# 近似度が一定以下の場合、"Unknown"を表示
if face_distances[best_match_index] > 0.4:
name = "Unknown"
st_name.text(name)
else:
name = known_names[best_match_index]
# 照合が成功したらボタンを表示
st_name.text(name)
entry_clicked = entry_button
if entry_clicked:
st.text("入室しました")
# Streamlit上で画像を表示
st_image.image(frame, channels="BGR", width=640)
で、カメラから一枚ずつフレームを抽出し、face_recognitionでフレームから人物の顔を認識します。
その後、認識した顔とknown_faceに登録されている顔画像の照合を行い、一定以上の近似値であった場合は該当者の名前を表示、近似値が一定以下であった場合にはUnknownを表示する形になっています。
今後の目標
今後の目標としては、データベースを接続し、メンバーの入退室状況を管理できるようにしたいです。