Back to skills
extension
Category: Data & AnalyticsNo API key required

face-photo-search

This skill should be used when the user provides one folder of reference photos of a specific person (a child, spouse, friend, or themselves) and wants to pull that person's other photos out of a large camera-roll, phone-backup, or NAS library. It uses face recognition (InsightFace/ArcFace embeddings + cosine similarity) to scan thousands of images on CPU, is crash-safe and resumable, never modifies the originals, and copies matches into a new folder with a scored report. Trigger phrases: 人脸聚类, 把我儿子的照片挑出来, 找出这个人的所有照片, find all photos of this person, group photos by person, sort photos by face.

personAuthor: user_f4fbb75chubcommunity

face-photo-search

从上万张照片里,把某一个人的所有照片挑出来。

给一个人的几张参考照片,它会扫描你的整个图库(手机备份、相机导出、NAS 相册), 用人脸识别找出这个人出现过的每一张,复制到新文件夹并附一份带相似度分数的报告。

原图一张不动 —— 只读扫描 + 复制,不移动、不重命名、不删除。

这是一个 WorkBuddy / Claude Code 格式的 Agent Skill, 装好之后直接对 AI 说「帮我把我妈的照片从 D:\相册 里挑出来,参考照片在 D:\参考」即可, 不需要记命令行参数。

实测

在一个 6321 张、16.2 GB 的手机相册备份上跑通:

| 指标 | 结果 | |---|---| | 图库规模 | 6321 张 / 16.2 GB | | 命中 | 268 张(相似度 ≥ 0.35,多数落在 0.75–0.86) | | 疑似 | 27 张(0.25–0.35,不复制,列进报告供人工核对) | | 无人脸自动跳过 | 4736 张 | | 读取失败 | 0 | | 稳态速度 | 约 0.6 秒/张(24 核 CPU,无需 GPU) |

过程中进程被中断三次,靠断点续跑无损恢复,结果一条没丢。

原理

InsightFace 的 buffalo_l 模型(ArcFace)把每张脸编码成 512 维向量, 参考照片取平均得到一个"这个人长什么样"的基准向量, 再和图库里每张脸算余弦相似度,超过阈值即判定命中。

参考照片文件夹 ──┐
待搜索图库    ──┼──► ArcFace 编码 ──► 余弦相似度 ──► 命中副本 + 评分报告
阈值 / 输出位置 ─┘

安装

git clone https://github.com/liyuechao2018/face-photo-search.git \
    ~/.workbuddy/skills/face-photo-search

Claude Code 用户放到 ~/.claude/skills/ 下同理。

依赖装在隔离 venv 里,安装顺序有讲究,照抄 SKILL.md 的「前置:环境搭建」一节。 简要说:

VENV="$HOME/.workbuddy/binaries/python/envs/default"
[ -d "$VENV" ] || python -m venv "$VENV"
PYBIN="$VENV/Scripts/python.exe"; [ -x "$PYBIN" ] || PYBIN="$VENV/bin/python"
M="https://pypi.tuna.tsinghua.edu.cn/simple"; H="pypi.tuna.tsinghua.edu.cn"

"$PYBIN" -m pip install -i $M --trusted-host $H numpy onnxruntime opencv-python-headless pillow tqdm
"$PYBIN" -m pip install -i $M --trusted-host $H --no-deps insightface
"$PYBIN" -m pip install -i $M --trusted-host $H onnx requests prettytable scikit-image scipy

首次运行会自动下载 buffalo_l 模型(约 270 MB)。

用法

对 AI 说人话就行。想手动跑也可以:

S="$HOME/.workbuddy/skills/face-photo-search/scripts"
W="./facework-某人"     # 每个人用一个独立工作目录

# 1. 建参考向量,并对图库抽样冒烟测试(先看区分度,别急着跑全量)
"$PYBIN" "$S/build_ref.py" --ref "<参考照片文件夹>" --lib "<图库>" --work "$W"

# 2. 全量扫描 + 复制 + 出报告(可随时中断,重跑自动续)
"$PYBIN" "$S/find_person.py" --ref "<参考照片文件夹>" --lib "<图库>" \
    --out "<结果文件夹>" --work "$W" --thr 0.35 --workers 8

# 3. 觉得阈值不合适?不用重扫,分数已缓存
"$PYBIN" "$S/find_person.py" ... --work "$W" --thr 0.45 --rebuild-only

阈值怎么定

| 阈值 | 效果 | |---|---| | 0.30 | 宁滥勿缺,适合找侧脸/远景/儿童跨年龄 | | 0.35 | 默认,实测漏检少、误判低 | | 0.45 | 严格,混入别人时调到这里 |

小孩照片跨年龄变化大,不建议超过 0.5。

设计上的几个决定

边扫边落盘。 每处理完一张就把分数追加写入 scores.tsv,而不是攒在内存里最后一次性写。 第一版就是攒内存的,跑到 1639 张时进程被回收,前面的判定结果全丢。 上万张的任务必然会被中断,crash-safe 不是优化项而是必需项。

分数全量缓存,输出可重建。 scores.tsv 存的是每张照片的原始相似度,不是"命中与否"。 所以改阈值只需重建输出(秒级),不用重扫几小时。

工作目录按「人 × 图库」隔离。 refvec.npyscores.tsv 都绑定特定的人和图库。 换人却复用同一个 --work,会读到上一个人的向量、且缓存显示"全部已扫描", 于是静默产出上一个人的结果——不报错的错才最危险。 脚本用 owner.json 记录归属,参数对不上直接终止。

用 Pillow 而不是 cv2 读图。 cv2.imread 读不了华为手机的 MPO 双摄格式(返回 None), 部分普通 JPEG 在 headless 构建下也读不出。Pillow 全都能读,转 BGR 数组再喂给模型。

多进程,但工人数别贪多。 8 工人 × 3 线程和 12 工人 × 2 线程实测几乎无差异, 瓶颈在磁盘 IO 不在 CPU。另外小样本测速会骗人——40 张测出 7.2 秒/张, 其实大头是 8 个工人各自加载模型的启动开销,稳态是 0.6 秒/张。

隐私

人脸特征属于生物识别信息。这个工具完全离线运行,模型在本地推理, 参考向量 .npy 和分数 .tsv 只落在你指定的工作目录里,不上传任何地方。

请只用于处理你自己的照片。

License

MIT