{"id":521,"date":"2025-12-29T10:21:47","date_gmt":"2025-12-29T02:21:47","guid":{"rendered":"https:\/\/seantang.cn\/?p=521"},"modified":"2025-12-29T15:26:16","modified_gmt":"2025-12-29T07:26:16","slug":"face-scan","status":"publish","type":"post","link":"https:\/\/seantang.cn\/?p=521","title":{"rendered":"Face Scan"},"content":{"rendered":"\n<p><strong>Python<\/strong><br>python -m venv face_scan<br>face_scan\\Scripts\\activate<\/p>\n\n\n\n<p><strong>\u5b89\u88c5\u4f9d\u8d56\uff08GPU \u7248\uff09<\/strong><br>pip install &#8211;upgrade pip<br>pip install insightface onnxruntime-gpu opencv-python numpy tqdm<\/p>\n\n\n\n<p><strong>\u51c6\u5907\u672c\u4eba\u7684\u4eba\u8138\u7279\u5f81<\/strong><br>1. \u76ee\u5f55\u7ed3\u6784\u5efa\u8bae<\/p>\n\n\n\n<p>project\/ \u2502 <br>             \u251c\u2500 me\/ # \u653e\u4f60\u7684 5\u201310 \u5f20\u4e2a\u4eba\u7167\u7247 <br>              \u2502 \u251c\u2500 1.jpg <br>              \u2502 \u251c\u2500 2.jpg <br>             \u251c\u2500 scan_and_copy.py <br>             \u251c\u2500 my_face.npy<\/p>\n\n\n\n<p><strong>\u751f\u6210\u4eba\u8138\u7279\u5f81\uff08\u4e00\u6b21\u6027\u6267\u884c\uff09<\/strong><br>import cv2<br>import numpy as np<br>from insightface.app import FaceAnalysis<br>from pathlib import Path<\/p>\n\n\n\n<p>app = FaceAnalysis(name=&#8221;buffalo_l&#8221;, providers=[&#8220;CUDAExecutionProvider&#8221;])<br>app.prepare(ctx_id=0, det_size=(640, 640))<\/p>\n\n\n\n<p>embeddings = []<\/p>\n\n\n\n<p>for img_path in Path(&#8220;me&#8221;).glob(&#8220;*&#8221;):<br>img = cv2.imread(str(img_path))<br>faces = app.get(img)<br>if faces:<br>embeddings.append(faces[0].embedding)<\/p>\n\n\n\n<p>if not embeddings:<br>raise RuntimeError(&#8220;\u672a\u68c0\u6d4b\u5230\u4f60\u7684\u4eba\u8138&#8221;)<\/p>\n\n\n\n<p>my_face = np.mean(embeddings, axis=0)<br>np.save(&#8220;my_face.npy&#8221;, my_face)<br>print(&#8220;\u672c\u4eba\u7279\u5f81\u5df2\u751f\u6210\uff1amy_face.npy&#8221;)<\/p>\n\n\n\n<p><strong>\u626b\u63cf\u6587\u4ef6\u5939\u5e76\u62f7\u8d1d\u9ad8\u5ea6\u7591\u4f3c\u672c\u4eba\u7167\u7247<\/strong><br>import os<br>import shutil<br>import cv2<br>import numpy as np<br>from insightface.app import FaceAnalysis<br>from PIL import Image<br>import pillow_heif<\/p>\n\n\n\n<h6 class=\"wp-block-heading\"># \u6ce8\u518c HEIC \/ HEIF \u652f\u6301<\/h6>\n\n\n\n<p>pillow_heif.register_heif_opener()<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#================== \u914d\u7f6e\u533a ==================<\/h6>\n\n\n\n<p>SCAN_ROOT = r&#8221;C:\\Users\\Downloads&#8221; # \u2190 \u6539\u6210\u4f60\u7684\u6e90\u76ee\u5f55 \/ \u516c\u5171\u76d8<br>OUTPUT_ROOT = r&#8221;C:\\Picture&#8221;<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#\u5206\u7ea7\u9608\u503c\uff08ArcFace \u7ecf\u9a8c\u503c\uff09<\/h6>\n\n\n\n<p>THRESH_SURE = 0.38 # \u51e0\u4e4e 100% \u662f\u4f60<br>THRESH_LIKELY = 0.33 # \u9ad8\u6982\u7387\u662f\u4f60<br>THRESH_REVIEW = 0.30 # \u503c\u5f97\u4eba\u5de5\u770b\u4e00\u773c<\/p>\n\n\n\n<p>image_ext = (<br>&#8220;.jpg&#8221;, &#8220;.jpeg&#8221;, &#8220;.png&#8221;, &#8220;.bmp&#8221;, &#8220;.tiff&#8221;,<br>&#8220;.jfif&#8221;, &#8220;.heic&#8221;, &#8220;.heif&#8221;<br>)<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#===========================================<\/h6>\n\n\n\n<h6 class=\"wp-block-heading\">#\u521b\u5efa\u8f93\u51fa\u76ee\u5f55<\/h6>\n\n\n\n<p>for sub in [&#8220;sure&#8221;, &#8220;likely&#8221;, &#8220;review&#8221;]:<br>os.makedirs(os.path.join(OUTPUT_ROOT, sub), exist_ok=True)<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#\u52a0\u8f7d\u672c\u4eba\u7279\u5f81<\/h6>\n\n\n\n<p>my_face = np.load(&#8220;my_face.npy&#8221;)<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#\u521d\u59cb\u5316 InsightFace\uff08CPU\uff09<\/h6>\n\n\n\n<p>app = FaceAnalysis(<br>name=&#8221;buffalo_l&#8221;,<br>providers=[&#8220;CPUExecutionProvider&#8221;]<br>)<br>app.prepare(ctx_id=-1, det_size=(640, 640))<\/p>\n\n\n\n<p>def cosine_similarity(a, b):<br>return np.dot(a, b) \/ (np.linalg.norm(a) * np.linalg.norm(b))<\/p>\n\n\n\n<p>def read_image_any_format(path):<br>&#8220;&#8221;&#8221;<br>\u652f\u6301 JPG \/ PNG \/ HEIC \/ HEIF<br>\u8fd4\u56de OpenCV BGR \u56fe\u50cf<br>&#8220;&#8221;&#8221;<br>try:<br>img = Image.open(path).convert(&#8220;RGB&#8221;)<br>return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)<br>except Exception:<br>return None<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">#================== \u626b\u63cf\u5f00\u59cb ==================<\/h6>\n\n\n\n<p>for root, _, files in os.walk(SCAN_ROOT):<br>for file in files:<br>if not file.lower().endswith(image_ext):<br>continue<br><br>img_path = os.path.join(root, file)<br>    img = read_image_any_format(img_path)<br><br>    if img is None:<br>        continue<br><br>    faces = app.get(img)<br>    if not faces:<br>        continue<br><br>    best_score = -1.0<br>    for face in faces:<br>        score = cosine_similarity(face.embedding, my_face)<br>        if score > best_score:<br>            best_score = score<br><br>    if best_score >= THRESH_SURE:<br>        subdir = &#8220;sure&#8221;<br>    elif best_score >= THRESH_LIKELY:<br>        subdir = &#8220;likely&#8221;<br>    elif best_score >= THRESH_REVIEW:<br>        subdir = &#8220;review&#8221;<br>    else:<br>        continue<br><br>    dst = os.path.join(<br>        OUTPUT_ROOT,<br>        subdir,<br>        f&#8221;{best_score:.3f}_{file}&#8221;<br>    )<br><br>    shutil.copy2(img_path, dst)<br>    print(f&#8221;[COPY] {best_score:.3f} -> {dst}&#8221;)<\/p>\n\n\n\n<p>print(&#8220;\u626b\u63cf\u5b8c\u6210\uff08\u652f\u6301 HEIC\uff0cCPU\uff09&#8221;)<\/p>\n\n\n\n<p><strong>\u8fd9\u5957\u811a\u672c\u5df2\u7ecf\u53ef\u4ee5\uff1a<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2714 \u626b <strong>JPG + iPhone HEIC \u539f\u56fe<\/strong><\/li>\n\n\n\n<li>\u2714 \u652f\u6301\u591a\u4eba\u5408\u5f71\uff08\u53ea\u8981\u6709\u4f60\u5c31\u62f7\uff09<\/li>\n\n\n\n<li>\u2714 \u4e0d\u6f0f\u6389\u4f60\uff08\u4f4e\u9608\u503c\u515c\u5e95\uff09<\/li>\n\n\n\n<li>\u2714 \u81ea\u52a8\u5206\u7ea7\uff0c\u4eba\u5de5\u6210\u672c\u6781\u4f4e<\/li>\n\n\n\n<li>\u2714 \u5b8c\u5168\u672c\u5730\u3001\u53ef\u5ba1\u8ba1\u3001\u53ef\u89e3\u91ca<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Pythonpython -m venv face_scanface_scan\\Scripts\\activat [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25],"tags":[21],"class_list":["post-521","post","type-post","status-publish","format-standard","hentry","category-25","tag-21"],"_links":{"self":[{"href":"https:\/\/seantang.cn\/index.php?rest_route=\/wp\/v2\/posts\/521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/seantang.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/seantang.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/seantang.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/seantang.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=521"}],"version-history":[{"count":0,"href":"https:\/\/seantang.cn\/index.php?rest_route=\/wp\/v2\/posts\/521\/revisions"}],"wp:attachment":[{"href":"https:\/\/seantang.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/seantang.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/seantang.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}