Hair Segmentation:MediaPipe 头发分割模块 CMake 独立编译

引言

MediaPipe 的 hair_segmentation 模块提供了一种高质量的实时头发分割方案------通过语义分割模型从画面中精确分离头发区域,并支持自定义发色渲染。与 face_mesh 的人脸关键点检测不同,hair_segmentation 关注的是像素级的头发/背景二分类,配合时序融合机制实现帧间平滑过渡。然而原版同样深度绑定 Bazel + GPU 工具链,Windows 桌面端难以独立部署。

Hair Segmentation CPU 项目将完整的 hair_segmentation 管线从 MediaPipe 0.10.10 中完全解耦,实现了:

  • 🔧 CMake 构建体系:告别 Bazel,Visual Studio 2022 及以上版本一键编译,首次构建不超过 5 分钟
  • 🚀 零 GPU 依赖:纯 CPU 推理,XNNPACK SIMD 加速,无需 CUDA / OpenGL
  • 🎨 实时发色渲染:512×512 语义分割 + 自定义 RGB 发色,实时 20~30 FPS
  • 🔄 时序一致性:前帧掩码回环融合(0.9 平滑系数),大幅减少帧间闪烁
  • 🎛️ 运行时热配置:发色 RGB 实时可调,无需重新编译
  • 📦 完整可执行文件仅 6.8 MB:包含分割模型,零外部运行时依赖

上图:Hair Segmentation 在 i7-12700H 纯 CPU 环境下的摄像头实时运行效果。左侧为原始画面,右侧为头发分割 + 蓝色发色渲染后的效果。

开源地址:https://github.com/lazyboooooy/hair_seg-cmake


一、项目定位

1.1 与 face_mesh / face_detection 的关系

三个项目同源,均从 MediaPipe 0.10.10 解耦,共享同一份 3rdparty 依赖和 CMake 构建体系,但定位各异:

维度 face_detection face_mesh hair_segmentation(本项目)
功能 人脸检测 + 6 个关键点 人脸 478 个 3D 关键点 头发分割 + 发色渲染
模型数量 1 个(225 KB) 3 个(3.8 MB) 1 个(782 KB)
计算子图 5 个 12 个 0(单图,无子图)
自定义 TFLite 算子 4 个 6 个 0
管线复杂度 最低
输入尺寸 128×128 128×128 + 192×192 512×512 RGBA
独特机制 置信度过滤 跳帧优化 + ROI 旋转 时序融合(0.9 平滑)
适用场景 人脸检测计数 面捕、虚拟主播 虚拟染发、美颜、AR 特效

关键区别 :hair_segmentation 是三个项目中最简洁 的一个------无子图、无自定义 TFLite 算子,整个管线由 10 个内置计算器在一个平铺的 .pbtxt 文件中串联完成。它的核心价值在于时序一致性------通过 PreviousLoopbackCalculator 将前帧分割掩码回环融合,实现帧间平滑过渡,这是单帧分割方案无法做到的。

1.2 为什么选择独立编译

问题 原版 MediaPipe 本项目
构建系统 Bazel(需 MSYS2 + Python + Bazelisk) CMake 3.16+(VS 2022 及以上原生)
首次配置 30~60 分钟 10 秒
首次编译 1~2 小时 3~5 分钟
GPU 依赖 必须 OpenGL / ES 3.1 不需要
项目体积 ~5 GB ~250 MB
IDE 支持 Visual Studio 原生

二、快速开始

2.1 环境要求

组件 要求 说明
操作系统 Windows 10/11 x64 ---
编译器 Visual Studio 2022 及以上 Community 免费版,勾选"使用 C++ 的桌面开发"
CMake ≥ 3.16 VS 2022 及以上自带

⚠️ 不需要:Python、CUDA、OpenGL、Docker、MSYS2。所有依赖已预编译打包。

2.2 三步运行

bash 复制代码
# 第一步:克隆
git clone https://github.com/lazyboooooy/hair_seg-cmake.git
cd hair_seg-cmake

# 第二步:编译
cmake -B build -S .
cmake --build build --config Release

# 第三步:运行
cd build/Release
./hair_segmentation_cpu.exe

摄像头自动打开,检测到头发后按默认蓝色渲染。按 ESC 退出。

为什么默认启动摄像头? 配置文件 hair_segmentation_config.ini[video] input = 默认为空,程序检测到没有指定视频文件后自动打开摄像头 0。

2.3 配置文件详解

编辑 exe 同目录下的 hair_segmentation_config.ini,改动即时生效:

ini 复制代码
[paths]
resource_root_dir = resource
graph_config = graphs/hair_segmentation_desktop_live.pbtxt

[video]
input =                         # 视频文件路径(留空用摄像头)
output =                        # 输出 MP4(预留)

[color]
# 发色 RGB(0-255),默认蓝色
r = 0
g = 0
b = 255

[execution]
num_threads = 2                 # TFLite 推理线程(0 = 自动)
xnnpack_enable = true           # XNNPACK SIMD 加速

配置优先级:命令行参数 > INI 文件 > 默认值。

2.4 发色预设

颜色 R G B 视觉效果
蓝色(默认) 0 0 255 纯净蓝发
红色 255 0 0 鲜艳红发
粉色 255 105 180 柔和粉发
金色 255 215 0 亮丽金发
紫色 128 0 128 深邃紫发
绿色 0 255 0 个性绿发

2.5 命令行参数

参数 说明
--config_file=D:/my.ini 自定义配置文件路径
--input_video_path=D:/test.mp4 视频文件路径
--resource_root_dir=D:/resource 资源目录

三、管线架构

3.1 数据流

复制代码
摄像头帧 (OpenCV)
  → FlowLimiterCalculator(限流:同时只飞 1 帧)
  → ImageTransformationCalculator(缩放至 512×512,STRETCH 模式)
  → PreviousLoopbackCalculator(回环上一帧分割掩码)
  → ColorConvertCalculator(RGBA 掩码 → 单通道灰阶掩码)
  → SetAlphaCalculator(掩码嵌入当前帧 Alpha 通道 → RGBA 4 通道)
  → TfLiteConverterCalculator(图像 → TFLite 张量,max_num_channels=4)
  → TfLiteInferenceCalculator(512×512 推理,XNNPACK 加速)
  → TfLiteTensorsToSegmentationCalculator(张量 → 掩码,时序融合 0.9)
  → RecolorCalculator(按 INI 配置的 RGB 渲染发色到原图)
  → 输出帧 (OpenCV imshow)

3.2 核心机制

FlowLimiterCalculator(限流):确保管线内同时只有 1 帧在处理,杜绝帧积压和内存膨胀。

PreviousLoopbackCalculator(掩码回环) :将上一帧的分割掩码缓存,在下一次推理时通过 SetAlphaCalculator 嵌入当前帧的 Alpha 通道。这使得模型输入为 RGBA 4 通道(RGB + 前帧掩码),模型可以利用前一帧的分割结果来引导当前帧的预测。

时序融合(Temporal Fusion)TfLiteTensorsToSegmentationCalculator 解码当前帧的 2 通道分割张量后,将其与上一帧掩码按 0.9 : 0.1 的比例加权融合:

复制代码
当前掩码 = 0.1 × 当前模型输出 + 0.9 × 上一帧掩码

0.9 的高融合比例使分割边缘在帧间平滑过渡,大幅减少闪烁。这是 MediaPipe hair_segmentation 管线相比单帧语义分割方案的独有优势。

3.3 10 个管线组件一览

组件 类型 功能
FlowLimiterCalculator 核心 背压控制,管线内最多 1 帧
ImageTransformationCalculator 图像 缩放至 512×512(STRETCH 模式)
PreviousLoopbackCalculator 核心 缓存前帧掩码,替换时间戳后回环
ColorConvertCalculator 图像 RGBA → 单通道灰阶掩码
SetAlphaCalculator 图像 掩码嵌入 Alpha 通道,生成 RGBA 输入
TfLiteConverterCalculator TFLite 图像 → TFLite 张量(max_num_channels=4)
TfLiteCustomOpResolverCalculator TFLite 注册自定义算子解析器
TfLiteInferenceCalculator TFLite CPU 推理(XNNPACK 加速)
TfLiteTensorsToSegmentationCalculator 工具 2 通道张量 → 分割掩码 + 时序融合
RecolorCalculator 工具 按 RGB 颜色渲染发色到原图

四、分割模型

4.1 模型规格

参数
架构 语义分割(Encoder-Decoder)
输入尺寸 512×512 RGBA(4 通道)
输入通道含义 RGB(当前帧)+ Alpha(前帧掩码)
输出 2 通道(头发 / 背景)
时序融合比例 0.9(combine_with_previous_ratio)
量化 FP32(全精度)
模型大小 782 KB

4.2 为什么是 512×512

头发分割属于像素级语义分割任务,不同于人脸检测只需要回答"有没有、在哪"。分割模型需要为每个像素分配类别标签(头发/背景),输入分辨率直接决定分割边界的精细度。512×512 的输入尺寸使模型能够捕捉发丝的细节纹理,输出高质量的头发轮廓掩码。

4.3 为什么是 4 通道 RGBA

标准 RGB 输入只能提供当前帧的色彩信息。通过 SetAlphaCalculator 将前帧掩码嵌入 Alpha 通道,模型同时获得:

  • RGB 通道:当前帧的视觉信息(颜色、纹理、边缘)
  • Alpha 通道:前一帧的分割结果("上一帧哪里是头发")

这种设计让模型具备时序感知能力------即使当前帧的某些头发区域因光照或运动而难以分辨,前帧的掩码信息也能引导模型做出正确预测。这是 MediaPipe hair_segmentation 区别于普通语义分割模型的核心设计。


五、与 face_mesh / face_detection 的横向对比

5.1 规模对比

指标 face_detection face_mesh hair_segmentation
源码文件数 ~130 个 .cc ~150 个 .cc ~100 个 .cc
Proto 文件数 ~25 个 ~30 个 ~18 个
计算子图 5 个 12 个 0
自定义算子 4 个 6 个 0
模型数 1 3 1
INI 配置项 ~10 ~12 ~7
编译时间(增量) ~30 秒 ~40 秒 ~20 秒

hair_segmentation 是三个项目中最精简的------零子图、零自定义算子,使其成为理解 MediaPipe CalculatorGraph 工作机制的最佳入门项目。

5.2 适用场景分工

需求 推荐项目 理由
人脸检测 / 计数 / 位置追踪 face_detection 225 KB 模型,极简
面部捕捉 / 虚拟主播 / 表情分析 face_mesh 478 关键点,虹膜定位
虚拟染发 / 美颜发色 / AR 特效 hair_segmentation 时序融合平滑,发色实时可调
移动端直接集成 Google ML Kit 原生 SDK

六、性能实测

6.1 测试环境

项目 配置
CPU Intel Core i7-12700H(14 核 20 线程,P-core 4.7 GHz)
内存 16 GB DDR5-4800
OS Windows 11 Pro
编译器 MSVC 2022,Release /O2 /arch:AVX2
TFLite 后端 XNNPACK(SSE4.1 + AVX2 自动调度)
推理线程 2 线程

6.2 逐帧耗时

阶段 耗时(ms) 占比 说明
帧捕获 + BGR→RGB 1~3 ~8% 摄像头 grab/retrieve + 色彩转换
ImageFrame 包装 1~2 ~5% cv::MatImageFrame 内存拷贝
图像缩放(→ 512×512) 1~2 ~5% STRETCH 模式,无额外插值开销
掩码嵌入(RGBA 合成) 0.5~1 ~3% SetAlphaCalculator Alpha 通道写入
TFLite 推理(512×512) 10~20 ~55% 计算最密集的阶段
分割解码 + 时序融合 2~5 ~12% 2 通道解码 + 0.9 加权平滑
发色渲染 2~4 ~12% RecolorCalculator 逐像素着色
单帧总计 16~34 100%

6.3 整体指标

指标 数值
实时帧率 20~30 FPS
内存占用 ~160 MB
CPU 占用 25~35%(i7-12700H)
可执行文件 6.8 MB
模型大小 782 KB

推理耗时与画面中头发占比无明显关联------512×512 全图推理的特性使得每帧计算量几乎恒定,帧率波动小,体验稳定。

6.4 与同类方案对比

方案 分割精度 CPU FPS 时序平滑 模型大小 自定义发色 构建难度
本项目 20~30 ✅ 0.9 融合 782 KB ✅ INI 热配置 极低
MediaPipe 原版 20~30 782 KB ❌ 需改 pbtxt 极高
OpenCV GrabCut 5~10 无模型
传统颜色阈值 60+ 无模型

七、项目目录结构

复制代码
hair_segmentation/
├── CMakeLists.txt                            # CMake 构建配置(C++17, MSVC)
├── README.md / README_EN.md                  # 中英文文档
├── LICENSE                                   # Apache 2.0
├── demo/
│   └── hair_seg.gif                          # 运行效果图
├── src/
│   ├── main.cc                               # 入口:图加载、摄像头、发色替换
│   ├── glog_config.h                         # GLog 预包含头文件
│   └── mediapipe/
│       ├── abseil_log/                       # Abseil 日志桩
│       ├── calculators/                      # 计算器(core/image/tensor/tflite/util)
│       ├── framework/                        # 图执行引擎、包管理
│       ├── gpu/                              # GPU 缓冲管理(Image 类型,无 OpenGL)
│       ├── tflite_kernels/                   # TFLite 内部符号补齐
│       └── util/tflite/                      # OpResolver、算子注册
├── resource/
│   ├── hair_segmentation_config.ini          # 运行时配置文件
│   ├── graphs/
│   │   └── hair_segmentation_desktop_live.pbtxt  # 计算图(单文件,无子图)
│   └── mediapipe/models/
│       └── hair_segmentation.tflite          # 分割模型(782 KB)
├── 3rdparty/                                 # 预编译第三方依赖(~240 MB)
│   ├── tflite/  opencv/  protobuf/  abseil/
│   ├── XNNPACK/  eigen/  flatbuffers/
│   └── ...
└── cmake/
    ├── protoc.exe                            # Protocol Buffer 编译器
    └── generate_protos.bat                   # Proto 编译脚本

八、常见问题排查

Q1: 双击 exe 窗口一闪就退出

在命令行运行查看错误信息:

bash 复制代码
cd build/Release
./hair_segmentation_cpu.exe
错误信息 原因 解决方案
Cannot open webcam (camera 0) 摄像头被占用 关闭微信/腾讯会议/浏览器等占用摄像头的程序
Resource not found: graphs/... resource/ 目录缺失 检查 build/Release/resource/,重新执行 cmake --build
Could not load config INI 文件缺失 检查 build/Release/hair_segmentation_config.ini
protoc not found 杀毒软件误删 cmake/protoc.exe 从 Windows Defender 恢复,或下载 protoc-3.21.12

Q2: 画面卡顿,FPS 低于预期

ini 复制代码
[execution]
num_threads = 4        # 增加推理线程
xnnpack_enable = true  # 确认 XNNPACK 已启用

也可以在任务管理器中将 hair_segmentation_cpu.exe 的 CPU 优先级设为"高"。

Q3: 分割边缘闪烁

时序融合已内置 0.9 平滑系数,正常情况下闪烁很轻微。如果仍有明显闪烁,可能是以下原因:

  • 摄像头光线不足 → 提高环境亮度
  • 人物移动过快 → 正常现象,时序融合需要 2~3 帧收敛
  • 头发与背景颜色相近 → 模型区分能力下降

Q4: 编译报错 "Cannot open include file: 'Eigen/Core'"

Eigen3 目录联结创建失败:

bash 复制代码
# 手动创建联结
mklink /J "build\generated\third_party\eigen3\Eigen" "3rdparty\eigen\include\Eigen"

# 如果 mklink 不可用,手动拷贝
xcopy /E /I "3rdparty\eigen\include\Eigen" "build\generated\third_party\eigen3\Eigen"

Q5: OpenCV DLL 缺失

bash 复制代码
copy 3rdparty\opencv\bin\opencv_world3410.dll build\Release\

九、3rdparty 依赖树

所有第三方依赖预编译打包,实现一次性下载、离线编译:

复制代码
3rdparty/
├── tflite/          (94 MB)    TensorFlow Lite 推理引擎
├── opencv/          (62 MB)    OpenCV 3.4.10(仅 world 模块)
├── protobuf/        (36 MB)    Protocol Buffers 3.21.12
├── abseil/          (18 MB)    Abseil C++ LTS 20230125
├── XNNPACK/         (3.7 MB)   SIMD 推理加速
├── eigen/           (仅头文件)   Eigen 3.4.0(模板库)
├── flatbuffers/     (1.2 MB)   序列化
├── cpuinfo/         (0.8 MB)   CPU 特性检测(SSE/AVX)
├── pthreadpool/     (0.3 MB)   线程池
├── farmhash/        (0.1 MB)   哈希函数
├── ruy/             (0.5 MB)   矩阵乘法微内核
├── fft2d/           (0.2 MB)   2D FFT
├── FP16/            (0.1 MB)   半精度浮点
├── FXdiv/           (0.05 MB)  快速整数除法
├── gemmlowp/        (0.3 MB)   低精度 GEMM(预留)
└── abseil_extra_obj/(1.5 MB)   日志符号桩

hair_segmentation 的依赖精简策略与 face_mesh 一致:头文件 3000+ → 652、Proto 50+ → 18、计算器 100+ → 10。由于无需子图和自定义算子,精简效果最显著。


十、局限性

局限 影响 改进方向
固定 512×512 输入 非正方形画面有轻微拉伸 改为 LETTERBOX 缩放模式
仅单人场景 多人会被分割为同一头发区域 先做实例分割再分别渲染
深色/短发的边缘精度 与背景对比度低时边界模糊 模型微调 + 边缘细化后处理
仅 Windows 不支持 Linux/macOS 替换平台 API
无视频输出 MP4 写入尚未实现 集成 OpenCV VideoWriter

十一、总结

三项目选型建议

需求 推荐
人脸检测 / 计数 face_detection-cmake
面部捕捉 / 表情分析 / AR 特效 face_mesh-cmake
虚拟染发 / 发色渲染 / 美颜 hair_seg-cmake(本项目)

hair_segmentation 是三个 MediaPipe 解耦项目中最简洁的一个:无子图、无自定义算子、仅 1 个模型、7 个 INI 配置项。它的价值在于:

  1. 时序融合是区别于所有单帧分割方案的核心优势------0.9 平滑系数让发色渲染结果在帧间丝滑过渡
  2. 发色热配置让换色像改 RGB 数值一样简单,无需重新训练或编译
  3. 作为学习项目,它的扁平管线架构比 face_mesh 的多层子图更容易理解 MediaPipe CalculatorGraph 的工作方式

开源地址:https://github.com/lazyboooooy/hair_seg-cmake


参考文献

  1. Lugaresi C, Tang J, Nash H, et al. MediaPipe: A Framework for Building Perception Pipelines . arXiv:1906.08172, 2019.
  2. Google. MediaPipe Hair Segmentation . MediaPipe Documentation
  3. Google. XNNPACK: High-efficiency Floating-point Neural Network Inference Operators . GitHub
  4. Sandler M, Howard A, Zhu M, et al. MobileNetV2: Inverted Residuals and Linear Bottlenecks . CVPR 2018. arXiv:1801.04381
  5. Google. TensorFlow Lite --- ML for Mobile and Edge Devices . TensorFlow Lite
相关推荐
糖葫芦君1 小时前
Claude code并行运行代理
人工智能·claude
AC赳赳老秦1 小时前
OpenClaw + 华为云自动化:批量管理云资源、生成月度云账单分析与成本优化报告
java·开发语言·javascript·人工智能·python·mysql·openclaw
code_pgf1 小时前
CenterPoint 3D 目标检测详解
人工智能·目标检测·3d
Irissgwe1 小时前
C++ STL 详解:list 的介绍使用与模拟实现
开发语言·c++·stl·list
AI客栈1 小时前
CI/CD 流水线与云原生自动化运维:ArgoCD + GitOps 全链路交付的工程实践
人工智能
SL-staff1 小时前
Vue3私有化AI白板落地实战|解决政企项目智能绘图合规难题(可直接复用源码)
人工智能·低代码·开源·vue3·白板·jvs规则引擎·jvs-draw
疯狂打码的少年1 小时前
【程序语言与编译】文法的分类(0-3型,乔姆斯基体系)
人工智能·笔记·分类·数据挖掘
我能坚持多久1 小时前
C++继承详解
开发语言·c++
量化君也1 小时前
桥水基金全天候策略拆解,构建中国ETF躺平版策略
大数据·人工智能·python·算法·金融·业界资讯