返回首页

Rust 上的面部交换:无需 Python 即可达到 60 FPS | 技术剖析

本文描述了 Rust 中实时面部交换应用的实现。它详细介绍了无锁多线程架构、内存优化以及通过 ONNX Runtime 集成神经网络模型。提供了实现 60 帧每秒的代码示例和技术解决方案。

Rust 上的面部交换:无需 Python 和 CUDA 即可达到 60 帧每秒
Advertisement 728x90

# Rust 实现实时人脸替换:无需 Python 即可达 60 帧/秒,并采用无锁架构

现有的实时人脸替换解决方案往往依赖 Python 及其生态系统,导致依赖过多和性能问题。本文详细剖析了一个纯 Rust 应用实现,其无需使用 Python 即可达到 60 帧/秒。主要组件:用于推理的 ONNX Runtime、无锁线程以及完整的内存优化。

帧处理管道

每一帧严格依次通过四个神经网络模型。RetinaFace 检测人脸并提取五个关键点。ArcFace 生成源人脸的 512 维嵌入。InSwapper 接收目标人脸区域和源嵌入,返回替换后的人脸。GFPGAN 可选地提升结果质量。所有模型均通过 ONNX Runtime 运行,无需自定义 CUDA 内核——仅输入和输出张量。

架构特性:无中间分配。像素缓冲区在应用启动时一次性分配。RGBA 到 RGB 转换、张量填充以及仿射变换均不进行额外内存分配。每帧唯一的分配是为最终快照创建 Arc,这是使用 ArcSwap 时不可避免的。

Google AdInline article slot

处理循环针对指令级并行进行了优化。例如,颜色空间转换每次迭代处理 4 个像素:

for i in 0..chunks {
    let si = i * 16;
    let di = i * 12;
    rgb[di] = rgba[si];
    rgb[di + 1] = rgba[si + 1];
    rgb[di + 2] = rgba[si + 2];
    rgb[di + 3] = rgba[si + 4];
    rgb[di + 4] = rgba[si + 5];
    rgb[di + 5] = rgba[si + 6];
    // ... also 2 pikselya
}

无锁多线程架构

系统使用三个线程,在热路径上零锁。捕获线程通过 nokhwa 接收帧,并通过 ArcSwap 发布。管道线程处理帧,并通过第二个 ArcSwap 传递结果。UI 线程通过 egui 渲染当前缓冲区。关键优化:将结构对齐到缓存行(64 字节)以防止伪共享:

const CL: usize = 64;
#[repr(C, align(64))]
struct ProducerCell {
    frame: ArcSwap<FrameSnapshot>,
    generation: AtomicU64,
    _pad: [u8; CL - 16],
}
const _: () = {
    assert!(std::mem::size_of::<ProducerCell>() == CL);
};

编译时断言保证尺寸符合。原子生成计数器取代互斥锁,消除同步开销。避免 async 和 channels 简化逻辑并减少开销。

Google AdInline article slot

减少代码重复的宏

四个神经网络需要相同的操作:RGBA 到 BGR 平面格式转换和归一化。与其复制代码,不如使用宏。fill_tensor_planar! 宏由归一化器参数化:

// For ArcFace: (v - 127.5) / 127.5
fill_tensor_planar!(
    self.tensor,
    self.aligned,
    PLANE,
    FS,
    FS,
    FS * 3,
    bgr_norm_arcface
);

// For InSwapper: v / 255.0
fill_tensor_planar!(
    self.tensor,
    self.aligned,
    PLANE,
    SS,
    SS,
    SS * 3,
    bgr_inv255
);

类似地,build_session! 消除了 ONNX Runtime 初始化期间的三重嵌套 ort_err! 调用:

macro_rules! build_session {
    ($path:expr, $threads:expr) => {{
        let builder = ort_err!(Session::builder())?;
        let mut builder = ort_err!(builder.with_intra_threads($threads))?;
        ort_err!(builder.commit_from_file($path))?
    }};
}

几何变换和 UI

人脸对齐使用自定义相似变换实现。从 RetinaFace 获取的五个关键点通过求解 4x4 系统(使用高斯方法和部分主元)匹配到 ArcFace 模板。应用逆变换进行双线性 warping 和 alpha 混合的粘贴回原位:

Google AdInline article slot
let edge_dist = ax.min(ay).min(fs - ax).min(fs - ay) - margin;
let alpha = (edge_dist * inv_blend).clamp(0.0, 1.0);

这确保边缘平滑过渡无伪影。UI 基于 egui 的即时模式构建,非常适合实时视频。自定义无边框主题,带有 macOS 风格的交通灯和透明背景,允许无保留状态拖动窗口。每帧渲染无延迟,保持稳定的 60 帧/秒。

关键要点

  • Rust 的所有权模型 即使在复杂多线程架构中,也消除了数据竞争和使用后释放。
  • 通过 ort 的 ONNX Runtime 证明了生产就绪:稳定的模型加载和推理,无 CUDA 依赖。
  • 实时 egui——即时模式渲染无保留状态,最小化视频流延迟。
  • 热路径零分配 通过预分配缓冲区和优化循环实现。
  • 通过 ArcSwap 的无锁 结合缓存对齐,消除了线程间同步开销。

该解决方案证明 Rust 在高性能计算机视觉任务中非常有效。单个二进制文件无需 Python 依赖,即开即用——只需从 GitHub 下载发布版即可。为进一步性能扩展,切换到多会话 ONNX Runtime 看起来很有前景,可实现并行模型执行而非顺序处理。

— Editorial Team

Advertisement 728x90

继续阅读