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.