import argparse
import numpy as np
import cv2 as cv
def str2bool(v)
if v.lower() in ['on', 'yes', 'true', 'y', 't']
return True
elif v.lower() in ['off', 'no', 'false', 'n', 'f']
return False
else:
raise NotImplementedError
parser = argparse.ArgumentParser()
parser.add_argument('--image1', '-i1', type=str, help='输入图像1的路径。省略则在默认相机上检测。')
parser.add_argument('--image2', '-i2', type=str, help='输入图像2的路径。当同时给出image1和image2参数时,程序会尝试在两张图像中找到人脸并运行人脸识别算法。')
parser.add_argument('--video', '-v', type=str, help='输入视频的路径。')
parser.add_argument('--scale', '-sc', type=float, default=1.0, help='用于调整输入视频帧大小的缩放因子。')
parser.add_argument('--face_detection_model', '-fd', type=str, default='face_detection_yunet_2021dec.onnx', help='人脸检测模型的路径。从https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet下载模型')
parser.add_argument('--face_recognition_model', '-fr', type=str, default='face_recognition_sface_2021dec.onnx', help='人脸识别模型的路径。从https://github.com/opencv/opencv_zoo/tree/master/models/face_recognition_sface下载模型')
parser.add_argument('--score_threshold', type=float, default=0.9, help='过滤掉分数 < score_threshold 的人脸。')
parser.add_argument('--nms_threshold', type=float, default=0.3, help='抑制iou >= nms_threshold 的边界框。')
parser.add_argument('--top_k', type=int, default=5000, help='在NMS之前保留top_k个边界框。')
parser.add_argument('--save', '-s', type=str2bool, default=False, help='设置为true以保存结果。使用相机时此标志无效。')
args = parser.parse_args()
def visualize(input, faces, fps, thickness=2)
if faces[1] is not None
for idx, face in enumerate(faces[1])
print('人脸 {}, 左上角坐标: ({:.0f}, {:.0f}), 框宽度: {:.0f}, 框高度 {:.0f}, 分数: {:.2f}'.format(idx, face[0], face[1], face[2], face[3], face[-1]))
coords = face[:-1].astype(np.int32)
cv.rectangle(input, (coords[0], coords[1]), (coords[0]+coords[2], coords[1]+coords[3]), (0, 255, 0), thickness)
cv.circle(input, (coords[4], coords[5]), 2, (255, 0, 0), thickness)
cv.circle(input, (coords[6], coords[7]), 2, (0, 0, 255), thickness)
cv.circle(input, (coords[8], coords[9]), 2, (0, 255, 0), thickness)
cv.circle(input, (coords[10], coords[11]), 2, (255, 0, 255), thickness)
cv.circle(input, (coords[12], coords[13]), 2, (0, 255, 255), thickness)
cv.putText(input,
'FPS: {:.2f}'.format(fps), (1, 16), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
if __name__ == '__main__'
args.face_detection_model,
"",
(320, 320),
args.score_threshold,
args.nms_threshold,
args.top_k
)
if args.image1 is not None
img1Width = int(img1.shape[1]*args.scale)
img1Height = int(img1.shape[0]*args.scale)
img1 =
cv.resize(img1, (img1Width, img1Height))
tm.start()
detector.setInputSize((img1Width, img1Height))
faces1 = detector.detect(img1)
tm.stop()
assert faces1[1] is not None, '在 {} 中找不到人脸'.format(args.image1)
visualize(img1, faces1, tm.getFPS())
if args.save
print('结果已保存到 result.jpg\n')
if args.image2 is not None
tm.reset()
tm.start()
detector.setInputSize((img2.shape[1], img2.shape[0]))
faces2 = detector.detect(img2)
tm.stop()
assert faces2[1] is not None, '在 {} 中找不到人脸'.format(args.image2)
visualize(img2, faces2, tm.getFPS())
args.face_recognition_model,"")
face1_align = recognizer.alignCrop(img1, faces1[1][0])
face2_align = recognizer.alignCrop(img2, faces2[1][0])
face1_feature = recognizer.feature(face1_align)
face2_feature = recognizer.feature(face2_align)
cosine_similarity_threshold = 0.363
l2_similarity_threshold = 1.128
cosine_score = recognizer.match(face1_feature, face2_feature, cv.FaceRecognizerSF_FR_COSINE)
l2_score = recognizer.match(face1_feature, face2_feature, cv.FaceRecognizerSF_FR_NORM_L2)
msg = '不同的人'
if cosine_score >= cosine_similarity_threshold
msg = '同一个人'
print('它们是{}. 余弦相似度: {}, 阈值: {} (值越高相似度越高,最大1.0)。'.format(msg, cosine_score, cosine_similarity_threshold))
msg = '不同的人'
if l2_score <= l2_similarity_threshold
msg = '同一个人'
print('它们是{}. L2范数距离: {}, 阈值: {} (值越低相似度越高,最小0.0)。'.format(msg, l2_score, l2_similarity_threshold))
else:
if args.video is not None
deviceId = args.video
else:
deviceId = 0
frameWidth = int(cap.get(cv.CAP_PROP_FRAME_WIDTH)*args.scale)
frameHeight = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)*args.scale)
detector.setInputSize([frameWidth, frameHeight])
hasFrame, frame = cap.read()
if not hasFrame
print('No frames grabbed!')
break
frame =
cv.resize(frame, (frameWidth, frameHeight))
tm.start()
faces = detector.detect(frame)
tm.stop()
visualize(frame, faces, tm.getFPS())
static Ptr< FaceDetectorYN > create(CV_WRAP_FILE_PATH const String &model, CV_WRAP_FILE_PATH const String &config, const Size &input_size, float score_threshold=0.9f, float nms_threshold=0.3f, int top_k=5000, int backend_id=0, int target_id=0)
使用给定参数创建人脸检测器类的实例。
static Ptr< FaceRecognizerSF > create(CV_WRAP_FILE_PATH const String &model, CV_WRAP_FILE_PATH const String &config, int backend_id=0, int target_id=0)
使用给定参数创建此类的实例。
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
尝试查找请求的数据文件。
void destroyAllWindows()
销毁所有HighGUI窗口。
void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
绘制一个简单、粗或填充的矩形。
void putText(InputOutputArray img, const String &text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=LINE_8, bool bottomLeftOrigin=false)
绘制文本字符串。
void circle(InputOutputArray img, Point center, int radius, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
Draws a circle.