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
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
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
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
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
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