Skip to content

AllenSWB/fast_guided_smooth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fast_guided_smooth

这是一个基于 GPUImage2 + OpenGL ES 的实时磨皮项目,核心算法是快速导向滤波(Fast Guided Filter),并结合颜色空间皮肤检测做区域约束。

项目目标:

  • 在 iOS 端以 Camera 预览实时跑磨皮
  • C++ 核心逻辑可移植(不依赖旧工程里的 Filter/Context 基类)
  • 通过描述化 pipeline(descriptor)组织多 pass 算法,便于 Android/其他渲染后端复用

1. 项目结构

1.1 iOS 侧(GPUImage2 接入)

  • ios/FastGuidedSmooth/FastGuidedSmooth/ViewController.swift
  • ios/FastGuidedSmooth/FastGuidedSmooth/FastGuidedSmoothOperation.swift
  • ios/FastGuidedSmooth/FastGuidedSmooth/FastGuidedSmoothBridge.h
  • ios/FastGuidedSmooth/FastGuidedSmooth/FastGuidedSmoothBridge.mm

职责:

  • ViewController 负责 Camera -> Filter -> RenderView 的链路搭建和 UI 参数调节
  • FastGuidedSmoothOperation 是 GPUImage2 的自定义节点,实现 Framebuffer 输入输出
  • Bridge(ObjC++)把 GPUImage 纹理转到 C++ descriptor 执行器里,完成多 pass 渲染

1.2 C++ 算法层(可移植核心)

  • src/smooth_fast_guided/FastGuidedPipeline.h
  • src/smooth_fast_guided/FastGuidedSmoothFilter.cpp
  • src/smooth_fast_guided/FastGuidedStatsFilter.cpp
  • src/smooth_fast_guided/FastGuidedABFilter.cpp
  • src/smooth_fast_guided/FastGuidedBlurABFilter.cpp
  • src/smooth_fast_guided/FastGuidedScaleFilter.cpp
  • src/smooth_fast_guided/FastGuidedUnitFilter.cpp
  • src/skin/ColorSpaceSkinDetectFilter.cpp

职责:

  • 用 ShaderPassDescriptor / PipelineDescriptor 描述每个 pass
  • 算法层只描述“图结构 + shader + uniform + 输入输出关系”
  • 不绑定 iOS 平台对象,便于跨端重用

2. GPUImage Filter 接入点

2.1 入口链路

在 ViewController 中,链路是:

  • Camera(sessionPreset: .hd1280x720, location: .frontFacing)
  • camera --> FastGuidedSmoothOperation --> RenderView

滑杆把 [0, 1] 的值实时映射到磨皮强度 strength。

2.2 FastGuidedSmoothOperation 的角色

FastGuidedSmoothOperation 遵循 ImageProcessingOperation:

  • 接收上游 camera 的 inputFramebuffer
  • 调用 bridge.processSourceTexture(texture, width, height)
  • 拿到输出纹理后,用 overriddenTexture 构建新的 outputFramebuffer
  • 调用 updateTargetsWithFramebuffer(outputFramebuffer) 发送到 RenderView

这一步是 GPUImage2 图中的“自定义滤镜节点”。

2.3 Bridge 的角色

FastGuidedSmoothBridge.mm 做了三件事:

  • 把算法对象 FastGuidedSmoothFilter 的 descriptor 取出来
  • 用 DescriptorExecutor 执行 descriptor 中定义的 pass 图
  • 返回最终 outputPassKey 对应的纹理给 Operation

DescriptorExecutor 负责:

  • shader 编译/链接缓存(避免重复编译)
  • 每个 pass 的 render target(texture + framebuffer)缓存
  • external input(source)与 pass output 的依赖解析
  • uniform 和 sampler 绑定

3. Fast Guided Filter 实现(重点)

当前主 pipeline 在 FastGuidedSmoothFilter::descriptor() 中组装,包含以下 pass:

  1. stats_downsample
  2. stats_horizontal
  3. stats_vertical
  4. ab
  5. blur_ab_horizontal
  6. blur_ab_vertical
  7. upsample_ab
  8. skin_mask
  9. unit(最终输出)

3.1 统计阶段(stats)

文件:src/smooth_fast_guided/FastGuidedStatsFilter.cpp

思路:

  • 先降采样(stats_downsample),降低计算量
  • 横向统计局部均值与平方均值(stats_horizontal)
  • 纵向再聚合得到 mean_I 与 var_I(stats_vertical)

核心意义:为导向滤波线性模型提供局部统计量。

3.2 系数阶段(ab)

文件:src/smooth_fast_guided/FastGuidedABFilter.cpp

基于统计量计算线性模型系数:

$$ a = \frac{\mathrm{cov}(I,p)}{\mathrm{var}(I)+\epsilon}, \quad b = \bar{p} - a\bar{I} $$

在当前实现中,使用灰度引导近似并写入 RG 两通道(a,b)。

3.3 系数平滑阶段(blur_ab)

文件:src/smooth_fast_guided/FastGuidedBlurABFilter.cpp

  • 对 a,b 做 separable blur:先横向再纵向
  • 进一步抑制系数噪声,得到更稳定的引导重建结果

3.4 上采样阶段(upsample_ab)

文件:src/smooth_fast_guided/FastGuidedScaleFilter.cpp

  • 将低分辨率 a,b 上采样回原图分辨率
  • 保证最终 unit pass 与原始输入在同尺寸空间融合

3.5 皮肤检测阶段(skin_mask)

文件:src/skin/ColorSpaceSkinDetectFilter.cpp

使用颜色空间规则生成 mask:

  • HSV 区间约束(H/S/V 范围)
  • RGB 阈值约束(肤色常见经验阈值)
  • 输出灰度 mask(皮肤=1,非皮肤=0)

3.6 最终融合阶段(unit)

文件:src/smooth_fast_guided/FastGuidedUnitFilter.cpp

输入:

  • inputImageTexture(原图)
  • meanABTexture(平滑后的 a,b)
  • skinMaskTexture(皮肤区域 mask)

流程:

  1. 计算皮肤加权强度:

$$ ext{maskedStrength} = \text{strength} \cdot \mathrm{clamp}(\text{skinMask}, 0, 1) $$

  1. 使用导向模型重建目标亮度 q
  2. 用 maskedStrength 在原亮度 I 与 q 之间插值
  3. 将亮度变化量回写到 RGB,限制变化范围,避免过磨皮

效果:

  • 皮肤区域平滑明显
  • 非皮肤区域尽量保持原细节

4. Descriptor 设计与跨端价值

核心结构在 src/smooth_fast_guided/FastGuidedPipeline.h:

  • ShaderPassDescriptor:单个 pass 的 shader、输入、uniform、输出缩放
  • PassInputDescriptor:描述输入来源(external 或上游 pass)
  • PipelineDescriptor:完整 pass 图 + 最终输出键

优点:

  • 算法层与渲染执行层解耦
  • iOS 只需提供一个执行器(当前是 OpenGL ES 执行器)
  • Android/Metal/Vulkan 侧可复用同一套 pass 描述,替换执行器即可

5. 渲染执行细节(Bridge)

Bridge 执行器关键点:

  • 按 pass.outputScale 推导每个 pass 输出尺寸
  • 每个 pass 按 key 缓存 program 和 render target
  • 逐 pass 绑定输入纹理与 sampler
  • 执行 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
  • 以 descriptor.outputPassKey 作为最终输出纹理

同时保留了较完整的调试日志(FGS_TRACE_V3),便于排查:

  • 链路是否进入 bridge
  • descriptor 是否正确生成
  • 各 pass 的输入输出尺寸
  • 关键 GL 调用是否报错

6. 当前参数与调优建议

默认参数(FastGuidedSmoothFilter.h):

  • downSampleFactor = 0.25
  • epsilon = 0.02
  • radius = 4.0
  • strength 由 UI slider 控制

调优建议:

  • 想更柔和:增大 strength、适当增大 radius
  • 想保细节:减小 strength 或减小 epsilon
  • 想提性能:减小 downSampleFactor(更低分辨率计算)

7. 已知工程化要点

  • GPUImage2 与自定义 OpenGL pass 混用时,要避免污染全局 GL 状态
  • 自定义 pass 输出纹理要与 GPUImage Framebuffer 生命周期对齐
  • RenderView/主线程相关调用需保证线程正确

8. 快速运行

  1. 打开 ios/FastGuidedSmooth/FastGuidedSmooth.xcodeproj
  2. 选择 FastGuidedSmooth scheme
  3. 运行到真机(Info.plist 已配置相机权限)
  4. 通过底部 slider 调节磨皮强度

TODO:

  • 将 DescriptorExecutor 抽象为可替换后端(OpenGL/Metal)
  • Android Demo

9. 能耗表现

gpu_report energy_report

About

Skin smoothing using the fast guided filter algorithm

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors