首页
/ Faceswap Manual Editor 手册:从 CLI 参数到五大编辑器与对齐文件全流程解析

Faceswap Manual Editor 手册:从 CLI 参数到五大编辑器与对齐文件全流程解析

2026-09-06 13:48:41作者:蔡怀权

本文基于 docs/full/tools/manual.rst 这份 tools.manual 包的 API 文档,结合 tools/manual/ 下的约 8000 行源码,完整解析 Faceswap 中 Manual(手动对齐)工具的架构与用法:如何从命令行启动、三个对齐器与四种归一化模式如何协同工作、五大编辑器与五种过滤模式各自解决什么问题、以及全部键盘快捷键与对齐文件的保存/回退/缩略图缓存机制。读完之后,你可以独立完成一次视频源帧的对齐文件精修,并能读懂该工具每一处行为背后的源码依据。

Manual 工具的定位:对齐文件的"可视化精修器"

tools/manual/cli.py 中对该工具的描述是:"A tool to perform various actions on frames, faces and alignments files using visual tools"。也就是说,Manual 工具是 Faceswap Tools 套件中唯一的 GUI 工具,它围绕 alignments(对齐)文件 工作:读取视频或帧文件夹,把其中每张人脸的检测框、68 点 landmarks、mask 等数据以 DetectedFace 对象形式加载进内存,让用户在图形界面上逐帧修正,再把结果写回 .json 对齐文件。

该工具只接受"源视频/源帧"作为输入,不接受 extract 步骤输出的"已抽取人脸文件夹"。tools/manual/manual.py 中的 _validate_non_faces 会在启动时随机抽一张 PNG 检查其 iTXt 元数据中是否带有 alignments 头,一旦发现输入是抽取后的人脸文件夹就直接报错退出:

The input folder 'xxx' contains extracted faces.
The Manual Tool works with source frames or a video file, not extracted faces.

这一校验决定了典型工作流:extract 生成对齐文件 → 用 Manual 精修对齐文件 → 再回到 extract 使用修正后的结果。

命令行启动方式与全部参数

Manual 工具的标准入口是 python tools.py manual(见 manual.py 类文档),CLI 参数定义在 cli.pyManualArgs.get_argument_list() 中,共有四个参数:

参数 选项 类型 必填 说明
对齐文件 -a / --alignments FileFullPaths(filetypes: alignments) 指向输入对应的 alignments 文件路径(当它不在默认位置时)
帧源 -f / --frames DirOrFileFullPaths(filetypes: video) 源视频文件,或包含源帧的目录(人脸最初即从该视频/帧抽取)
强制重建缩略图 -t / --thumb-regen store_true 强制重新生成缓存在对齐文件中的低分辨率 jpg 缩略图
单进程建缩略图 -s / --single-process store_true 禁用并行线程从视频抽缩略图,改用更慢但更稳定的单线程(用于某些视频会导致缓存过程挂起时)

最小可运行示例:

python tools.py manual -f /path/to/video.mp4

-f 既可以是视频文件也可以是图片文件夹;输入类型由 globals.pyTkGlobals._check_input 判定——目录按帧文件夹处理,扩展名在 lib.videoVIDEO_EXTENSIONS 中的按视频处理,否则直接 sys.exit(1)

整体架构:API 文档映射到的模块树

docs/full/tools/manual.rst 用 automodapi 指令按包生成了 API 参考,它列出的五个模块与源码目录一一对应:

API 文档中的模块 源码文件 职责
manual 包主体 manual.py 主入口 Manual 类(tkinter 应用)、右侧选项面板 _Options、对齐管线 Aligner、帧加载器 FrameLoader
manual.cli cli.py 命令行参数定义
manual.detected_faces detected_faces.py DetectedFaces 及磁盘 IO、面更新、过滤三大子系统
manual.globals globals.py 全局 tkinter 变量 TkGlobals 与当前帧状态 CurrentFrame
manual.thumbnails thumbnails.py 对齐文件缩略图缓存生成器 ThumbsCreator
manual.face_viewer.frame face_viewer/frame.py 下方"人脸视图"画布 FacesFrame
manual.face_viewer.interact face_viewer/interact.py 人脸视图的鼠标悬停与活动帧交互
manual.face_viewer.viewport face_viewer/viewport.py 人脸视图可视区域/视口处理
manual.frame_viewer.control frame_viewer/control.py 上方"帧视图"的导航 Navigation 与背景图
manual.frame_viewer.frame frame_viewer/frame.py 上方主显示区 DisplayFrame 与动作切换
manual.frame_viewer.editor.* editor/bounding_box.py / extract_box.py / landmarks.py / mask.py 五个编辑器的具体实现

从源码结构看,整个 GUI 是一个垂直 ttk.PanedWindow:上半部分是帧视图(DisplayFrame),下半部分是人视图(FacesFrame),右侧再挂一个随编辑器切换的控制面板(manual.py_create_containers)。窗口初始几何为 940×600 并尝试全屏(manual.py),标题为 "Faceswap.py - Visual Alignments"。

启动流程:两条后台线程 + 对齐器管线

Manual.__init__manual.py)的初始化顺序揭示了该工具的并发设计:

  1. 输入校验_validate_non_faces 排除人脸文件夹输入;
  2. tkinter 初始化:解绑 TButton/TCheckbutton/TRadiobutton<Key-space>(防止空格触发按钮而不是播放控制),设置窗口几何与标题;
  3. 并行启动两条后台线程
    • Aligner:加载三个对齐插件并初始化推理管线(通常最耗时,因此最先启动);
    • FrameLoader:用 lib.image.SingleFrameLoader 打开视频或帧文件夹。若输入是文件夹,会把"不在对齐文件中的帧"加入 skip 列表(manual.py),只遍历对齐文件覆盖到的帧;
  4. 加载人脸DetectedFaces.load_faces() 将 alignments JSON 反序列化为 DetectedFace 对象列表(detected_faces.py);
  5. 主线程等待_wait_for_threads 每 1 秒轮询两条线程的 is_initialized,全部就绪后把 DetectedFaces 挂到 Aligner 上,并在视频元数据缺失时把 pts_time / keyframes 写回对齐文件,避免下次再全量扫描视频(manual.py);
  6. 生成缩略图ThumbsCreator 检查对齐文件是否已有缩略图缓存,没有(或传了 -t)则后台多线程重建(manual.py)。

三个对齐器与归一化

Alignermanual.py)在后台线程中依次初始化三个插件:

for plugin in ("cv2-dnn", "FAN", "HRNet"):
    self._aligners[plugin] = Align(plugin, normalization="hist")()
  • cv2-dnn:OpenCV DNN 的人脸检测(快,用于快速加框);
  • FAN / HRNet:68 点 landmark 对齐模型,用户可在 GUI 中切换当前使用哪一个。

Aligner.get_landmarks 的调用链是:取 TkGlobals.current_frame 的当前帧图像 → 用指定对齐器对该帧上某个人脸的检测框执行推理(passthrough=True)→ 返回 68 点 landmarks_xymanual.py)。这正是"用户手动画框 → 自动算 landmarks"功能背后的实现。

归一化方法可在 GUI 调整,set_normalization_method 会同步更新所有三个对齐器的 handler(manual.py)。editor/bounding_box.py 帮助文本列出了全部四种取值:

  • hist(直方图均衡,默认)
  • mean(均值归一化)
  • clahe(自适应直方图均衡)
  • none(不做归一化)

对低质量、光照不均的视频,切换归一化方式能明显改善自动 landmarks 的稳定性。

上方帧视图:五个动作(Editor)

DisplayFrameframe_viewer/frame.py)左上是主画面。动作列表硬编码为五个(frame_viewer/frame.py):

self._actions = ("View", "BoundingBox", "ExtractBox", "Landmarks", "Mask")

它们分别映射到 F1–F5 快捷键,切换后右侧面板(_Options)会随之换成对应编辑器的控制项(manual.py)。编辑器实现都继承自 editor/_base.pyEditor 基类,并在 editor/init.py 统一导出,其中还包含 Mesh(landmarks 网格查看器)与 View

from ._base import View
from .bounding_box import BoundingBox
from .extract_box import ExtractBox
from .landmarks import Landmarks, Mesh
from .mask import Mask
  • View / Mesh:只读查看帧;Mesh 会把 68 点 landmarks 以连线网格叠加显示,便于肉眼检查对齐质量(数据来自 lib.alignLANDMARK_PARTS,见 editor/landmarks.py);
  • BoundingBoxeditor/bounding_box.py):鼠标拖拽修改/添加人脸检测框;框选完成后由 Aligner 自动重算该框的 landmarks。面板中同时暴露归一化下拉框(四种模式见上节);
  • ExtractBoxeditor/extract_box.py):绘制自定义框,用于"抽脸"预览——即模拟 extract 步骤对该框的裁剪/对齐效果,确认抽取区域是否符合预期;
  • Landmarkseditor/landmarks.py):拖动 68 个关键点中的某一个来精修 landmark,右侧面板提供按 LandmarkType 分组的点选择;
  • Maskeditor/mask.py):画笔式编辑人脸 mask,支持 B(Brush)、D(Drag)、E(Erase)操作与 Z(Zoom)缩放,[ / ] 调整画笔粗细——这些是源码注释中明确保留给 editor 模块的按键(manual.py)。

导航条(播放/进度条)由 frame_viewer/control.pyNavigation 类管理:进度条的 to 值随过滤模式动态变化(nav_scale_callback),播放状态用独立的 tk.BooleanVar 跟踪。

下方人视图:缩略图画布与交互

FacesFrameface_viewer/frame.py,约 800 行)是下方的网格画布,把当前过滤条件下每一帧的每个人脸缩略图排成网格:

  • 缩略图不是每次运行时现场解码视频,而是缓存在对齐文件里的低分辨率 jpg-t 强制重建的对象)。ThumbsCreator 的线程策略见 thumbnails.py:CPU 核数大于 2 时取 cpu_count - 2,并向上取到至少 32 线程;视频输入加 --single-process 时强制单线程——这正是 CLI 中 -s 选项存在的原因;
  • 缩略图尺寸由右侧面板的 "Face Size" 下拉控制,取值为 Tiny / Small / Medium / Large / Extra Large,默认 Mediummanual.py);
  • face_viewer/viewport.py 负责把画布可视区域(视口)内的帧正确渲染出来,避免全量重绘;
  • face_viewer/interact.py 处理鼠标悬停预览与"活动帧"——点击网格中的某个脸即可在上方帧视图定位到对应帧。

帧过滤模式:快速定位"问题帧"

DetectedFaces 内建的 Filter 子系统(detected_faces.py)提供五种导航过滤模式,按 F 键循环切换:

过滤模式 判据(源码)
All Frames 不过滤
No Faces 该帧没有任何检测到的人脸
Has Face(s) len(frame_faces) > 0
Multiple Faces len(frame_faces) > 1
Misaligned Faces 任一 face.aligned.average_distance > 阈值

其中 Misaligned Faces 最实用:它基于对齐后的平均残差距离筛出"对齐得不像"的帧。距离阈值由全局变量 filter_distance 控制,默认 10globals.pytk.IntVar(value=10)),在过滤模式下会显示一个专门的阈值滑块(Navigation.pack_threshold_slider,见 frame_viewer/control.py)。过滤条件改变后,进度条总帧数、人视图网格会随之刷新。

键盘快捷键全表

Manual._handle_key_pressmanual.py)集中定义了全局快捷键,其中数字键支持小键盘(KP_ 前缀自动剥离):

功能
z / x 上一帧 / 下一帧
space 播放/暂停
home / end 跳到第一帧 / 最后一帧
up / down 人视图画布上/下滚动
prior / next(PageUp/PageDown) 人视图画布翻页
f 循环切换过滤模式
F1F5 切换 View / BoundingBox / ExtractBox / Landmarks / Mask
F9 / F10 切换人视图上的标注显示
c / v 把当前帧的人脸复制(copy)到上一帧 / 下一帧
ctrl+s 保存对齐文件
r 把当前帧回退到已保存版本
Delete[ / ]B/D/E/M 保留给编辑器:删除人脸 / 调画笔粗细 / 画笔操作

源码特别注明 Windows 下 Alt 修饰键不可靠,因此所有组合键只用 shift / ctrlmanual.py)。

对齐文件的数据流:加载、更新、保存、回退

DetectedFacesdetected_faces.py)是数据中枢,内部分三个子系统:

  • _DiskIOload_faces().json 反序列化出每帧的 DetectedFace 列表;save()(Ctrl+S 触发)把内存中所有编辑写回文件;revert_to_saved(frame_index)r 键)把某帧恢复到上次保存的状态;extract() 支持从工具内直接调用抽取流程;
  • FaceUpdate:GUI 中任何一次编辑(移动框、拖动 landmark、涂 mask、Delete 删脸、c/v 跨帧复制)都会更新对应 DetectedFace,并把帧索引记入 _updated_frame_indicesis_frame_updated 可查询);
  • Filter:前文所述的五种过滤模式,按 TkGlobals 中当前 filter_mode 字符串分派。

三个 tkinter 布尔变量驱动界面状态(detected_faces.py):tk_unsaved(自上次保存后有修改)、tk_edited(需要触发 GUI 重绘)、tk_face_count_changed(人脸数量变化,需要重画网格)。标题栏/状态区的"未保存"提示即由 tk_unsaved 驱动。

此外 DetectedFaces.available_masks 会统计对齐文件中各 mask 类型覆盖的人脸数,用于 mask 编辑器面板中列出可选 mask;save_video_meta_data 则把视频的 pts_time 与关键帧列表持久化进对齐文件(detected_faces.py),保证二次打开同一视频时无需重新扫描。

小结

docs/full/tools/manual.rst 给出的 API 目录其实就是 Manual 工具的全部骨架:manual.py 负责入口、容器与 Aligner/FrameLoader 两条后台线程;detected_faces.py 负责对齐文件 IO、编辑与过滤;globals.py 承载跨组件的 tkinter 变量;thumbnails.py 负责缩略图缓存;face_viewer/ 三件套负责下方人脸网格;frame_viewer/controlframeeditor/ 四个编辑器模块负责上方帧画面与五种编辑动作。掌握 python tools.py manual -f <video> 的四个参数、F1–F5 编辑器切换、f 循环过滤(尤其 Misaligned Faces + 距离阈值)以及 Ctrl+S / r 的保存与回退,就足以完成一次完整的对齐文件精修;而当自动 landmarks 不理想时,记得先检查 BoundingBox 面板里的归一化选项,它直接决定 Aligner 推理输入的质量。

登录后查看全文
热门项目推荐
相关项目推荐