Пример #1
0
def face_search(request_id, b64_data, group_id='DEFAULT', max_user_num=5):
    # 最多返回5个相似用户
    max_user_num = min(5, max_user_num)

    # 并行获取特征值  --  分别检测人脸, 人脸角度可以分别调整
    #all_encodings, face_locations = predict_parallel(get_features_thread_db, b64_data, group_id, 
    #        request_id=request_id, classifier='api')

    # 并行获取特征值  --  只检测人脸一次,人脸角度要一起调整 (由ALGORITHM['evo']['p_angle']确定)
    all_encodings, face_locations, face_array = verify.get_features_b64_parallel(b64_data, request_id=request_id)

    if len(face_locations)==0: # 未取得特征值
        return []

    # 先使用knn分类器搜索(临时特征库)
    predictions = predict_parallel(predict_thread_db, all_encodings, group_id, 
            request_id=request_id, classifier='knn', data_type='encodings')
    # 如果未找到,再使用深度网络分类器(全量特征库)
    if len(predictions)==0 or predictions[0][0]=='unknown':
        print('search using keras classifier')
        plus_encodings = [all_encodings['vgg']['None']+all_encodings['evo']['None']]
        predictions = predict_K(plus_encodings, group_id,
            model_path=TRAINED_MODEL_PATH, 
            face_algorithm="plus",
            data_type="encodings")

        # 如果仍未识别,返回空
        if len(predictions)==0 or predictions[0][0]=='unknown':
            return []

    # 准备返回结果
    user_list = []
    for i in range(min(max_user_num, len(predictions))):
        user_id, box, score, _ = predictions[i]
        info = user_info(group_id, user_id)
        user_list.append({
            'user_id'     : user_id,
            'mobile_tail' : info['mobile'][:-4], # 手机后4位
            'name'        : info['name'], # 用户姓名
            'location'    : face_locations[0], # 只有一个人脸坐标
            'score'       : score,
        })

    # 只记录有结果的人脸数据,用于后面数据增强, 图片在预测时已保存
    if len(user_list)>0:
        face_save_to_temp(group_id, request_id, 'face_search', user_list, image=face_array[0])
        #face_save_to_temp(group_id, request_id, 'face_search', user_list)

    return user_list
Пример #2
0
def face_verify_db(request_id, b64_data, group_id, user_id):
    # 获取已知用户的特征数据
    face_list = user_face_list(group_id, user_id)
    if face_list==-1: # user_id 不存在
        return None, -1
    face_encodings = [face_info(i)['encodings'] for i in face_list]
    # 进行比较验证
    is_match, score, face_array = verify.verify_vgg.is_match_b64_2(face_encodings, b64_data)
    if type(score)!=type([]):
        score = score.tolist() # np.array

    # 只记录结果正确的人脸数据,用于后面数据增强
    if is_match>0:
        face_save_to_temp(group_id, request_id, 'face_verify_db', [user_id], face_array[0])

    return is_match, score
Пример #3
0
def face_search_mobile_tail(request_id, b64_data, mobile_tail, group_id='DEFAULT', max_user_num=5):
    # 获取手机尾号的用户列表
    user_list = user_list_by_mobile_tail(mobile_tail, group_id)

    # 获取已知用户的特征数据
    face_X = []
    face_y = []
    user_dict = {}
    for user in user_list:
        user_dict[user['user_id']] = user
        face_list = user_face_list(group_id, user['user_id'])
        if face_list==-1: # user_id 不存在
            continue

        for x in face_list:
            ec = face_info(x)['encodings']['vgg'].values()
            face_X.extend(ec)
            face_y.extend([user['user_id']]*len(ec))

    # 进行识别: 与给定的用户人脸进行比较
    r, face_boxes, face_array = verify.verify_vgg.is_match_b64_3((face_X, face_y), b64_data)

    user_list = []
    for i in r[:max_user_num]:
        user_id = i[0]
        user_list.append({
            'user_id'     : user_id,
            'mobile_tail' : mobile_tail, # 手机后4位
            'name'        : user_dict[user_id]['name'], # 用户姓名
            'location'    : face_boxes,
            'score'       : i[1], # 距离
        })

    # 只记录有结果的人脸数据,用于后面数据增强
    if len(user_list)>0:
        face_save_to_temp(group_id, request_id, 'face_search_mobile_tail', user_list, face_array[0])

    return user_list
Пример #4
0
def get_features_thread_db(face_algorithm,
                           model_name,
                           image_data,
                           group_id,
                           data_type='base64',
                           request_id='',
                           classifier='knn'):
    import keras.backend.tensorflow_backend as tb
    tb._SYMBOLIC_SCOPE.value = True

    module_verify = import_verify(face_algorithm)

    X_base64 = image_data
    faces_encodings, X_face_locations, faces = module_verify.get_features_b64(
        X_base64, angle=ALGORITHM[face_algorithm]['p_angle'])

    if len(X_face_locations) == 0:
        return [], []

    # 保存人脸到临时表, 只保存vgg的
    if request_id != '' and face_algorithm == 'vgg':
        face_save_to_temp(group_id, request_id, image=faces[0])

    return faces_encodings, X_face_locations
Пример #5
0
def predict_K(X_base64,
              group_id,
              model_path='',
              face_algorithm='vgg',
              data_type='base64',
              request_id=''):
    """
    Recognizes faces in given image using a trained Keras classifier

    """

    global CLF_CACHE

    # Load a trained Keras model (if one was passed in)
    clf_path = os.path.join(model_path,
                            '%s.%s.h5' % (group_id, face_algorithm))

    # 检查是否已缓存clf
    mtime = int(os.path.getmtime(clf_path))  # 模型最近修改时间

    with cache_lock:
        if (clf_path in CLF_CACHE.keys()) and (CLF_CACHE[clf_path][1]
                                               == mtime):
            model, label_y = CLF_CACHE[clf_path][0]
            #print('Bingo clf cache!', group_id)
        else:
            with graph.as_default():
                with session.as_default():
                    #with open(clf_path, 'rb') as f:
                    #    keras_clf = pickle.load(f)

                    # 读取模型,并识别
                    with open(clf_path + '.save', 'rb') as f:
                        input_dim, output_dim, label_y = pickle.load(f)

                    from train_classifier import get_model
                    model = get_model(input_dim, output_dim)
                    model.load_weights(clf_path)

            # 放进cache
            CLF_CACHE[clf_path] = ((model, label_y), mtime)
            print('Feeding CLF cache: ', CLF_CACHE.keys())

    if data_type == 'base64':
        # 动态载入 verify库
        module_verify = import_verify(face_algorithm)

        # Load image file and find face locations
        # Find encodings for faces in the test iamge
        faces_encodings, X_face_locations, faces = module_verify.get_features_b64(
            X_base64, angle=ALGORITHM[face_algorithm]['p_angle'])

        if len(X_face_locations) == 0:
            return []

        # 保存人脸到临时表, 只保存vgg的
        if request_id != '' and face_algorithm == 'vgg':
            dbport.face_save_to_temp(group_id, request_id, image=faces[0])

    else:
        # data_type = 'encodings'
        faces_encodings = X_base64
        X_face_locations = [(0, 0, 0, 0)]  # 从db来的数据没有人脸框坐标,只有一个人脸

    with graph.as_default():
        with session.as_default():
            results = []
            for x in range(len(X_face_locations)):

                # 按概率返回结果
                result = model.predict(np.array([faces_encodings[x]]))

                # 整理结果
                max_list = result[0].argsort()[-5:][::-1]  # 返回 5 个概率最大的结果
                percent_list = [result[0][i] for i in max_list]
                class_list = label_y.inverse_transform(max_list)
                # 保留概率大于 10% 的结果, 这里返回的评分是(1-概率), 为与距离表示一致:越小越接近
                result_list = [ [i, X_face_locations[x], 1-j, 1] for i,j in zip(class_list, percent_list) \
                        if j>KERAS_THRESHOLD_PERCENTAGE ]
                #print(result_list)
                results.extend(result_list)

    return results
Пример #6
0
def predict(X_base64,
            group_id,
            model_path='',
            distance_threshold=0.6,
            face_algorithm='vgg',
            data_type='base64',
            request_id=''):
    """
    Recognizes faces in given image using a trained KNN classifier

    :param X_base64: image data in base64 coding
    :param model_path: (optional) 已训练模型路径,默认当前路径
    """
    global CLF_CACHE

    # Load a trained KNN model (if one was passed in)
    clf_path = os.path.join(model_path,
                            group_id + ALGORITHM[face_algorithm]['ext'])

    # 检查是否已缓存clf
    mtime = int(os.path.getmtime(clf_path))  # 模型最近修改时间

    with cache_lock:
        if (clf_path in CLF_CACHE.keys()) and (CLF_CACHE[clf_path][1]
                                               == mtime):
            knn_clf = CLF_CACHE[clf_path][0]
            #print('Bingo clf cache!', group_id)
        else:
            with open(clf_path, 'rb') as f:
                knn_clf = pickle.load(f)
            # 放进cache
            CLF_CACHE[clf_path] = (knn_clf, mtime)
            print('Feeding CLF cache: ', CLF_CACHE.keys())

    if data_type == 'base64':
        # 动态载入 verify库
        module_verify = import_verify(face_algorithm)

        # Load image file and find face locations
        # Find encodings for faces in the test iamge
        faces_encodings, X_face_locations, faces = module_verify.get_features_b64(
            X_base64, angle=ALGORITHM[face_algorithm]['p_angle'])

        if len(X_face_locations) == 0:
            return []

        # 保存人脸到临时表, 只保存vgg的
        if request_id != '' and face_algorithm == 'vgg':
            dbport.face_save_to_temp(group_id, request_id, image=faces[0])

    else:
        # data_type = 'encodings'
        faces_encodings = X_base64
        X_face_locations = [(0, 0, 0, 0)]  # 从db来的数据没有人脸框坐标,只有一个人脸

    #print(faces_encodings)

    # Use the KNN model to find the first 5 best matches for the test face
    # 返回5个最佳结果
    closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=5)
    #are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]

    # Predict classes and remove classifications that aren't within the threshold
    #return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]

    #print(closest_distances)

    # return multi results
    results = []
    for i in range(len(X_face_locations)):
        # 第一个超过阈值,说明未匹配到
        if closest_distances[0][i][0] > distance_threshold:
            results.append([
                'unknown', X_face_locations[i],
                round(closest_distances[0][i][0], 6), 0
            ])
            continue
        # 将阈值范围内的结果均返回
        labels = {}
        temp_result = []
        for j in range(len(closest_distances[0][i])):
            if closest_distances[0][i][j] <= distance_threshold:
                # labels are in classes_
                l = knn_clf.classes_[knn_clf._y[closest_distances[1][i][j]]]
                #results.append( (l, X_face_locations[i], round(closest_distances[0][i][j], 6)) )
                if l not in labels.keys():
                    temp_result.append([
                        l,
                        X_face_locations[i],
                        #round(closest_distances[0][i][j], 6)
                        closest_distances[0][i][j] / distance_threshold
                    ])
                    labels[l] = 1
                else:
                    labels[l] += 1

        # 找到labels里count最大值
        max_count = max(labels.items(), key=operator.itemgetter(1))[1]
        # 相同人脸位置,labels 里 count最大的认为就是结果,如果count相同才返回多结果
        #results.extend([i+[labels[i[0]]] for i in temp_result if labels[i[0]]==max_count])
        # 当count最大的不是距离最短的结果时,同时返回距离最短的结果
        #results.extend( [result+[labels[result[0]]] for i,result in enumerate(temp_result) \
        #    if labels[result[0]]==max_count or (i==0 and labels[result[0]]!=max_count)] )
        # 最短距离的不是最大count,且距离短很多时,也加入结果
        temp_result2 = [
            i + [labels[i[0]]] for i in temp_result
            if labels[i[0]] == max_count
        ]
        if labels[temp_result[0][0]] != max_count and temp_result[0][
                2] / temp_result2[0][2] < 0.5:
            temp_result2.insert(0,
                                temp_result[0] + [labels[temp_result[0][0]]])
        results.extend(temp_result2)

    return results