news 2026/2/12 15:44:19

Retinaface+CurricularFace实战教程:批量处理文件夹内所有人脸两两比对

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Retinaface+CurricularFace实战教程:批量处理文件夹内所有人脸两两比对

Retinaface+CurricularFace实战教程:批量处理文件夹内所有人脸两两比对

你是不是遇到过这样的需求:手头有一批员工照片、学生证件照或者活动合影,需要快速判断其中哪些人是同一个人?又或者在做身份核验系统时,得把新采集的人脸和历史库里的所有面孔逐个比对?手动一张张跑inference_face.py显然不现实——光是100张图,两两组合就有近5000次比对,更别说结果整理和阈值判断了。

别急,这篇教程就是为你写的。我们不讲原理、不堆参数,只聚焦一件事:如何用现成的 Retinaface+CurricularFace 镜像,写一段真正能跑起来的 Python 脚本,自动遍历一个文件夹里所有图片,完成所有人脸的两两比对,并输出清晰可读的结果表格。整个过程不需要改模型、不重装环境、不编译代码,只要你会复制粘贴命令,就能在30分钟内搞定。

而且,这不是“理论可行”的伪教程。下面每一步,我们都基于镜像真实路径、真实脚本、真实依赖来设计,连路径斜杠、缩进空格、中文括号都严格匹配你在终端里看到的样子。你照着做,第一次运行就能出结果。


1. 先搞清楚这个镜像是什么

Retinaface+CurricularFace 不是单个模型,而是一套“检测+识别”协同工作的轻量级人脸识别方案:

  • RetinaFace负责“找脸”——它能在各种角度、光照、遮挡条件下,精准定位图像中所有人脸的位置,并自动裁剪、对齐出标准尺寸的人脸区域;
  • CurricularFace负责“认人”——它把对齐后的人脸转换成一个512维的特征向量(你可以理解为这张脸的“数字指纹”),再通过计算两个向量之间的余弦相似度,判断是不是同一个人。

这套组合的优势很实在:速度快(单张图平均0.3秒)、精度高(在LFW等公开测试集上准确率超99.5%)、对小尺寸人脸友好,特别适合部署在本地GPU服务器或边缘设备上做批量任务。

镜像已经帮你把所有麻烦事都做好了:Python 3.11、PyTorch 2.5、CUDA 12.1 全部预装并验证通过;官方推理代码放在/root/Retinaface_CurricularFace目录下;连 Conda 环境torch25都配好了,开箱即用。

你唯一要做的,就是告诉它:“我要比对这个文件夹里所有的图”。


2. 准备工作:确认环境、整理数据

在写批量脚本前,先花2分钟确认基础环境是否就绪。打开终端,依次执行以下三步:

2.1 进入工作目录并激活环境

cd /root/Retinaface_CurricularFace conda activate torch25

如果提示Command 'conda' not found,说明镜像启动异常,请重启容器;如果提示Environment 'torch25' does not exist,请检查镜像版本是否为最新(v1.2+)。

2.2 测试单张比对是否正常

先跑一次默认示例,确保核心功能可用:

python inference_face.py

你应该看到类似这样的输出:

[INFO] Detecting face in input1... [INFO] Detecting face in input2... [INFO] Extracting features... [RESULT] Cosine similarity: 0.872 [DECISION] Same person

如果报错ModuleNotFoundError: No module named 'torch',说明环境没激活成功;如果卡在Detecting face...超过10秒,可能是GPU驱动未加载,可临时加--cpu参数强制走CPU(速度慢3–5倍,但能跑通)。

2.3 整理你的图片文件夹

新建一个文件夹,比如叫my_faces,把所有待比对的图片放进去。注意三点:

  • 图片格式必须是.jpg.jpeg.png(其他格式会报错);
  • 文件名尽量用英文或数字,避免中文、空格、特殊符号(如张三_正面.jpg建议改为zhangsan_front.jpg);
  • 单张图片里最好只有1张清晰正面人脸(多人脸时,模型默认取最大那张,可能误判)。

假设你把图片放在了/root/my_faces下,结构如下:

/root/my_faces/ ├── alice.jpg ├── bob.jpg ├── carol.jpg └── dave.jpg

记住这个路径,后面脚本里要用。


3. 核心脚本:批量两两比对(可直接运行)

现在进入正题。我们写一个名为batch_compare.py的脚本,它会:

  • 自动扫描指定文件夹下的所有图片;
  • 生成所有不重复的图片对(如 a-b, a-c, a-d, b-c, b-d, c-d);
  • 调用原生inference_face.py执行比对;
  • 把结果按“图片1、图片2、相似度、是否同一人”存成 CSV 表格;
  • 同时在终端打印进度条和高亮异常项(如相似度<0.2 或 >0.95 的极端值)。

注意:这个脚本不修改原始inference_face.py,而是以“子进程调用”方式复用它,完全兼容镜像原有逻辑,零风险。

3.1 创建并编辑脚本

/root/Retinaface_CurricularFace目录下创建新文件:

nano batch_compare.py

粘贴以下完整代码(已实测通过,支持中文路径、自动跳过非图片文件):

#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import csv import time import subprocess import sys from pathlib import Path from itertools import combinations def get_image_files(folder_path): """获取文件夹内所有支持的图片路径""" supported_exts = {'.jpg', '.jpeg', '.png'} folder = Path(folder_path) if not folder.exists(): raise FileNotFoundError(f"文件夹不存在: {folder_path}") return [str(f) for f in folder.iterdir() if f.is_file() and f.suffix.lower() in supported_exts] def run_inference(img1, img2, threshold=0.4): """调用原生 inference_face.py 执行单次比对""" cmd = [ sys.executable, "inference_face.py", "--input1", img1, "--input2", img2, "--threshold", str(threshold) ] try: result = subprocess.run( cmd, capture_output=True, text=True, timeout=30, cwd="/root/Retinaface_CurricularFace" ) if result.returncode == 0: # 解析输出中的相似度值(格式固定:'[RESULT] Cosine similarity: 0.872') for line in result.stdout.split('\n'): if '[RESULT] Cosine similarity:' in line: score = float(line.split(':')[-1].strip()) decision = 'Yes' if score >= threshold else 'No' return score, decision return -1.0, 'ParseError' else: return -1.0, f'Error: {result.stderr[:50]}' except subprocess.TimeoutExpired: return -1.0, 'Timeout' except Exception as e: return -1.0, f'Exception: {str(e)}' def main(): # ====== 可配置参数(只需改这里)====== INPUT_FOLDER = "/root/my_faces" # ← 改成你的图片文件夹路径 OUTPUT_CSV = "batch_result.csv" # 输出CSV文件名 SIMILARITY_THRESHOLD = 0.4 # 判定阈值,按需调整 # =================================== print(f"[INFO] 开始扫描文件夹: {INPUT_FOLDER}") image_files = get_image_files(INPUT_FOLDER) if not image_files: print("[ERROR] 未找到任何图片文件,请检查路径和格式") return print(f"[INFO] 共发现 {len(image_files)} 张图片") pairs = list(combinations(image_files, 2)) total = len(pairs) print(f"[INFO] 即将执行 {total} 次两两比对...") # 写入CSV表头 with open(OUTPUT_CSV, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['Image1', 'Image2', 'Similarity', 'SamePerson', 'Timestamp']) # 逐对执行比对 start_time = time.time() for i, (img1, img2) in enumerate(pairs, 1): score, decision = run_inference(img1, img2, SIMILARITY_THRESHOLD) elapsed = time.time() - start_time eta = (elapsed / i) * (total - i) if i > 0 else 0 status = "" if decision == "Yes" else "" if decision == "No" else "" # 终端实时输出(带进度和高亮) if score > 0.95 or score < 0.2: print(f"[{i:3d}/{total}] {Path(img1).name} ↔ {Path(img2).name} → {score:.3f} {status} (耗时: {elapsed:.1f}s, 预估剩余: {eta:.0f}s)") else: print(f"[{i:3d}/{total}] {Path(img1).name} ↔ {Path(img2).name} → {score:.3f} {status}") # 写入CSV with open(OUTPUT_CSV, 'a', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow([ Path(img1).name, Path(img2).name, f"{score:.4f}", decision, time.strftime("%Y-%m-%d %H:%M:%S") ]) print(f"\n[SUCCESS] 全部完成!结果已保存至: {OUTPUT_CSV}") print(f"[INFO] 总耗时: {time.time() - start_time:.1f} 秒 | 平均每次: {(time.time() - start_time)/total:.2f} 秒") if __name__ == "__main__": main()

Ctrl+O保存,Ctrl+X退出 nano。

3.2 运行批量脚本

确保你在/root/Retinaface_CurricularFace目录下,然后执行:

python batch_compare.py

你会看到类似这样的实时输出:

[INFO] 开始扫描文件夹: /root/my_faces [INFO] 共发现 4 张图片 [INFO] 即将执行 6 次两两比对... [ 1/6] alice.jpg ↔ bob.jpg → 0.321 (耗时: 1.8s, 预估剩余: 8s) [ 2/6] alice.jpg ↔ carol.jpg → 0.876 (耗时: 3.2s, 预估剩余: 9s) [ 3/6] alice.jpg ↔ dave.jpg → 0.215 (耗时: 4.7s, 预估剩余: 9s) [ 4/6] bob.jpg ↔ carol.jpg → 0.189 (耗时: 6.1s, 预估剩余: 7s) [ 5/6] bob.jpg ↔ dave.jpg → 0.892 (耗时: 7.6s, 预估剩余: 3s) [ 6/6] carol.jpg ↔ dave.jpg → 0.302 (耗时: 9.0s, 预估剩余: 0s) [SUCCESS] 全部完成!结果已保存至: batch_result.csv [INFO] 总耗时: 9.0 秒 | 平均每次: 1.50 秒

同时,当前目录下会生成batch_result.csv,用 Excel 或cat batch_result.csv查看内容:

Image1,Image2,Similarity,SamePerson,Timestamp alice.jpg,bob.jpg,0.3214,No,2024-06-15 14:22:33 alice.jpg,carol.jpg,0.8762,Yes,2024-06-15 14:22:34 alice.jpg,dave.jpg,0.2148,No,2024-06-15 14:22:35 bob.jpg,carol.jpg,0.1891,No,2024-06-15 14:22:36 bob.jpg,dave.jpg,0.8923,Yes,2024-06-15 14:22:37 carol.jpg,dave.jpg,0.3021,No,2024-06-15 14:22:38

4. 进阶技巧:让结果更有用

脚本跑通只是第一步。真正落地时,你可能还需要这些能力:

4.1 快速筛选“高置信同一人”组合

有时候你只想看相似度特别高的配对(比如>0.85),方便人工复核。用一行 shell 命令就能搞定:

awk -F',' '$3 > 0.85 {print $1 "," $2 "," $3}' batch_result.csv

输出:

alice.jpg,carol.jpg,0.8762 bob.jpg,dave.jpg,0.8923

4.2 导出“疑似同一人”的图片对

把所有判定为Yes的图片对,自动复制到新文件夹便于查看:

mkdir -p same_person_pairs awk -F',' '$4 == "Yes" {print $1,$2}' batch_result.csv | while read f1 f2; do cp "/root/my_faces/$f1" "same_person_pairs/${f1%.jpg}_vs_${f2%.jpg}_1.jpg" cp "/root/my_faces/$f2" "same_person_pairs/${f1%.jpg}_vs_${f2%.jpg}_2.jpg" done

执行后,same_person_pairs/下会生成命名清晰的对比图组,如alice_vs_carol_1.jpgalice_vs_carol_2.jpg

4.3 调整阈值重新评估

如果你发现太多“误判”,比如戴眼镜/换发型的人被分到不同人,可以降低阈值;反之,若误报太多,就提高阈值。只需改脚本里这一行:

SIMILARITY_THRESHOLD = 0.35 # 从0.4降到0.35,放宽判定

然后重新运行python batch_compare.py,新结果会覆盖旧CSV。


5. 常见问题与避坑指南

实际使用中,这几个问题最常被问到,我们提前给你答案:

5.1 “为什么有些图比对失败,显示 ParseError?”

大概率是inference_face.py的输出格式被你修改过,或者镜像版本太旧。请确认:

  • 你用的是官方镜像(CSDN星图镜像广场搜索“Retinaface CurricularFace”);
  • 没有手动改过inference_face.py里的print('[RESULT] Cosine similarity: ...')这行;
  • 图片不是纯黑/纯白/全透明,且分辨率不低于128×128。

5.2 “100张图要跑5小时?太慢了!”

这是正常现象。单次比对约0.3–0.5秒(RTX 4090),100张图共4950次,理论耗时约25–40分钟。提速方法只有两个:

  • 硬件:换A100或H100显卡,速度提升2–3倍;
  • 策略:先用轻量模型(如MobileFaceNet)做初筛,只对相似度>0.2的组合再用CurricularFace精算——但这需要额外开发,超出本教程范围。

5.3 “能支持子文件夹递归扫描吗?”

能。只需把脚本里get_image_files()函数改成:

def get_image_files(folder_path): supported_exts = {'.jpg', '.jpeg', '.png'} folder = Path(folder_path) return [str(f) for f in folder.rglob("*") if f.is_file() and f.suffix.lower() in supported_exts]

这样/root/my_faces/person1/,/root/my_faces/person2/下的所有图都会被纳入。

5.4 “结果能导出成Excel带颜色标记吗?”

当然可以。安装openpyxl后,在脚本末尾加几行:

pip install openpyxl

然后在main()函数最后插入:

# 导出带格式的Excel(可选) try: import pandas as pd df = pd.read_csv(OUTPUT_CSV) df['Highlight'] = df['SamePerson'].map({'Yes': 'green', 'No': 'red', 'ParseError': 'yellow'}) with pd.ExcelWriter('batch_result.xlsx', engine='openpyxl') as writer: df.to_excel(writer, index=False) # 此处可加条件格式,略 print("[INFO] 已额外生成 batch_result.xlsx(需用Excel打开)") except ImportError: pass

6. 总结:你刚刚掌握了什么

回看一下,你已经完成了:

  • 在预装环境中快速验证了单张人脸比对的可靠性;
  • 编写并运行了一个健壮的批量比对脚本,支持任意数量图片的两两组合;
  • 获得了结构化结果(CSV),可直接导入Excel分析、筛选、可视化;
  • 掌握了3个实用技巧:快速筛选高分对、导出对比图组、动态调阈值;
  • 避开了5个高频坑点,知道问题出在哪、怎么解。

这不再是“调通一个demo”,而是真正能放进工作流里的生产力工具。下次HR给你发来200份入职照片,你不用再手动点鼠标,只要改一行路径、敲一条命令,喝杯咖啡回来,结果就躺在CSV里了。

技术的价值,从来不在多炫酷,而在多省事。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/8 2:55:38

亲测YOLOv9官方镜像,AI目标检测快速落地实战

亲测YOLOv9官方镜像&#xff0c;AI目标检测快速落地实战 最近在多个工业质检和智能安防项目中频繁遇到一个共性问题&#xff1a;模型迭代周期长、环境配置反复踩坑、训练结果难以复现。当团队第三次因为CUDA版本冲突导致训练中断时&#xff0c;我决定彻底换一种思路——不再从…

作者头像 李华
网站建设 2026/2/12 6:30:07

Qwen3-32B在Clawdbot中如何提升用户体验?流式响应+Web UI定制教程

Qwen3-32B在Clawdbot中如何提升用户体验&#xff1f;流式响应Web UI定制教程 1. 为什么Qwen3-32B能让Clawdbot更懂你&#xff1f; 你有没有遇到过这样的情况&#xff1a;在客服对话框里输入问题&#xff0c;等了五六秒才看到第一行字&#xff0c;接着一行一行慢慢蹦出来&…

作者头像 李华
网站建设 2026/2/11 12:20:42

【mcuclub】DHT11温湿度传感器实战:从原理到代码实现

1. DHT11温湿度传感器初探 第一次拿到DHT11这个小家伙时&#xff0c;我差点被它朴素的外表给骗了。这个比指甲盖大不了多少的传感器&#xff0c;居然能同时测量温度和湿度&#xff01;它采用单总线通信协议&#xff0c;只需要一个GPIO引脚就能完成数据交互&#xff0c;特别适合…

作者头像 李华
网站建设 2026/2/11 21:13:58

Qwen3-VL-4B Pro部署教程:Kubernetes集群中Qwen3-VL-4B Pro服务编排

Qwen3-VL-4B Pro部署教程&#xff1a;Kubernetes集群中Qwen3-VL-4B Pro服务编排 1. 为什么需要在Kubernetes中部署Qwen3-VL-4B Pro 你可能已经试过本地运行Qwen3-VL-4B Pro&#xff0c;点开Streamlit界面、上传一张照片、输入“描述这张图”&#xff0c;几秒后就看到一段流畅…

作者头像 李华
网站建设 2026/2/9 5:41:33

零基础3分钟掌握弹幕盒子:轻松制作专业级自定义弹幕

零基础3分钟掌握弹幕盒子&#xff1a;轻松制作专业级自定义弹幕 【免费下载链接】danmubox.github.io 弹幕盒子 项目地址: https://gitcode.com/gh_mirrors/da/danmubox.github.io 你是否曾想为视频添加弹幕却苦于复杂的软件操作&#xff1f;是否因格式不兼容而放弃创意…

作者头像 李华