def __init__(self): # 这里假设在外面已经配置好了 ArcFace 的 APP_ID 和 SDK_KEY self._arcface = ArcFace(ArcFace.IMAGE_MODE) self._features: Dict[str, bytes] = {} # 人脸数据库 # max_workers 必须为 1,因为 SDK 对并行的支持有限 self._executors = (ThreadPoolExecutor(max_workers=1), ThreadPoolExecutor(max_workers=1))
def __init__(self): self._arcface = ArcFace(ArcFace.IMAGE_MODE) self._features: Dict[str, bytes] = {} # 人脸数据库 # max_workers 必须为 1,因为 SDK 对并行的支持有限 self._executors = (ThreadPoolExecutor(max_workers=1), ThreadPoolExecutor(max_workers=1)) self.close_update_feature = True self.count = 0
def _run_1_n(image_source: ImageSource, face_process: FaceProcess, feature_data) -> None: """ 1:n 的整个处理的逻辑 :image_source: 识别图像的源头 :face_process: 用来对人脸信息进行提取 :return: None """ with ArcFace(ArcFace.VIDEO_MODE) as arcface: cur_face_info = None # 当前的人脸 frame_rate_statistics = _frame_rate_statistics_generator() while True: # 获取视频帧 image = image_source.read() # 检测人脸 faces_pos = arcface.detect_faces(image) if len(faces_pos) == 0: # 图片中没有人脸 cur_face_info = None else: # 使用曼哈顿距离作为依据找出最靠近中心的人脸 center_y, center_x = image.shape[:2] center_y, center_x = center_y // 2, center_x // 2 center_face_index = -1 min_center_distance = center_x + center_y + 4 cur_face_index = -1 for i, pos in enumerate(faces_pos): if cur_face_info is not None and pos.face_id == cur_face_info.arc_face_info.face_id: cur_face_index = i break x, y = pos.rect.center if x + y < min_center_distance: center_face_index = i min_center_distance = x + y if cur_face_index != -1: # 上一轮的人脸依然在,更新位置信息 cur_face_info.arc_face_info = faces_pos[cur_face_index] else: # 上一轮的人脸不在了,选择当前所有人脸的最大人脸 cur_face_info = FaceInfo(faces_pos[center_face_index]) if cur_face_info is not None: # 异步更新人脸的信息 if cur_face_info.need_update(): face_process.async_update_face_info(image, cur_face_info) # 绘制人脸信息 _draw_face_info(image, cur_face_info) # 绘制中心点 # put_text(image, "x", bottom_middle=(center_x, center_y)) # 显示到界面上 flag = _show_image(image) if flag == 3: break elif flag == 1 or flag == 2: change_face(flag, face_process, feature_data) # 统计帧率 fps = next(frame_rate_statistics) if fps: _logger.info("FPS: %.2f" % fps)
def __init__(self, config): self.device = config['device'] self.refresh_interval = config['yolo_refresh_interval'] self.inputpath = os.path.join(config['job2_output'], '*.json') self.config = config self.outputpath = config['job3_output'] if config['face_iditify'] == 'facenet': self.model = InceptionResnetV1( pretrained=config['facenet_pretained_model']).to( self.device).eval() self.batchsize = config['facenet_batch_size'] self.imagesize = config['facenet_image_size'] elif config['face_iditify'] == 'arcface': from arcface import ArcFace self.model = ArcFace(config['arcface_modelpath'], self.device, 112) self.imagesize = 112 self.batchsize = config['arcface_batch_size'] self.alignUtils = AlignFace((self.imagesize, self.imagesize)) print('完成了人脸特征提取的初始化')
def _run_m_n(image_source: ImageSource, face_process: FaceProcess, feature_data: str) -> None: with ArcFace(ArcFace.VIDEO_MODE) as arcface: faces_info: Dict[int, FaceInfo] = {} frame_rate_statistics = _frame_rate_statistics_generator() while True: # 获取视频帧 image = image_source.read() # 检测人脸 faces_pos: Dict[int, ArcFaceInfo] = {} for face_pos in arcface.detect_faces(image): faces_pos[face_pos.face_id] = face_pos # 删除过期 id, 添加新的 id cur_faces_id = faces_pos.keys() last_faces_id = faces_info.keys() for face_id in last_faces_id - cur_faces_id: faces_info[face_id].cancel() # 如果有操作在进行,这将取消操作 faces_info.pop(face_id) for face_id in cur_faces_id: if face_id in faces_info: # 人脸已经存在,只需更新位置就好了 faces_info[face_id].arc_face_info = faces_pos[face_id] else: faces_info[face_id] = FaceInfo(faces_pos[face_id]) # 更新人脸的信息 # for face_info in faces_info: # face_process.async_update_face_info(image, face_info) opt_face_info = None for face_info in filter(lambda x: x.need_update(), faces_info.values()): if opt_face_info is None or opt_face_info.rect.size < face_info.rect.size: opt_face_info = face_info if opt_face_info is not None: face_process.async_update_face_info(image, opt_face_info) # 绘制人脸信息 for face_info in faces_info.values(): _draw_face_info(image, face_info) flag = _show_image(image) if flag == 3: break elif flag == 1 or flag == 2: change_face(flag, face_process, feature_data) # 统计帧率 fps = next(frame_rate_statistics) if fps: _logger.info("FPS: %.2f" % fps)
collection.remove({}) # read the list of probe images probe_directory = "http://nginx/images/probe/" probe_images = requests.get(probe_directory + "images.txt").text.split() print("The number of probe images is equal to " + str(len(probe_images))) # read the list of gallery images gallery_directory = "http://nginx/images/gallery/" gallery_images = requests.get(gallery_directory + "images.txt").text.split() print("The number of gallery images is equal to " + str(len(gallery_images))) # create the detector, using default weights mtcnn_detector = MTCNN() retina_detector = RetinaFace(quality="normal") arc_detector = ArcFace.ArcFace() # K-most similar gallery faces are selected K = 1 # valid gallery stores bytes of images valid_gallery = {} valid_probe = {} couldnt_find_face_in_probe = [] similarities = [] for gallery_image in gallery_images: print("encoding gallery images" + gallery_image) g_image = requests.get(gallery_directory + gallery_image) g_image_bytes = BytesIO(g_image.content)
class FaceFeatureService(BaseService): def __init__(self, config): self.device = config['device'] self.refresh_interval = config['yolo_refresh_interval'] self.inputpath = os.path.join(config['job2_output'], '*.json') self.config = config self.outputpath = config['job3_output'] if config['face_iditify'] == 'facenet': self.model = InceptionResnetV1( pretrained=config['facenet_pretained_model']).to( self.device).eval() self.batchsize = config['facenet_batch_size'] self.imagesize = config['facenet_image_size'] elif config['face_iditify'] == 'arcface': from arcface import ArcFace self.model = ArcFace(config['arcface_modelpath'], self.device, 112) self.imagesize = 112 self.batchsize = config['arcface_batch_size'] self.alignUtils = AlignFace((self.imagesize, self.imagesize)) print('完成了人脸特征提取的初始化') def _get_input(self, frame, obj): ''' frame is a numpy array,have channel BGR :param frame: :param obj: :return: ''' x1, y1, x2, y2 = obj['face_box'] x1 = max(x1, 0) x2 = max(x2, 0) y1 = max(y1, 0) y2 = max(y2, 0) #########################ALIGN FACE#################################### landmark = np.array(obj['landmark']).reshape((5, 2)) frame = self.alignUtils.align(Image.fromarray(frame), (x1, y1, x2, y2), landmark, self.config['face_align_margin'], self.config['face_align_type']) ############################################################# #now frame is a PIL image.channel order did not change I = self.model._preprocessing(frame) return (obj, I) def _handle(self, queue): faceids = self.model.extractFeature([img for obj, img in queue], self.device) for (obj, img), faceid in zip(queue, faceids): del img obj['face_id'] = faceid def _after_precessing(self, final, videofile, jobfile): ''' ''' if os.path.exists(jobfile): os.remove(jobfile) outputpath = os.path.join(self.outputpath, os.path.basename(videofile)) if os.path.exists(outputpath): os.remove(outputpath) shutil.move(videofile, outputpath) id = getId(videofile) # final['job3_video='] = outputpath with open(os.path.join(self.outputpath, id + '.json'), 'w') as fs: json.dump(final, fs, indent=1) def _process(self, filename): print('开始任务3:%s' % filename) stream = None final = self._defaultReturn(filename) queue = [] try: if final['status'] == 'success': videofile = final['job3_video'] stream, videoinfo = readVideo(videofile) frames = videoinfo['frames'] for t in tqdm(range(frames)): retval, frame = stream.read() if not retval: break objs_at_t = final['track']['objs'][t] for obj in objs_at_t: if 'face_box' in obj: queue.append(self._get_input(frame, obj)) if len(queue) == self.batchsize: self._handle(queue) del queue queue = [] if len(queue) > 0: self._handle(queue) self._after_precessing(final, videofile, filename) print('任务3:%s完成' % videofile) except Exception as e: final['status'] = 'fail' final['error'] = 'At job3,' + str(e) if self.config['debug']: raise e finally: if stream is not None: stream.release() print('任务3:%s完成' % filename)
import numpy as np import cv2 import os from retinaface import RetinaFace from arcface import ArcFace import faiss det = RetinaFace(quality='normal') model = ArcFace.ArcFace() d = 512 index = faiss.IndexFlatL2(d) path = './KIETEmpTrain/' imgList = np.sort(os.listdir(path)) class ImageServices(): def __init__(self): self.images = [] self.faces = [] self.embeddings = [] self.PersonNames = [] self.imageDB = self.ImageDatabase(imgList) self.faceDB = self.DetectFace(self.images) self.embDB = self.ExtractEmbedding(self.faces) def ImageDatabase(self, imgList): for pname in imgList: # print(pname) curImage = cv2.imread(f'{path}/{pname}') self.images.append(curImage) self.PersonNames.append(os.path.splitext(pname)[0])
from head_pose_est import HeadPoseEst from face_detection_naive import FaceDetection from utils import good_head_angle class Miris(BaseModel): unique_faces: list raw_faces: list time: float # server modules app = FastAPI() # Vision modules face_embed = ArcFace() face_detect = FaceDetection() age_gender_est = AgeGenderEstimator() headpose = HeadPoseEst() # database modules FDC = FaceDatabase() # face_list = FDC.loadFaces() @app.get("/") async def root(): return {"message": "Hello World"} @app.post("/face/log/")
class FaceProcess: def __init__(self): self._arcface = ArcFace(ArcFace.IMAGE_MODE) self._features: Dict[str, bytes] = {} # 人脸数据库 # max_workers 必须为 1,因为 SDK 对并行的支持有限 self._executors = (ThreadPoolExecutor(max_workers=1), ThreadPoolExecutor(max_workers=1)) def async_update_face_info(self, image: np.ndarray, face_info: FaceInfo) -> None: """ 更新单个人脸的信息。 :param image: 包含人脸的图片 :param face_info: 人脸信息 :return: None """ _logger.info("人脸 %d: 开始获取信息" % face_info.arc_face_info.face_id) face_info.image = image if face_info.stop_flags[0]: _logger.debug("人脸 %d: 获取姓名" % face_info.arc_face_info.face_id) face_info.stop_flags[0] = False future: Future = self._executors[0].submit(self._update_name, face_info) future.add_done_callback( lambda x: FaceProcess._update_name_done(face_info, x)) if face_info.stop_flags[1]: _logger.debug("人脸 %d: 活体检测、性别、年龄" % face_info.arc_face_info.face_id) face_info.stop_flags[1] = False future: Future = self._executors[1].submit(self._update_other, face_info) future.add_done_callback( lambda x: FaceProcess._update_other_done(face_info, x)) def _update_other( self, face_info: FaceInfo ) -> Tuple[Optional[bool], Optional[int], Optional[Gender]]: """ 更新其它信息,比如 活体、性别、年龄 :param face_info: :return: 识别成功的信息数 """ image, orient = face_info.image, face_info.arc_face_info.orient face_id = face_info.arc_face_info.face_id arc_face_info = face_info.arc_face_info if face_info.stop_flags[1]: return None, None, None if not self._arcface.process_face( image, arc_face_info, ArcFace.LIVENESS | ArcFace.AGE | ArcFace.GENDER): _logger.debug("人脸 %d: 处理失败" % face_id) return None, None, None arcface = self._arcface return arcface.is_liveness(), arcface.get_age(), arcface.get_gender() @staticmethod def _update_other_done(face_info: FaceInfo, future: Future): face_info.liveness, face_info.age, face_info.gender = future.result() face_info.stop_flags[1] = True def _update_name(self, face_info: FaceInfo) -> Tuple[str, float]: """ 提取特征,再在人脸数据库查找符合条件的特征 :return: 成功返回 True,失败返回 False """ image, orient = face_info.image, face_info.arc_face_info.orient face_id = face_info.arc_face_info.face_id arc_face_info = face_info.arc_face_info feature = self._arcface.extract_feature(image, arc_face_info) if not feature: _logger.debug("人脸 %d: 提取特征值失败(%s)" % (face_id, "%dx%d" % face_info.rect.size)) return "", 0.0 if face_info.stop_flags[0]: _logger.debug("人脸 %d: 取消识别人脸" % face_id) return "", 0.0 max_threshold = 0.0 opt_name = "" for name, feature_ in self._features.items(): threshold = self._arcface.compare_feature(feature, feature_) if max_threshold < threshold: max_threshold = threshold opt_name = name #相似度阈值 if 0.6 < max_threshold: _logger.debug("人脸 %d: 识别成功,与 %s 相似度 %.2f" % (face_id, opt_name, max_threshold)) return opt_name, max_threshold _logger.debug("人脸 %d: 识别失败,与最像的 %s 的相似度 %.2f" % (face_id, opt_name, max_threshold)) return "", 0.0 @staticmethod def _update_name_done(face_info: FaceInfo, future: Future): face_info.name, face_info.threshold = future.result() face_info.stop_flags[0] = True def dump_features(self, filename: str) -> int: """ 将已有的人脸数据库保存到文件 :filename: 保存人脸数据库的文件名 :return: 保存的人脸数 """ with open(filename, "w", encoding="utf-8") as file: for name, feature in self._features.items(): file.write(name) file.write(":") file.write(base64.b64encode(feature).decode()) file.write("\n") return len(self._features) def load_features(self, filename: str) -> int: """ 从先前保存的人脸数据库加载数据 :param filename: 保存人脸数据库的文件名 :return: 加载的人脸数 """ count = 0 with open(filename, encoding="utf-8") as file: line = file.readline() while line: name, feature = line.split(":") feature = base64.b64decode(feature) self._features[name] = feature count += 1 line = file.readline() _logger.info("从 \"%s\" 中加载了 %d 个特征值" % (filename, count)) return count def add_features(self, path_name: str) -> int: """ 将本地文件夹或者本地图片所有用户的特征值添加人脸数据库 :param path_name: 文件夹名或者图片路径名 :return: 成功添加的人脸数 """ features = self._load_all_features(path_name) self._features.update(features) return len(features) def add_person(self, filename: str, feature_data: str) -> int: features = {} name: str = os.path.basename(filename) name: str = name.split(".")[0] faces_number, features_ = self._load_features_from_image( name, read_image(filename)) if faces_number == 1: features.update(features_) with open(feature_data, "a", encoding="utf-8") as file: for name, feature in features_.items(): file.write(name) file.write(":") file.write(base64.b64encode(feature).decode()) file.write("\n") self._features.update(features) return faces_number def delete_person(self, ID, filename) -> None: with open(filename, 'r') as r: lines = r.readlines() with open(filename, 'w') as w: for l in lines: name, feature = l.split(":") if name != ID: w.write(l) if ID in self._features.keys(): del self._features[ID] def _load_all_features(self, path_name: str) -> Dict[str, bytes]: """ 从本地文件夹或者本地图片加载所有用户的特征值 如果从图片中加载,则用户名是数字 ID(类型依然是字符串) 如果指定文件夹则遍历所有合法的图片,用户名是 <图片文件名-数字 ID>,如果只有一张图片则没有数字 ID :type path_name: 文件夹名或者图片路径名 :return: 包含所有特征值的 map<姓名, 特征值> """ if not os.path.exists(path_name): raise ValueError("不存在的路径 \"%s\"" % path_name) _logger.info("从 \"%s\" 中加载所有的人脸特征值" % path_name) total_faces_number = 0 files_number = 0 features = {} count = 0 for filename in get_regular_file(path_name): count += 1 print("\r已经加载了 %d 个文件" % count, end="") files_number += 1 # TODO: name 类型的问题 name: str = os.path.basename(filename) name: str = name.split(".")[0] faces_number, features_ = self._load_features_from_image( name, read_image(filename)) total_faces_number += faces_number if faces_number == 0: _logger.warning("\n\"%s\" 中没有发现人脸" % filename) features.update(features_) print() _logger.info("在 %d 个文件中,一共发现 %d 张人脸,其中 %d 张清晰有效" % (files_number, total_faces_number, len(features))) return features def _load_features_from_image( self, name: str, image: np.ndarray) -> Tuple[int, Dict[str, bytes]]: """ 从图片中加载特征值 如果 name 为空,名字按数字编号来 否则,如果只有一个特征,使用 name 的值作为名称 否则,使用 <name-数字编号> 来命名 :param name: 图片中人的名字 :param image: 需要提取特征的图片 :return: 总的人脸数(包含不清晰无法提取特征值的人脸), Dict[姓名, 特征值] """ if image.size == 0: return 0, {} image = image_regularization(image) # 检测人脸位置 faces = self._arcface.detect_faces(image) # 提取所有人脸特征 features = map(lambda x: self._arcface.extract_feature(image, x), faces) # 删除空的人脸特征 features = list(filter(lambda feature: feature, features)) # 按一定规则生成名字 def get_name() -> Generator[str, None, None]: for i in range(len(features)): if len(name) == 0: yield "%d" % i if len(features) == 1: yield name else: yield "%s-%d" % (name, i) # 将所有特征和名字拼接起来 def assemble() -> Dict[str, bytes]: res = {} for name_, feature in zip(get_name(), features): res[name_] = feature return res return len(faces), assemble() def release(self): for executor in self._executors: executor.shutdown() self._arcface.release() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.release()
class FaceProcess: def __init__(self): self._arcface = ArcFace(ArcFace.IMAGE_MODE) self._features: Dict[str, bytes] = {} # 人脸数据库 # max_workers 必须为 1,因为 SDK 对并行的支持有限 self._executors = (ThreadPoolExecutor(max_workers=1), ThreadPoolExecutor(max_workers=1)) self.close_update_feature = True self.count = 0 def async_update_face_info(self, image: np.ndarray, face_info: FaceInfo) -> None: """ 更新单个人脸的信息。 :param image: 包含人脸的图片 :param face_info: 人脸信息 :return: None """ _logger.info("人脸 %d: 开始获取信息" % face_info.arc_face_info.face_id) face_info.image = image if face_info.stop_flags[0]: _logger.debug("人脸 %d: 获取姓名" % face_info.arc_face_info.face_id) face_info.stop_flags[0] = False future: Future = self._executors[0].submit(self._update_name, face_info) future.add_done_callback( lambda x: FaceProcess._update_name_done(face_info, x)) if face_info.stop_flags[1]: _logger.debug("人脸 %d: 活体检测、性别、年龄" % face_info.arc_face_info.face_id) face_info.stop_flags[1] = False future: Future = self._executors[1].submit(self._update_other, face_info) future.add_done_callback( lambda x: FaceProcess._update_other_done(face_info, x)) def _update_other( self, face_info: FaceInfo ) -> Tuple[Optional[bool], Optional[int], Optional[Gender]]: """ 更新其它信息,比如 活体、性别、年龄 :param face_info: :return: 识别成功的信息数 """ image, orient = face_info.image, face_info.arc_face_info.orient face_id = face_info.arc_face_info.face_id arc_face_info = face_info.arc_face_info if face_info.stop_flags[1]: return None, None, None if not self._arcface.process_face( image, arc_face_info, ArcFace.LIVENESS | ArcFace.AGE | ArcFace.GENDER): _logger.debug("人脸 %d: 处理失败" % face_id) return None, None, None arcface = self._arcface return arcface.is_liveness(), arcface.get_age(), arcface.get_gender() @staticmethod def _update_other_done(face_info: FaceInfo, future: Future): face_info.liveness, face_info.age, face_info.gender = future.result() face_info.stop_flags[1] = True def _update_name(self, face_info: FaceInfo) -> Tuple[str, float]: """ 提取特征,再在人脸数据库查找符合条件的特征 :return: 成功返回 True,失败返回 False """ image, orient = face_info.image, face_info.arc_face_info.orient face_id = face_info.arc_face_info.face_id arc_face_info = face_info.arc_face_info feature = self._arcface.extract_feature(image, arc_face_info) if not feature: _logger.debug("人脸 %d: 提取特征值失败(%s)" % (face_id, "%dx%d" % face_info.rect.size)) return "", 0.0 if face_info.stop_flags[0]: _logger.debug("人脸 %d: 取消识别人脸" % face_id) return "", 0.0 max_threshold = 0.0 opt_name = "" for name, feature_ in self._features.items(): threshold = self._arcface.compare_feature(feature, feature_) if max_threshold < threshold: max_threshold = threshold opt_name = name #相似度阈值 if 0.6 < max_threshold: _logger.debug("人脸 %d: 识别成功,与 %s 相似度 %.2f" % (face_id, opt_name, max_threshold)) url = "http://127.0.0.1:8000/checkedface/" info = {'id': opt_name} r = requests.post(url, data=info) return opt_name, max_threshold _logger.debug("人脸 %d: 识别失败,与最像的 %s 的相似度 %.2f" % (face_id, opt_name, max_threshold)) return "", 0.0 @staticmethod def _update_name_done(face_info: FaceInfo, future: Future): face_info.name, face_info.threshold = future.result() face_info.stop_flags[0] = True def load_features(self) -> int: """ 从数据库加载数据 :param filename: 保存人脸数据库的文件名 :return: 加载的人脸数 """ while True: with open("profile.yml", "r", encoding="utf-8") as file: profile: Dict[str, str] = yaml.load(file, yaml.Loader) server_on = profile["server-on"].encode() host = profile["database"]["host"].encode() user = profile["database"]["user"].encode() password = profile["database"]["password"].encode() base = profile["database"]["base"].encode() if server_on == 0: break conn = pymysql.connect(host, user, password, base, charset='utf8') cursor = conn.cursor() sql = "SELECT * FROM FACE_FEATURE" self.count = 0 try: cursor.execute(sql) # 获取所有记录列表 results = cursor.fetchall() for row in results: id = row[0] feature = base64.b64decode(row[1]) self._features[id] = feature self.count += 1 except: print("Error: unable to fecth data") conn.close() _logger.info("从数据库中加载了 %d 个特征值" % (self.count)) time.sleep(30) def add_person(self, filename: str): features = {} name: str = os.path.basename(filename) name: str = name.split(".")[0] faces_number, features_ = self._load_features_from_image( name, read_image(filename)) if faces_number == 1: features.update(features_) for name, feature in features_.items(): return faces_number, base64.b64encode(feature).decode() self._features.update(features) return faces_number, "None" def _load_features_from_image( self, name: str, image: np.ndarray) -> Tuple[int, Dict[str, bytes]]: """ 从图片中加载特征值 如果 name 为空,名字按数字编号来 否则,如果只有一个特征,使用 name 的值作为名称 否则,使用 <name-数字编号> 来命名 :param name: 图片中人的名字 :param image: 需要提取特征的图片 :return: 总的人脸数(包含不清晰无法提取特征值的人脸), Dict[姓名, 特征值] """ if image.size == 0: return 0, {} image = image_regularization(image) # 检测人脸位置 faces = self._arcface.detect_faces(image) # 提取所有人脸特征 features = map(lambda x: self._arcface.extract_feature(image, x), faces) # 删除空的人脸特征 features = list(filter(lambda feature: feature, features)) # 按一定规则生成名字 def get_name() -> Generator[str, None, None]: for i in range(len(features)): if len(name) == 0: yield "%d" % i if len(features) == 1: yield name else: yield "%s-%d" % (name, i) # 将所有特征和名字拼接起来 def assemble() -> Dict[str, bytes]: res = {} for name_, feature in zip(get_name(), features): res[name_] = feature return res return len(faces), assemble() def release(self): for executor in self._executors: executor.shutdown() self._arcface.release() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.release()
#! /usr/bin/python3 # this implementation only returns 96.87% accuracy, # It uses TensorFlow Light to speed up results (pip install arcface) # it uses pre-trained model based on ResNet50 # need to do face detection and alignment (See if_test.py) from arcface import ArcFace face_rec = ArcFace.ArcFace() emb1 = face_rec.calc_emb("img/igor1_out.jpg") print(emb1) emb2 = face_rec.calc_emb("img/igor2_out.jpg") dist = face_rec.get_distance_embeddings(emb1, emb2) print("Distance", dist)
def create_model(l2, num_classes, num_ctrl_classes): ############## # BRANCH MODEL ############## regul = regularizers.l2(l2) # optim = Adam(lr=lr) # kwargs = {'kernel_regularizer': regul} base_model = efn.EfficientNetB2(input_shape=(network_shape[0], network_shape[1], 3), weights='imagenet', include_top=False) input_tensor = Input(shape=network_shape, dtype=K.floatx()) conv1 = Conv2D(32, kernel_size=(3, 3), strides=(2, 2), activation='relu', use_bias=False, padding='same', input_shape=(input_shape[0] + 6, input_shape[1] + 6, input_shape[2])) layers = [] layers.append(input_tensor) layers.append(conv1) layers[2:] = base_model.layers[2:] new_model = copy_model_graph(layers, base_model, input_tensor) weights = base_model.layers[1].get_weights() weight0 = weights[0] w = np.concatenate((weight0, weight0), axis=2) w = w / 2.0 weights[0] = w # weights.append(np.zeros((64),dtype='float32')) new_model.layers[1].set_weights(weights) inp = Input(shape=input_shape, dtype='uint8') # 384x384x6 x = Lambda(augment)(inp) for layer in new_model.layers: if type(layer) is Conv2D: layer.kernel_regularizer = regul x = new_model(x) x = GlobalMaxPooling2D()(x) x = BatchNormalization()(x) x = Dropout(rate=0.5)(x) x = Flatten()(x) x = Dense(512, use_bias=False, kernel_initializer='he_normal')(x) x = BatchNormalization()(x) encoder_model = Model(inputs=inp, outputs=x) # softmax model for training encoder output_softmax = Dense(num_classes, use_bias=False, activation='softmax')(x) softmax_model = Model(inputs=inp, outputs=output_softmax) ################# # COMPARE MODEL # ################# mid = 32 xa_inp = Input(shape=encoder_model.output_shape[1:]) xb_inp = Input(shape=encoder_model.output_shape[1:]) x1 = Lambda(lambda x: x[0] * x[1])([xa_inp, xb_inp]) x2 = Lambda(lambda x: x[0] + x[1])([xa_inp, xb_inp]) x3 = Lambda(lambda x: x[0] - x[1])([xa_inp, xb_inp]) x4 = Lambda(lambda x: K.square(x))(x3) head = Concatenate()([x1, x2, x3, x4]) head = Reshape((4, encoder_model.output_shape[1], 1), name='reshape1')(head) # Per feature NN with shared weight is implemented using CONV2D with appropriate stride. head = Conv2D(mid, (4, 1), activation='relu', padding='valid')(head) head = Reshape((encoder_model.output_shape[1], mid, 1))(head) head = Conv2D(1, (1, mid), activation='linear', padding='valid')(head) head = Flatten()(head) compare_model = Model([xa_inp, xb_inp], head) # process encoding from control # compare the current features to all controls features_controls = Input( shape=[num_ctrl_classes, encoder_model.output_shape[1]]) fs = Lambda(lambda x: tf.unstack(x, axis=1))(features_controls) # def create_mask(features_controls): # # Use a function with a Keras Lambda layer wrapper to resolve a tensorflow issue. # # https://stackoverflow.com/questions/50715928/valueerror-output-tensors-to-a-model-must-be-the-output-of-a-tensorflow-layer # max_abs_features = K.max(K.abs(features_controls), axis=2) # mask = tf.greater(max_abs_features, K.epsilon()) # mask = tf.expand_dims(tf.expand_dims(tf.dtypes.cast(mask, K.floatx()), axis=-1), axis=-1) # return mask # mask = Lambda(create_mask)(features_controls) comps = [] for f in fs: comp = compare_model([x, f]) comps.append(comp) c = Concatenate()(comps) c = Reshape((num_ctrl_classes, encoder_model.output_shape[1], 1))(c) # c = Lambda(lambda x: tf.math.multiply(x[0], x[1]))([c, mask]) # compare = Lambda(compare_features)([x, features_controls]) # Per feature NN with shared weight is implemented using CONV2D with appropriate stride. compare = Conv2D(mid, (num_ctrl_classes, 1), activation='relu', padding='valid')(c) compare = Reshape((encoder_model.output_shape[1], mid, 1))(compare) compare = Conv2D(1, (1, mid), activation='linear', padding='valid')(compare) compare = Flatten(name='flatten2')(compare) feature_model = Model(inputs=[inp, features_controls], outputs=compare) label = Input(shape=(num_classes, )) output_arcface = ArcFace(num_classes, regularizer=regul)([compare, label]) arcface_model = Model([inp, features_controls, label], output_arcface) output_cosface = CosFace(num_classes, regularizer=regul)([compare, label]) cosface_model = Model([inp, features_controls, label], output_cosface) return encoder_model, softmax_model, feature_model, arcface_model, cosface_model
################################################# #1. I will load face image,detect it's feature #2. compute feature's index #3. then generate a record for each picture #id filename feature id0 id1 .... id 255 ################################################# from arcface import ArcFace import cv2 import numpy as np import glob from search.pq import quanizer import tqdm mymodel = ArcFace('../arcface/models/model', 'cuda') basepath = '/home/zxk/AI/data/faces_umd/db' def getFeature(imagepath): im = cv2.imread(imagepath) im = cv2.resize(im, (112, 112)) im = im[:, :, ::-1] im = np.expand_dims(im, 0) im = np.transpose(im, (0, 3, 1, 2)) emb = mymodel.forward(im) return emb[0] def readFiles():
def _run_m_n(image_source: ImageSource, face_process: FaceProcess) -> None: """ m:n 的整个处理的逻辑 :image_source: 识别图像的源头 :face_process: 用来对人脸信息进行提取 :return: None """ with ArcFace(ArcFace.VIDEO_MODE) as arcface: faces_info: Dict[int, FaceInfo] = {} frame_rate_statistics = _frame_rate_statistics_generator() while True: # 获取视频帧 image = image_source.read() # 检测人脸 faces_pos: Dict[int, ArcFaceInfo] = {} for face_pos in arcface.detect_faces(image): faces_pos[face_pos.face_id] = face_pos # 删除过期 id, 添加新的 id cur_faces_id = faces_pos.keys() last_faces_id = faces_info.keys() for face_id in last_faces_id - cur_faces_id: faces_info[face_id].cancel() # 如果有操作在进行,这将取消操作 faces_info.pop(face_id) for face_id in cur_faces_id: if face_id in faces_info: # 人脸已经存在,只需更新位置就好了 faces_info[face_id].arc_face_info = faces_pos[face_id] else: faces_info[face_id] = FaceInfo(faces_pos[face_id]) # 更新人脸的信息 # for face_info in faces_info: # face_process.async_update_face_info(image, face_info) opt_face_info = None for face_info in filter(lambda x: x.need_update(), faces_info.values()): if opt_face_info is None or opt_face_info.rect.size < face_info.rect.size: opt_face_info = face_info if opt_face_info is not None: face_process.async_update_face_info(image, opt_face_info) # cv.imshow("temp", opt_face_info.image) # print(opt_face_info.image.shape) # 绘制人脸信息 for face_info in faces_info.values(): _draw_face_info(image, face_info) if _show_image(image): break # if all(map(lambda x: x.complete(), faces_info.values())): # break # 统计帧率 fps = next(frame_rate_statistics) if fps: _logger.info("FPS: %.2f" % fps)