"""load_preset_image.pyのバックアップ用
このファイルは使用されません。
"""
import os
from os.path import exists, isdir
from pathlib import Path
from shutil import move
from typing import List, Tuple
import numpy as np
import numpy.typing as npt
from face01lib.api import Dlib_api # type: ignore
from face01lib.logger import Logger # type: ignore
from face01lib.utils import Utils # type: ignore
from face01lib.Calc import Cal
Dlib_api_obj = Dlib_api()
Utils_obj = Utils()
[ドキュメント]
class LoadPresetImage:
def __init__(
self,
log_level: str = "info"
) -> None:
self.log_level = log_level
# Setup logger
name: str = __name__
dir: str = os.path.dirname(__file__)
parent_dir, _ = os.path.split(dir)
self.logger = Logger(self.log_level).logger(name, parent_dir)
Cal().cal_specify_date(self.logger)
[ドキュメント]
def load_preset_image(
self,
deep_learning_model: int,
RootDir: str,
preset_face_imagesDir: str,
upsampling: int = 0,
jitters: int = 100,
mode: str = 'hog',
model: str = 'small'
) -> Tuple[List, List]:
"""Load face image from preset_face_images folder.
Args:
deep_learning_model (int): You can select from 0 or 1. 0 is Dlib, 1 is Efficientnetv2_arcface.onnx.
RootDir (str): Root directory. npKnown.npzが作成されるディレクトリ。
preset_face_imagesDir (str): Path to preset_face_images folder. pngファイルが存在するディレクトリ。
upsampling (int, optional): Value of upsampling. Defaults to 0.
jitters (int, optional): Value of jitters. Defaults to 100.
mode (str, optional): You can select from hog or cnn. Defaults to 'hog'.
model (str, optional): You cannot modify this value.
Returns:
Tuple[List, List]: known_face_encodings_list, known_face_names_list
- known_face_encodings_list
- List of encoded many face images as ndarray
- known_face_names_list
- List of name which encoded as ndarray
Example:
>>> known_face_encodings, known_face_names = LoadPresetImage().load_preset_image(
self,
self.conf_dict["RootDir"],
self.conf_dict["preset_face_imagesDir"]
)
"""
self.deep_learning_model = deep_learning_model
self.RootDir = RootDir
self.preset_face_imagesDir = preset_face_imagesDir
self.upsampling = upsampling
self.jitters = jitters
self.mode = mode
self.model = model
# Initialize
known_face_names_list: List[str] = []
known_face_encodings_list: List[np.ndarray] = []
new_files: List = []
cnt: int = 1 # cnt:何番目のファイルかを表す変数
cd: bool = False
if cd == False:
os.chdir(self.RootDir)
cd = True
self.logger.info("Loading npKnown.npz")
# npKnown.npzがdeep_learning_modelに合致しているかチェックする
if exists("npKnown.npz"):
if deep_learning_model == 1:
# npKnown.npzファイルから配列をロード
with np.load('npKnown.npz') as data:
keys = data.files # 配列の名前のリストを取得
# キーの存在をチェックする変数
has_efficientnetv2_arcface = 'efficientnetv2_arcface.npy' in keys
# has_name = 'name.npy' in keys
# 条件をチェック
if has_efficientnetv2_arcface == False:
self.logger.error(
'npKnown.npz file is corrupted. Create again.')
# npKnown.npzファイルを削除
os.remove('npKnown.npz')
###################### npKnown.npzの有る無しで処理を分岐させる ######################
# ============= npKnown.npzファイルが存在する場合の処理 ===============
if exists("npKnown.npz"):
# npKnown.npzの読み込みを行い、今までの全てのデータを格納する
npKnown = np.load('npKnown.npz', allow_pickle=True)
if 'dlib' in npKnown:
# deep_learning_modelが0の場合はdlibのデータを読み込むが、1の場合はエラーを表示する
if self.deep_learning_model == 0:
known_face_names_ndarray = npKnown['name']
known_face_encodings_ndarray = npKnown['dlib']
else:
self.logger.error(
"Mismatch between deep_learning_model and npKnown.npz content. The deep_learning_model is set to 0 (dlib model), but the npKnown.npz contains data for a different model.")
exit(1)
elif 'efficientnetv2_arcface' in npKnown:
# deep_learning_modelが1の場合はefficientnetv2_arcfaceのデータを読み込むが、0の場合はエラーを表示する
if self.deep_learning_model == 1:
known_face_names_ndarray = npKnown['name']
known_face_encodings_ndarray = npKnown['efficientnetv2_arcface']
else:
self.logger.error(
"Mismatch between deep_learning_model and npKnown.npz content. The deep_learning_model is set to 1 (efficientnetv2_arcface model), but the npKnown.npz contains data for a different model.")
exit(1)
else:
error_msg = "Unable to use npKnown.npz due to a mismatch between deep_learning_model and the file content. " \
"The deep_learning_model is set to a different value or the file contains data for a different model."
self.logger.error(error_msg)
# ############ 各配列の整形(ndarray型からリスト型へ変換する) ############
known_face_names_list = known_face_names_ndarray.tolist()
list = []
for i in known_face_encodings_ndarray:
list.append(i)
# for x in i:
# list.append(x)
known_face_encodings_list = list
# #########################################################################
# preset_face_imagesフォルダ内の全てのファイル名を読み込む
os.chdir(self.preset_face_imagesDir)
# まずself.preset_face_imagesDirのファイル名を全て得る
for preset_face_image in os.listdir(self.preset_face_imagesDir):
# <DEBUG>
# if 'テスト' in preset_face_image:
# if not preset_face_image in known_face_names:
# print(preset_face_image)
# exit()
# 関係ないファイルやフォルダは処理からとばす
if preset_face_image == 'desktop.ini':
continue
if isdir(preset_face_image):
continue
if 'debug' in preset_face_image:
continue
if 'npKnown.npz' in preset_face_image:
continue
# もし画像ファイル以外だった場合、continueする
if not preset_face_image.endswith('.jpg') and not preset_face_image.endswith('.jpeg') and not preset_face_image.endswith('.png'):
continue
# all_preset_face_images.append(preset_face_image)
# =============== file名がnpKnownのキーに存在していない場合の処理 ===============
if not preset_face_image in known_face_names_list:
# preset_face_imageはknown_face_names配列にないから、new_fileに名前を変える
new_file: str = preset_face_image
new_file_face_image: npt.NDArray[np.uint8] = \
Dlib_api_obj.load_image_file(
new_file
)
new_file_face_locations: List[Tuple[int, int, int, int]] = \
Dlib_api_obj.face_locations(
new_file_face_image,
self.upsampling,
self.mode
)
# 顔検出できなかった場合hogからcnnへチェンジして再度顔検出する
if len(new_file_face_locations) == 0:
if self.mode == 'hog':
self.logger.info(
"Face could not be detected. Temporarily switch to 'cnn' mode")
new_file_face_locations = Dlib_api_obj.face_locations(
new_file_face_image, self.upsampling, 'cnn')
# cnnでも顔検出できない場合はnoFaceフォルダへファイルを移動する
self.logger.info(
f"{cnt} No face detected in registered face image {new_file}(CNN mode). Move it to the 'noFace' folder")
# `noFace`フォルダが存在しない場合は作成する
if not exists('../noFace'):
os.mkdir('../noFace')
self.logger.info("Create 'noFace' folder")
try:
move(new_file, '../noFace/')
except Exception as e:
# # 移動先のファイルが存在する場合は削除する
# if os.path.exists('../noFace/' + new_file):
# os.remove('../noFace/' + new_file)
# # ファイルを移動する
# move(new_file, '../noFace/')
self.logger.error(e)
os.remove('../noFace/' + new_file)
move(new_file, '../noFace/')
self.mode = 'hog'
self.logger.info('Back to HOG mode')
# new_file顔画像のエンコーディング処理:array([encoding 配列])
self.logger.info(f"{cnt} Encoding {new_file}")
new_file_face_encodings: List[npt.NDArray] = []
# Dlib使用時の顔画像のエンコーディング処理
if self.deep_learning_model == 0:
new_file_face_encodings = Dlib_api_obj.face_encodings(
deep_learning_model=0,
resized_frame=new_file_face_image,
face_location_list=new_file_face_locations,
num_jitters=self.jitters,
model=self.model
)
# efficientnetv2_arcface.onnx使用時の顔画像のエンコーディング処理
elif self.deep_learning_model == 1:
new_file_face_encodings = Dlib_api_obj.face_encodings(
deep_learning_model=1,
resized_frame=new_file_face_image,
face_location_list=new_file_face_locations,
num_jitters=self.jitters,
model=self.model
)
# CPU温度が設定温度を超過していたら待機
Utils_obj.temp_sleep()
if len(new_file_face_encodings) > 1: # 複数の顔が検出された時
self.logger.info(
f"{cnt} Multiple faces detected in registered face image {new_file}. Move it to noFace folder.")
# もしnoFaceフォルダに同じファイル名が存在したら削除する
if os.path.exists('../noFace/' + new_file):
os.remove('../noFace/' + new_file)
# もし`new_file`自体がカレントディレクトリに存在しない場合、`continue`する
if not os.path.exists(new_file):
self.logger.error(
f"{new_file} does not exist in the current directory. Skip it.")
continue
move(new_file, '../noFace/')
elif len(new_file_face_encodings) == 0: # 顔が検出されなかった時
self.logger.info(
f"{cnt} No face detected in registered face image {new_files}. Move it to noFace folder.")
try:
move(new_file, '../noFace/' + new_file)
except:
pass
# エンコーディングした顔画像だけ新しい配列に入れる
if len(new_file_face_encodings) == 1:
known_face_names_list.append(new_file)
known_face_encodings_list.append(
new_file_face_encodings[0])
cnt += 1
# ============= npKnown.npzファイルが存在しない場合の処理 =============
elif not exists("npKnown.npz"):
# os.chdir(self.RootDir)
os.chdir(self.preset_face_imagesDir)
# os.chdir(os.path.join(self.RootDir, self.preset_face_imagesDir))
# まずself.preset_face_imagesDirのファイル名を全て得る
for preset_face_image_filename in os.listdir(self.preset_face_imagesDir):
# # 関係ないファイルやフォルダは処理からとばす
# if preset_face_image_filename == 'desktop.ini': # desktop.iniは処理をとばす
# continue
# if isdir(preset_face_image_filename): # フォルダの場合は処理をとばす
# continue
# if 'debug' in preset_face_image_filename: # ファイル名にdebugを含む場合は処理をとばす
# continue
# preset_face_image_filenameがpngファイル以外の場合は処理をとばす
if not preset_face_image_filename.endswith("png"):
continue
# それぞれの顔写真について顔認証データを作成する
preset_face_img = \
Dlib_api_obj.load_image_file(
preset_face_image_filename
)
preset_face_img_locations = \
Dlib_api_obj.face_locations(
preset_face_img,
self.upsampling,
self.mode
)
# CPU温度が設定温度を超過していたら待機
Utils_obj.temp_sleep()
# 得られた顔データについて顔写真なのに顔が判別できない場合や複数の顔がある場合はcnnモードで再確認し、それでもな場合はnoFaceフォルダに移動する
noFace_file = '../noFace/' + preset_face_image_filename
if len(preset_face_img_locations) == 0 or len(preset_face_img_locations) > 1:
if self.mode == 'hog':
self.logger.info(
'No face detected or multiple face detected. Temporarily switch to cnn mode')
# CNNモードにて顔検出を行う
preset_face_img_locations = \
Dlib_api_obj.face_locations(
preset_face_img, self.upsampling,
'cnn'
)
# CPU温度が設定温度を超過していたら待機
Utils_obj.temp_sleep()
# cnnでも顔検出できない場合はnoFaceフォルダへファイルを移動する
if len(preset_face_img_locations) == 0 or len(preset_face_img_locations) > 1:
self.logger.info(
f"{cnt} (CNN mode) Registered face image {preset_face_image_filename}, No face detected or multiple face detected. Move it to noFace folder.")
if exists(noFace_file):
os.remove(noFace_file)
move(preset_face_image_filename, '../noFace/')
self.mode = 'hog'
self.logger.info('Back to HOG mode')
# 得られた顔データ(この場合は顔ロケーション)を元にエンコーディングする:array([encoding 配列])
self.logger.info(
f"{cnt} Encoding {preset_face_image_filename}")
preset_face_image_encodings = \
Dlib_api_obj.face_encodings(
self.deep_learning_model,
preset_face_img,
preset_face_img_locations,
self.jitters,
'small'
)
# CPU温度が設定温度を超過していたら待機
Utils_obj.temp_sleep()
# エンコーディングした顔写真について複数顔や顔がない場合はnoFaceフォルダへ移動する
if len(preset_face_image_encodings) > 1: # 複数の顔が検出された時
self.logger.info(
f"{cnt} Multiple faces detected in registered face image {preset_face_image_filename}. Move it to noFace folder.")
if exists(noFace_file):
os.remove(noFace_file)
try:
move(preset_face_image_filename, '../noFace/')
except:
pass
elif len(preset_face_image_encodings) == 0: # 顔が検出されなかった時
self.logger.info(
f"{cnt} No face detected in registered face image {preset_face_image_filename}. Move it to noFace folder.")
if exists(noFace_file): # noFaceフォルダに同じ名前のファイルがある場合は削除する
os.remove(noFace_file)
try:
move(preset_face_image_filename, '../noFace/')
except:
"""TODO"""
pass
continue
# 配列に、名前やエンコーディングデータを要素として追加する
# FACE01GRAPHICS本体の方では要素にndarrayを含むListを返り値として期待している(Dlib_api_obj APIにそう書いてある)
known_face_names_list.append(preset_face_image_filename)
known_face_encodings_list.extend(
preset_face_image_encodings[0])
# known_face_encodings_list.append(preset_face_image_encodings[0])
cnt += 1
###################### savezで保存 ######################
os.chdir(self.RootDir)
# print('debug_npKnown.npzを作成します')
if self.deep_learning_model == 0:
np.savez(
'npKnown',
name=known_face_names_list,
dlib=known_face_encodings_list
)
elif self.deep_learning_model == 1:
np.savez(
'npKnown',
name=known_face_names_list,
efficientnetv2_arcface=known_face_encodings_list
)
if known_face_encodings_list:
print(type(known_face_encodings_list[0]))
# ################### リスト型を返す ###################
# <DEBUG>
# list=[]
# for i in known_face_encodings: ## shape:(677, 1, 128)
# for x in i:
# list.append(x)
# known_face_encodings = list
return known_face_encodings_list, known_face_names_list
# #################### 備考 ####################
# 返り値のknown_face_encodingsと、npKnown.npzから読み込んだknown_face_encodingsとでは
# もしかしたらデータ型とか?なにかが異なっているのかもしれない。