def do_enhanement(name): # 获取指定name的图像路径列表 directory_path = cfg_manager.read_cfg('Common', 'face_directory') folderPath = os.path.sep.join([directory_path, name]) pathlist = oshelper.dirwalker(folderPath, ('.jpg', '.jpeg')) ePath = './data/enhanced/%s' % name # 数据增强存储地址 isExists = os.path.exists(ePath) if isExists: key = input('name has already exists, would you like to cover it?(y/n) :') if key == 'n': return if key == 'y': # 删除文件夹中所有增强文件 # 保留原有目录 oshelper.deleteAll(path=ePath, removedir=False) else: # 若不存在创建目录 os.makedirs('./data/enhanced/%s' % name) # 对指定照片库使用数据增强 for imagePath in pathlist: img = cv2.imread(imagePath) # 随机应用多种变换中的一种 random_key = random.randint(1, 3) if random_key == 1: rotate(img) elif random_key == 2: flip(img) elif random_key == 3: blurred(img) # 将增强过的列表写入文件夹 i = 0 for pic in output: pic_name = "enhanced%i.jpg" % i cv2.imwrite('./data/enhanced/%s/%s' % (name, pic_name), pic) # 存至硬盘 i += 1 # 验证图片可用性 # 移除无效增强 enumerated_list = oshelper.dirwalker(ePath, ('.jpg', '.jpeg')) for enumerated in enumerated_list: enumerated_pic = cv2.imread(enumerated) flag, detections = tool_interface.where_face(enumerated_pic) if flag: if len(detections) > 0: # 取人脸最大可能性的位置 i = np.argmax(detections[0, 0, :, 2]) confidence = detections[0, 0, i, 2] # 如果置信度小于设定值 if confidence < float(cfg_manager.read_cfg('FaceEmbeddings', 'confidence')): os.remove(enumerated) print('removed') else: print('enumerated') else: print('\033[1;31m[ERROR]enumerate failed\033[0m')
def get_path(): pickle_directory = cfg_manager.read_cfg('Common', 'pickle_directory') empickle = os.path.sep.join([pickle_directory, "embeddings.pickle"]) lepickle = os.path.sep.join([pickle_directory, "le.pickle"]) recopickle = os.path.sep.join([pickle_directory, "recognizer.pickle"]) pickledic = { 'embedding': empickle, 'le': lepickle, 'recognizer': recopickle } return pickledic
def where_face(img): flag = True # 成功执行的标志 detections = [] protoPath = os.path.sep.join( [cfg_manager.read_cfg('Common', 'detector_path'), "deploy.prototxt"]) modelPath = os.path.sep.join([ cfg_manager.read_cfg('Common', 'detector_path'), "res10_300x300_ssd_iter_140000.caffemodel" ]) # 加载图片,保持纵横比更改宽度维600 # 取得标准化后的图像高度与宽度 image = imutils.resize(img, width=600) (h, w) = image.shape[:2] # 取得图片的RGB均值 resized = cv2.resize(image, (300, 300)) r_mean = np.mean(resized[:, :, 0]) g_mean = np.mean(resized[:, :, 1]) b_mean = np.mean(resized[:, :, 2]) rgb_means = (r_mean, g_mean, b_mean) # 对整张图片构建blob imageBlob = cv2.dnn.blobFromImage(resized, 1.0, (300, 300), rgb_means, swapRB=False, crop=False) # 输入深度学习模型并取得预测结果 try: detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath) detector.setInput(imageBlob) detections = detector.forward() except SyntaxError: flag = False finally: return flag, detections
def do_alignment(image): # 加载Haar分类器 glasses_eyes_classifier = cv2.CascadeClassifier( cfg_manager.read_cfg('FaceAlignment', 'glasseseyes_classifier_path')) lefteye_classifier = cv2.CascadeClassifier( cfg_manager.read_cfg('FaceAlignment', 'lefteye_classifier_path')) righteye_classifier = cv2.CascadeClassifier( cfg_manager.read_cfg('FaceAlignment', 'righteye_classifier_path')) # 对传入照片进行浅度复制 img = image.copy() # 初始化人眼中心点数组 eye_location = [] # 获取人脸图像尺寸 (fH, fW) = img.shape[:2] # 裁剪人脸上半部分 eye_region = img[0:int(fH / 2.1), 0:int(fW)] # 首先使用Haar分类器对两只眼睛分别进行定位 lefteye = lefteye_classifier.detectMultiScale(eye_region, 1.2, 10, cv2.CASCADE_SCALE_IMAGE) righteye = righteye_classifier.detectMultiScale(eye_region, 1.2, 10, cv2.CASCADE_SCALE_IMAGE) # 若两个分类器均检测到结果 if len(righteye) == 1 and len(lefteye) == 1: # 分析左右眼坐标差异性 difference = reduce(operator.add, lefteye - righteye) var = np.var(difference) # 若左右眼区域之差的方差大于200 # 视为成功分别检测到左右眼 if var > 200: faceRects_eye = [lefteye, righteye] for faceRect_eye in faceRects_eye: # 压缩二维数组至一维 _faceRect_eye = reduce(operator.add, faceRect_eye) x1, y1, w1, h1 = _faceRect_eye cv2.rectangle(eye_region, (int(x1), int(y1)), (int(x1) + int(w1), int(y1) + int(h1)), (0, 255, 0), 2) # 标出人眼中心点 eye_region_center = (int(x1) + int(w1 / 2), int(y1) + int(h1 / 2)) cv2.circle(eye_region, eye_region_center, radius=3, color=(0, 0, 255)) for num in eye_region_center: eye_location.append(num) if len(eye_location) == 4: cv2.line(eye_region, (eye_location[0], eye_location[1]), (eye_location[2], eye_location[3]), (0, 0, 255), thickness=3) k = (eye_location[3] - eye_location[1]) / (eye_location[2] - eye_location[0]) cv2.imshow('eye', eye_region) cv2.waitKey(10) return else: print('face_alignment failed') # 当仅仅检测到一只眼时 elif len(righteye) == 1 or len(lefteye) == 1: faceRects_eye = [lefteye, righteye] for faceRect_eye in faceRects_eye: # 若存在某一人眼的坐标 # 压缩二维数组至一维 if len(faceRect_eye) != 0: _faceRect_eye = reduce(operator.add, faceRect_eye) print(_faceRect_eye) # 使用戴眼镜的人眼检测查找另一只眼睛 glasses_eyes = glasses_eyes_classifier.detectMultiScale( eye_region, 1.2, 10, cv2.CASCADE_SCALE_IMAGE) print(glasses_eyes) # 若能找到两只人眼 if len(glasses_eyes) == 2: # 分析左右眼坐标差异性 difference = glasses_eyes[0] - glasses_eyes[1] var = np.var(difference) # 若左右眼区域之差的方差大于200 # 视为成功分别检测到左右眼 if var > 200: for glasses_eye in glasses_eyes: # 压缩二维数组至一维 _faceRect_eye = reduce(operator.add, glasses_eye) x1, y1, w1, h1 = _faceRect_eye cv2.rectangle( eye_region, (int(x1), int(y1)), (int(x1) + int(w1), int(y1) + int(h1)), (0, 255, 0), 2) cv2.imshow('eye', eye_region) cv2.waitKey(10) return else: print('face_alignment failed') # 若只检测到一只眼 elif len(glasses_eyes) == 1: eyes = [faceRect_eye, glasses_eyes] difference = reduce(operator.add, eyes[0] - eyes[1]) var = np.var(difference) if var > 200: for eye in eyes: _faceRect_eye = reduce(operator.add, eye) x1, y1, w1, h1 = _faceRect_eye cv2.rectangle( eye_region, (int(x1), int(y1)), (int(x1) + int(w1), int(y1) + int(h1)), (0, 255, 0), 2) cv2.imshow('eye', eye_region) cv2.waitKey(10) return else: print('face_alignment failed') else: print('face_alignment failed') else: print('face_alignment failed')
def do_encoding(name): global run_flag global main_box global knownNames global knownEmbeddings global pic_num # 从磁盘中加载embedder print("\033[1;33m[INFO] loading face recognizer...\033[0m") try: embedder = cv2.dnn.readNetFromTorch( cfg_manager.read_cfg('Common', 'embedder_path')) except cv2.error: # 返回模型加载失败错误 print('\033[1;31m[ERROR]load embedder failed\033[0m') print(">>>HELP") print( " * Confirm that the corresponding model file exists in the specified path" ) flag = 'Embedder_Error' return flag print("\033[22;32m>>>success\033[0m") # 获取编码pickle路径 pickledic = pickle_helper.get_path() # 尝试从硬盘中读取pickle try: data = pickle_helper.load_pickle_from_disk(pickledic['embedding']) knownNames = data["names"] # pickle中已有的name knownEmbeddings = data["embeddings"] # pickle中以有的人脸编码 # 捕获异常 # 尝试通过已有图像重新生成pickle except FileNotFoundError: flag = face_encoding.do_embedding() if flag == 'FaceNum_Error': # 程序刹车 run_flag = False else: # 成功重新生成则再次读取pickle data = pickle_helper.load_pickle_from_disk(pickledic['embedding']) knownNames = data["names"] # pickle中已有的name knownEmbeddings = data["embeddings"] # pickle中以有的人脸编码 pic_num = 0 while run_flag: # 按下s开始编码 if pressed_key == 's': # 若main_box中存在数据 # 说明camera_shot中存在人脸需要执行编码 if len(main_box) != 0: pic_name = time.strftime("%Y%m%d_%H_%M_%S.jpg", time.localtime()) cv2.imwrite("./face_directory/%s/%s" % (name, pic_name), camera_shot) # 存至硬盘 startX = main_box[0] startY = main_box[1] endX = main_box[2] endY = main_box[3] # 将ROI区域截出 face = camera_shot[startY:endY, startX:endX] (fH, fW) = face.shape[:2] # 剔除较小的人脸 if fW < 20 or fH < 20: continue # 取得图片RGB均值 r_mean = np.mean(face[:, :, 0]) g_mean = np.mean(face[:, :, 1]) b_mean = np.mean(face[:, :, 2]) rgb_means = (r_mean, g_mean, b_mean) # 构造blob # 对人脸进行编码 faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255, (96, 96), rgb_means, swapRB=True, crop=False) embedder.setInput(faceBlob) vec = embedder.forward() # 将姓名写入列表 # 编码存储至列表 knownNames.append(name) knownEmbeddings.append(vec.flatten()) pic_num += 1 # 已捕获照片数量+1 # 按下任意键暂停编码 else: continue time.sleep(1) if pic_num != 0: data = {"embeddings": knownEmbeddings, "names": knownNames} pickle_helper.write_pickle_to_disk(pickledic['embedding'], data) train_model.do_modeltrain() else: os.removedirs('./face_directory/%s' % name) print('[INFO] no pic added')
def camera_tracking(): # 从磁盘加载detector print("\033[1;33m[INFO] loading face detector from \033[4;32m%s\033[0m" % cfg_manager.read_cfg('Common', 'detector_path')) protoPath = os.path.sep.join( [cfg_manager.read_cfg('Common', 'detector_path'), "deploy.prototxt"]) modelPath = os.path.sep.join([ cfg_manager.read_cfg('Common', 'detector_path'), "res10_300x300_ssd_iter_140000.caffemodel" ]) try: detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath) except cv2.error: # 返回模型加载失败错误 print('\033[1;31m[ERROR]load detector failed\033[0m') print(">>>HELP") print( " * Confirm that the corresponding model file exists in the specified path" ) flag = 'Detector_Error' return flag print("\033[22;32m>>>success\033[0m") capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) while run_flag: ret, frame = capture.read() if ret is False: break image = imutils.resize(frame, width=600) (h, w) = image.shape[:2] # 取得图片的RGB均值 resized = cv2.resize(image, (300, 300)) r_mean = np.mean(resized[:, :, 0]) g_mean = np.mean(resized[:, :, 1]) b_mean = np.mean(resized[:, :, 2]) rgb_means = (r_mean, g_mean, b_mean) # 构建Blob imageBlob = cv2.dnn.blobFromImage(resized, 1.0, (300, 300), rgb_means, swapRB=False, crop=False) detector.setInput(imageBlob) detections = detector.forward() # 根据box面积将人脸主体与其他人分离 # 使用绿色box标记主体,红色box标记路人 box_list = [] # box区域列表 box_measure = [] # box面积列表 global main_box global camera_shot # 扫描循环 for i in range(0, detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.4: box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) intbox = box.astype("int") (startX, startY, endX, endY) = intbox face_box = intbox camera_shot = image.copy() measure = (endX - startX) * (endY - startY) # 计算box面积 box_measure.append(measure) # 写入box面积列表 box_item = [startX, startY, endX, endY] box_list.append(box_item) # 写入box区域列表 try: max_measure = box_measure.index(max(box_measure)) except ValueError: continue # 绘制循环 for i in range(0, len(box_measure)): startX = box_list[i][0] startY = box_list[i][1] endX = box_list[i][2] endY = box_list[i][3] if i == max_measure: cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 2) global main_box main_box = [startX, startY, endX, endY] else: cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2) cv2.putText(image, 'captured:' + str(pic_num), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imshow('camera', image) cv2.waitKey(1) capture.release() cv2.destroyAllWindows()
def do_recognition(): parent_directory = os.getcwd() # 获取存储人脸检测器的face_detection_model路径 detector_path = os.path.sep.join( [parent_directory, cfg_manager.read_cfg('Common', 'detector_path')]) # load detector from disk print("[INFO] loading face detector...") protoPath = os.path.sep.join( [cfg_manager.read_cfg('Common', 'detector_path'), "deploy.prototxt"]) modelPath = os.path.sep.join([ cfg_manager.read_cfg('Common', 'detector_path'), "res10_300x300_ssd_iter_140000.caffemodel" ]) detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath) print("[INFO] loading face recognizer...") # 获取用于生成128维人脸向量的Torch模型存储位置 embedder_path = os.path.sep.join( [parent_directory, cfg_manager.read_cfg('Common', 'embedder_path')]) embedderPath = os.path.sep.join( [embedder_path, "openface_nn4.small2.v1.t7"]) # 加载Torch模型 embedder = cv2.dnn.readNetFromTorch( cfg_manager.read_cfg('Common', 'embedder_path')) # 读取SVM模型及对应编码文件 recognizer = pickle.loads( open(r'./data/pickleHere/recognizer.pickle', "rb").read()) le = pickle.loads(open(r'./data/pickleHere/le.pickle', "rb").read()) # 从摄像头获取图像 # 转换每张图的宽度为600,保持其纵横比并读取高度 capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 启动键盘监控线程 kthread = keyboardThread() kthread.start() while run_flag: ret, frame = capture.read() if ret is False: break image = imutils.resize(frame, width=600) (h, w) = image.shape[:2] # 构建Blob imageBlob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0), swapRB=False, crop=False) detector.setInput(imageBlob) detections = detector.forward() # 提取人脸ROI for i in range(0, detections.shape[2]): # 取得置信度 confidence = detections[0, 0, i, 2] # 根据置信度筛选是否存在人脸 if confidence > 0.4: # 取得最高置信度对应的box区域 box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") # 框出ROI区域 face = image[startY:endY, startX:endX] (fH, fW) = face.shape[:2] # 过滤过小的人脸 if fW < 20 or fH < 20: continue # 识别人脸姓名 faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255, (96, 96), (0, 0, 0), swapRB=True, crop=False) embedder.setInput(faceBlob) vec = embedder.forward() # 使用训练好的SVM分类器识别人脸 preds = recognizer.predict_proba(vec)[0] # 使用最高概率索引器查询标签编码器 j = np.argmax(preds) proba = preds[j] name = le.classes_[j] # 绘制box text = "{}: {:.2f}%".format(name, proba * 100) y = startY - 10 if startY - 10 > 10 else startY + 10 cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 2) cv2.putText(image, text, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 255, 0), 2) cv2.imshow('', image) cv2.waitKey(1) capture.release() cv2.destroyAllWindows() kthread.join()
def do_management(): # 得到name_list try: data = pickle_helper.load_pickle_from_disk( r'C:\Users\ZHIYUAN\PycharmProjects\Facepro\data\pickleHere\embeddings.pickle' ) names = data["names"] name_list = [] except FileNotFoundError: print( "\033[1;31m[ERROR]no pickle here, please load your face and encode first\033[0m" ) return for name in names: if name not in name_list: name_list.append(name) print('| id | name |') for i in range(len(name_list)): print(' %i %s' % (i, name_list[i])) # 选定操作用户 flag = True global selected while flag: try: n = int(input('\033[4;33menter an id :\033[0m')) selected = name_list[n] flag = False except ValueError: print('no such id please enter again ') except IndexError: print('index out of range') try: global directory_path global folder_names directory_path = cfg_manager.read_cfg('Common', 'face_directory') folder_names = os.listdir(os.path.sep.join([directory_path, selected])) lastchange = 0 for folder_name in folder_names: time = folder_name.replace('_', '').replace('.jpg', '') if int(time) > int(lastchange): lastchange = time finally: pass # 展示选中用户信息 print( '\033[1;32m=======================User Info========================\033[0m' ) print('- Name: %s' % selected) print('- Pic num: %i' % names.count(selected)) print('- Data enhanced: %s' % os.path.exists('./data/enhanced/%s' % selected)) print('- Last modified: %s' % lastchange) print( '\033[1;32m========================================================\033[0m' ) print('press 1 for : Delete') print('press 2 for : DataEnhancement') print('press 3 for : Backup') # 选择对用户的操作 key = input('\033[4;33menter num and press enter : \033[0m') function_choose(key)
def do_embedding(): """ >>使用cfg_manager从硬盘加载配置文件 >>读取模型 人脸定位:deploy.prototxt res10_300x300_ssd_iter_140000.caffemodel Torch嵌入模型:openface_nn4.small2.v1.t7 >>对读取到的人脸进行编码并写入 embeddings.pickle """ # 错误标记 flag = '' # 从磁盘加载detector print("\033[1;33m[INFO] loading face detector from \033[4;32m%s\033[0m" % cfg_manager.read_cfg('Common', 'detector_path')) protoPath = os.path.sep.join( [cfg_manager.read_cfg('Common', 'detector_path'), "deploy.prototxt"]) modelPath = os.path.sep.join([ cfg_manager.read_cfg('Common', 'detector_path'), "res10_300x300_ssd_iter_140000.caffemodel" ]) try: detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath) except cv2.error: # 返回模型加载失败错误 print('\033[1;31m[ERROR]load detector failed\033[0m') print(">>>HELP") print( " * Confirm that the corresponding model file exists in the specified path" ) flag = 'Detector_Error' return flag print("\033[22;32m>>>success\033[0m") # 从磁盘中加载embedder print("\033[1;33m[INFO] loading face recognizer...\033[0m") try: embedder = cv2.dnn.readNetFromTorch( cfg_manager.read_cfg('Common', 'embedder_path')) except cv2.error: # 返回模型加载失败错误 print('\033[1;31m[ERROR]load embedder failed\033[0m') print(">>>HELP") print( " * Confirm that the corresponding model file exists in the specified path" ) flag = 'Embedder_Error' return flag print("\033[22;32m>>>success\033[0m") directory_path = cfg_manager.read_cfg('Common', 'face_directory') folder_names = os.listdir(directory_path) knownEmbeddings = [] knownNames = [] folderPaths = [] total = 0 nameNum = 0 for folder_name in folder_names: # 获取每个文件夹的路径 folderPaths.append(os.path.sep.join([directory_path, folder_name])) nameNum += 1 name_code = -1 for folderPath in folderPaths: imagePaths = list(paths.list_images(folderPath)) name_code += 1 # 获取到当前处理的文件夹名 name = folder_names[name_code] # 判断此用户是否启用了数据增强 isExists = os.path.exists('./data/enhanced/%s' % name) # 若启用了数据增强 # 将增强后的文件路径一并写入代编码路径中 if isExists: enhancedPaths = oshelper.dirwalker('./data/enhanced/%s' % name, ('jpg', )) for enhancedPath in enhancedPaths: imagePaths.append(enhancedPath) for (i, imagePath) in enumerate(imagePaths): print("[INFO] processing image {}/{}".format( i + 1, len(imagePaths))) # 加载图片,保持纵横比更改宽度维600 # 取得标准化后的图像高度与宽度 image = cv2.imread(imagePath) image = imutils.resize(image, width=600) (h, w) = image.shape[:2] # 取得图片的RGB均值 resized = cv2.resize(image, (300, 300)) r_mean = np.mean(resized[:, :, 0]) g_mean = np.mean(resized[:, :, 1]) b_mean = np.mean(resized[:, :, 2]) rgb_means = (r_mean, g_mean, b_mean) # 对整张图片构建blob imageBlob = cv2.dnn.blobFromImage(resized, 1.0, (300, 300), rgb_means, swapRB=False, crop=False) # 输入深度学习模型并取得预测结果 detector.setInput(imageBlob) detections = detector.forward() # 确认检测到人脸 if len(detections) > 0: # 取人脸最大可能性的位置 i = np.argmax(detections[0, 0, :, 2]) confidence = detections[0, 0, i, 2] # 如果置信度大于设定值 if confidence >= float( cfg_manager.read_cfg('FaceEmbeddings', 'confidence')): # 取得ROI区域 roi = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = roi.astype("int") # 将ROI区域截出 face = image[startY:endY, startX:endX] (fH, fW) = face.shape[:2] # 剔除较小的人脸 if fW < 20 or fH < 20: continue # 构造blob # 对人脸进行编码 faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255, (96, 96), (0, 0, 0), swapRB=True, crop=False) embedder.setInput(faceBlob) vec = embedder.forward() # 将姓名写入列表 # 编码存储至列表 knownNames.append(name) knownEmbeddings.append(vec.flatten()) total += 1 else: print("\033[1;31m[ERROR]no face detected\033[0m") # 将编码写入pickle print("[INFO] serializing {} encodings...".format(total)) data = {"embeddings": knownEmbeddings, "names": knownNames} pickle_helper.write_pickle_to_disk(pickle_helper.get_path()['embedding'], data) print("-------------------------------------") if nameNum < 2: print(knownNames) print('\033[1;31m[ERROR]classes must be greater than one\033[0m') flag = 'FaceNum_Error' return flag