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))
Beispiel #2
0
 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
Beispiel #3
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)
Beispiel #4
0
    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('完成了人脸特征提取的初始化')
Beispiel #5
0
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)
Beispiel #7
0
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)
Beispiel #8
0
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])
Beispiel #9
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/")
Beispiel #10
0
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()
Beispiel #11
0
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()
Beispiel #12
0
#! /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)
Beispiel #13
0
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
Beispiel #14
0
#################################################
#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)