onnxruntime部署LivePortrait人像动画:C++与Python双栈实战 简介本资源面向希望在人像动画生成方向落地的开发者提供使用onnxruntime部署LivePortrait的完整程序同时给出C与Python两套实现路径适合具备一定深度学习推理基础、想在本地或工程环境中集成人像驱动能力的读者参考。压缩包共14个文件约459KB包含4个cpp与3个h源文件构成C推理主流程2个py脚本负责Python侧调用与裁剪处理另有txt、md说明文档及mp4、jpg、png等示例素材便于对照理解输入输出。目前已有204人学习下载。资源涵盖人脸检测、裁剪对齐、动画生成等模块的代码组织读者可据此掌握onnxruntime加载模型、前后处理与跨语言调用的排错思路并借助示例素材快速验证效果适合作为人像动画工程化部署的起步模板。1. 拿到 liveportrait-onnxrun-main 之后这套 C/Python 双栈人像动画程序到底能跑出什么上周有个做短视频工具的朋友甩给我一个压缩包名字很长——使用onnxruntime部署LivePortrait人像动画生成C和Python程序.zip。他问得很直接这东西能不能脱离 PyTorch 那套重依赖在普通 Windows 机器上把一张静态人像照片驱动成一段说话视频我解压跑了一遍答案是能而且它把推理后端换成了 onnxruntimePython 和 C 两条路都给了。LivePortrait 本身是快手开源的肖像动画框架核心思路是从源图像里提取外观特征和关键点运动信息再结合驱动视频的表情、姿态、视线变化逐帧渲染出目标人像的动画。原版依赖 PyTorch 和一堆 CUDA 算子部署门槛不低。这个包做的事是把模型转成 ONNX 格式后用 onnxruntime 加载推理同时提供了 Python 脚本和一套完整的 C 工程含 CMakeLists.txt、liveportrait.h/cpp、faceanalysis.h/cpp、utils_crop.h/cpp、main.cpp等于把「快速验证」和「集成进现有 C 项目」两条路都铺好了。适合谁用如果你手头有 C 的桌面端或服务端工程想把人像动画能力嵌进去又不想拖一个 PyTorch 运行时这套东西值得拆开看。如果你只是想先跑通效果Python 那条线几分钟就能出第一段视频。下面按我实际操作的顺序把两条路都走一遍。2. 环境准备与模型文件落位onnxruntime 动态库、Python 依赖和目录结构2.1 先看清包里的目录骨架解压后根目录是liveportrait-onnxrun-main里面大致分三块Python 侧有main.py、utils_crop.py以及0.jpg、mask_template.png、d0.mp4这几个示例素材C 侧在cpp目录下包含CMakeLists.txt、liveportrait.h、liveportrait.cpp、faceanalysis.h、faceanalysis.cpp、utils_crop.h、utils_crop.cpp、main.cpp根目录还有一份README.md。模型文件.onnx通常需要单独下载后放到指定目录包里不会塞几百兆的权重。常见做法是在根目录建一个models或onnx文件夹把外观提取、运动提取、生成器、关键点检测这几类 ONNX 文件按 README 里的命名放进去。这一步别偷懒路径和文件名对不上后面报错会很难定位。2.2 Python 侧依赖安装Python 这条线依赖比较轻核心就是 onnxruntime、opencv、numpy、pillow 这几个。我一般用虚拟环境隔离避免和系统里的 PyTorch 打架# 建虚拟环境Python 3.8 及以上都行 python -m venv venv_lp # Windows 激活 venv_lp\Scripts\activate # Linux/macOS 激活 source venv_lp/bin/activate # 装核心依赖CPU 版 onnxruntime pip install onnxruntime opencv-python numpy pillow # 如果有 NVIDIA 显卡且想用 GPU 推理换成 GPU 版 # pip install onnxruntime-gpu这里有个参数选择onnxruntime和onnxruntime-gpu只能装一个装混了会出现 provider 找不到的情况。CPU 版默认用CPUExecutionProviderGPU 版需要 CUDA 和 cuDNN 版本匹配具体版本对照去 onnxruntime 官方文档查别凭感觉装。2.3 C 侧依赖与 onnxruntime 动态库C 这条线要准备三样东西onnxruntime 的 C 库头文件 动态库、OpenCV、CMake。onnxruntime 官方提供预编译包下载对应平台的压缩包后把include和lib目录路径记下来等会儿在 CMakeLists.txt 里指过去。Windows 上还需要注意运行库Microsoft Visual C 2015-2022 Redistributable (x64)建议先装上否则 onnxruntime 的动态库加载可能直接失败报找不到vcruntime140_1.dll之类的错。这个坑我踩过不止一次装完重启一下最稳。提示onnxruntime 动态库的版本要和头文件版本一致混用不同版本的 dll 和 lib 会出现符号找不到的链接错误。3. Python 跑通第一段动画main.py 的参数、裁剪脚本与推理链路3.1 先跑 utils_crop.py 做素材预处理LivePortrait 对输入图像有裁剪和对齐要求直接丢一张原图进去人脸区域比例不对出来的动画会歪或者抖动。包里给了utils_crop.py作用是把源图像裁剪到合适的人脸区域并生成对齐后的图。# 对示例图 0.jpg 做裁剪输出对齐后的人脸图 python utils_crop.py 0.jpg这个脚本内部一般会调用人脸检测拿到关键点后做仿射变换把脸摆正并缩放到模型期望的输入尺寸。执行完会生成一张裁剪后的图记下输出文件名下一步要作为参数传进去。如果脚本报检测不到人脸先检查图片是不是太暗、人脸太小或者侧脸角度过大——检测模型对这三类情况比较敏感。3.2 main.py 的核心参数逐个说清跑主推理脚本时参数顺序和含义必须搞对否则要么读错文件要么输出空视频。典型调用长这样# 源图像 驱动视频 输出路径 python main.py --source 0_crop.jpg --driving d0.mp4 --output result.mp4如果包里的 main.py 用的是位置参数而非命名参数就按 README 里的顺序传。几个关键点source裁剪对齐后的源人像图不是原图。传原图可能也能跑但效果打折。driving驱动视频示例给了d0.mp4。驱动视频里的人脸要清晰帧率稳定否则运动信号提取会抖。output输出视频路径编码格式一般跟随 OpenCV 的 VideoWriter 设置常见是 mp4v 或 avc1。推理链路大致是源图过外观提取网络拿到特征和关键点 → 驱动视频逐帧过运动提取网络拿到表情和姿态 → 生成器把两者融合渲染 → 写回视频帧。整个过程在 onnxruntime 里就是一次次session.run()没有 PyTorch 的动态图开销。3.3 输出视频的编码与帧率对齐跑完第一遍最容易翻车的不是模型是视频编码。OpenCV 写视频时如果编码器选得不对输出文件要么打不开要么只有几帧。我一般会显式指定# 在 main.py 里找到 VideoWriter 那段确认编码和帧率 fourcc cv2.VideoWriter_fourcc(*mp4v) out cv2.VideoWriter(output_path, fourcc, fps, (w, h))fps要和驱动视频一致宽高要和生成帧一致。如果输出视频播放速度不对八成是 fps 传错了。另外mask_template.png是配合遮罩用的某些后处理步骤会拿它做区域融合别删。4. C 工程编译与集成CMakeLists 配置、faceanalysis 与 liveportrait 模块拆解4.1 CMakeLists.txt 里必须改的三处路径C 工程能不能编过九成看 CMakeLists.txt 里的路径对不对。打开后重点找这三类# 1. onnxruntime 头文件和库路径 set(ONNXRUNTIME_ROOT 你的路径/onnxruntime) include_directories(${ONNXRUNTIME_ROOT}/include) link_directories(${ONNXRUNTIME_ROOT}/lib) # 2. OpenCV find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) # 3. 链接目标 target_link_libraries(your_target ${OpenCV_LIBS} onnxruntime)Windows 下链接的库名通常是onnxruntime.libLinux 下是libonnxruntime.so。如果编译时报LNK2019未解析外部符号先确认库路径和库名没写错再确认 32/64 位一致。4.2 faceanalysis 模块在做什么faceanalysis.h/cpp负责人脸检测和关键点提取是整条链路的前置。它一般封装了一个轻量检测模型比如 SCRFD 或类似结构的 onnxruntime 推理输入一张图输出人脸框和五点/多点关键点。这些关键点后面要用来做对齐和运动参考。看这个模块时重点关注输入输出的张量形状和归一化方式。检测模型的输入通常是1x3xHxW像素值归一化到 0~1 或减均值除方差具体看模型导出时的设定。归一化搞错检测框会飘。4.3 liveportrait 模块的推理封装liveportrait.h/cpp是核心把外观提取、运动提取、生成器几个 onnxruntime session 串起来。典型结构是类里持有多个Ort::Session对象提供init()加载模型、run()执行推理的接口。// 伪代码示意实际以包内实现为准 class LivePortrait { public: bool init(const std::string model_dir); cv::Mat animate(const cv::Mat source, const cv::Mat driving_frame); private: Ort::Session appearance_session_; Ort::Session motion_session_; Ort::Session generator_session_; };main.cpp则是把读视频、逐帧调用、写视频串起来的主流程。编译前确认main.cpp里的模型路径、输入视频路径都改成你本地的实际路径。4.4 编译命令与常见链接错误cd cpp mkdir build cd build cmake .. cmake --build . --config ReleaseRelease 模式很重要Debug 下 onnxruntime 推理会慢好几倍。如果 cmake 阶段报找不到 onnxruntime检查ONNXRUNTIME_ROOT是否指向了正确的解压目录如果链接阶段报错检查库文件名和平台后缀。Linux 下还可能需要把 onnxruntime 的 lib 目录加进LD_LIBRARY_PATH否则运行时报找不到共享库。5. 避坑与排查模型路径、显存、关键点抖动这些翻车点5.1 报错找不到 onnx 模型文件现象程序启动即退出日志显示Failed to load model或No such file。 原因模型文件没下载或者路径拼接时多了/少了一层目录Windows 下反斜杠和正斜杠混用也可能出问题。 解决打印出程序实际拼接的完整路径和文件系统里的真实路径逐字符比对。统一用正斜杠或std::filesystem::path拼接。5.2 GPU 推理时显存不足现象跑几帧后崩溃报CUDA out of memory或 onnxruntime 的 allocation 失败。 原因驱动视频分辨率太高或者同时加载了多个 session 没释放中间张量。 解决先把驱动视频缩到 512 或 256 宽度试跑确认能通再逐步放大。onnxruntime 的 GPU 内存池可以通过 session options 限制别让它无限涨。5.3 输出视频人脸区域抖动或跳变现象生成的动画在某些帧突然歪一下或者闪。 原因驱动视频里人脸检测在某几帧失败关键点跳到了背景上运动信号就脏了。 解决对驱动视频先做一遍人脸检测过滤检测置信度低的帧做插值或者跳过。也可以在运动信号上加一点时序平滑常见做法是滑动平均。5.4 C 编译过但运行时报 DLL 缺失现象exe 双击没反应或者命令行报找不到onnxruntime.dll。 原因动态库没放到 exe 同目录或者系统 PATH 里没有。 解决把 onnxruntime 的 dll 复制到 exe 旁边最省事。Windows 下也可以用dumpbin /dependents看依赖了哪些 dll逐个补齐。5.5 Python 和 C 结果不一致现象同一张源图同一个驱动视频两条路输出效果有差异。 原因预处理裁剪、归一化、颜色通道顺序实现不一致或者模型版本不同。 解决先确认两边用的是同一批 onnx 文件再逐行比对预处理代码。OpenCV 默认 BGR很多模型要 RGB这个转换漏了颜色就会偏。6. 进阶技巧用 C 接口做批量处理和实时预览的取舍跑通单条之后真正要落地通常会碰到两个需求批量处理一堆源图或者做实时预览。这两件事在 C 里的做法不太一样。批量处理的关键是把模型加载和推理分开。init()只调一次把几个 session 常驻内存然后循环读图、推理、写文件。我一般会写一个简单的任务队列// 初始化一次复用 session LivePortrait lp; lp.init(model_dir); for (const auto img_path : image_list) { cv::Mat src cv::imread(img_path); cv::Mat driving cv::imread(driving_frame_path); cv::Mat out lp.animate(src, driving); cv::imwrite(out_ img_path, out); }这样比每次重新 init 快一个数量级因为省掉了模型加载和显存分配的开销。实时预览则是另一回事。onnxruntime 在 CPU 上跑一帧 LivePortrait 通常要几百毫秒做不到 30fps。想实时要么上 GPU 并把分辨率压到 256 以内要么做帧间缓存——只对关键帧跑完整推理中间帧用光流或者简单形变过渡。这个取舍没有标准答案看你的场景能接受多少延迟。验证结果是否正常我有个笨办法但很管用拿同一张源图分别用原始驱动视频和一段静止画面去驱动。静止画面驱动出来的结果应该几乎不动如果还在大幅晃说明运动信号提取或者时序处理有问题。这个对照测试能快速区分是模型问题还是输入问题。从那以后我每次拿到这类 onnxruntime 部署包都先跑一遍静止驱动对照再跑正常驱动两步都过了才往工程里集成。希望帮到你。本文还有配套的精品资源点击获取