顔認証

```python
# -*- coding: utf-8 -*-
"""
Created on Sat Jan 21 21:34:25 2023

@author: user
"""

import cv2
import os
from facenet_pytorch import MTCNN, InceptionResnetV1
from PIL import Image
import numpy as np
import tkinter
from tkinter import font
import tkinter.ttk as ttk
import pygetwindow as gw
import pyautogui
import time

def textfile_list(path):
    #ディレクトリ内にあるテキストファイルの名前を取得
    path_search=path
    folderfile=os.listdir(path_search)
    
    file_list=[]
    for n in folderfile:
        file_list.append(n)

    return file_list

def cos_similarity(p1,p2):
    #コサイン類似度を算出
    return np.dot(p1,p2)/(np.linalg.norm(p1)*np.linalg.norm(p2))

def face_analysis():
    
    #顔検出のAI
    #image_size: 顔を検出して切り取るサイズ
    #margin:顔周りの余白
    mtcnn=MTCNN(image_size=160,margin=10)
    #切り取った顔を512個の数字にするAI
    resnet=InceptionResnetV1(pretrained="vggface2").eval()
    #顔画像を読み込み    
    cam_img=Image.open("C:\\face_matching\\cam_face\\cam_image.jpg")
    #顔部分で切り取り
    cam_cropped=mtcnn(cam_img)
    try:  #顔が検出されなかった場合exceptの処理を実行
        #512個の数字に変換
        cam_embedding=resnet(cam_cropped.unsqueeze(0))    
    except: 
        #空のリストを作成する
        cam_p=[]
        return cam_p
    #切り取った顔画像を保存
    cam_cropped=mtcnn(cam_img,save_path="cropped_img.jpg")
    #pytorchの型tensorなのでnumpyに変換
    cam_p=cam_embedding.squeeze().to("cpu").detach().numpy().copy()
    
    return cam_p

def write_textfile(path,array):
    
    #テキストファイルに浮動小数点数を文字列に変換し書き込む
    with open(path,"w")as file:
        for d in array:
            file.write(str(d)+"\n")

    file.close()

def load_textfile(path):
    
    #テキストファイルから文字列を読み取り浮動小数点数に変換してリストに追加
    value=[]
    with open(path,"r")as file:
        for d in file:
            value.append(float(d))
    
    file.close()
    return value
    
def distance_judge(cos):
    #算出したコサイン類似度と設定されたしきい値を比較して同一人物が判定
    file=open("C:\\face_matching\\judge\\Level.txt","r") #しきい値を読み込み
    level=file.read()
    level=level.rstrip("\n")
    file.close()    
    
    if cos>=float(level): #しきい値より大きい場合Trueを返す
        return True
    
    return False
    
def get_password(path,file_name):
    #与えられたファイル名に対するログインID,パスワードを取得
    with open(path,"r",encoding="utf-8") as file:
        for w in file:
            file_data=w.rstrip("\n")
            data_list=file_data.split()
            if file_name==data_list[0]:
                break
    file.close
    return data_list[1],data_list[2],data_list[3]

def input_pw(id_value,pw,root):
    #XsionのページにID,パスワードを入力
    memo_window = gw.getWindowsWithTitle('Edge')[0]
    memo_window.activate()
    
    pyautogui.press("tab")
    time.sleep(0.5)
    pyautogui.write(id_value)
    time.sleep(0.5)
    pyautogui.press("tab")
    time.sleep(0.5)
    pyautogui.write(pw)
    time.sleep(0.5)
    pyautogui.press("enter")
    
    root.destroy()

def name_window(name,id_value,pw):
    #認証に成功したとき名前ボタンを画面上に表示
    root=tkinter.Tk()
    root.title("Your Name") #タイトルを指定
    root.geometry("800x400")#画面のサイズを指定
    
    frame=ttk.Frame(root)
    frame.pack(fill=tkinter.BOTH,padx=20,pady=20)
    
    text=tkinter.StringVar(frame)
    text.set(name)
    button=tkinter.Button(frame,textvariable=text,width=40,height=50,font=("MSゴシック","40"),command=lambda:input_pw(id_value,pw,root))
    button.pack()
    
    root.mainloop()


if __name__ == '__main__':

    os.chdir("C:\\face_matching")
    capture=cv2.VideoCapture(0)

    while(True):
        ret,frame=capture.read()
        cv2.imshow("frame",frame)
    
        key=cv2.waitKey(1)&0xff
    
        if key ==ord("s"): #"s"が入力された場合
            cv2.imwrite("C:\\face_matching\\cam_face\\cam_image.jpg",frame) #カメラから画像を取得
            image_p=face_analysis() #顔を解析し数値化
            if image_p==[]:#空のリストが返ってきた場合ループの先頭へ(顔が検出されなかった時)
                continue
            write_textfile("C:\\face_matching\\face_value\\p_value.txt", image_p) #数値化したデータをテキストファイルに書込み
        
        if key==ord("r"): #"r"が入力された場合
            cv2.imwrite("C:\\face_matching\\cam_face\\cam_image.jpg",frame) #カメラから画像を取得
            cam_p=face_analysis() #顔を解析し数値化
            if cam_p==[]:#空のリストが返ってきた場合ループの先頭へ(顔が検出されなかった時)
                continue
            #登録された顔の数値データが書き込まれたテキストファイルのファイル名をを取得
            file_name_list=textfile_list("C:\\face_matching\\sub_value")
        
            for file_name in file_name_list:
                #登録された顔の数値データを読みだす
                p_value=load_textfile("C:\\face_matching\sub_value\\"+file_name)
                #カメラで撮影した顔の数値データと、登録された顔の数値データの類似度を算出する
                cos_value=cos_similarity(p_value,cam_p)
            
                if distance_judge(cos_value): #登録された顔と同一人物と判定された場合
                    id_value,pw,name=get_password("C:\\face_matching\\pw\\pw_list.txt", file_name)
                    name_window(name, id_value, pw)#XsionのサイトにID,パスワードを入力
                
        elif key & 0xFF ==ord("q"):
            break
    
    capture.release()
    cv2.destroyAllWindows()


```