使用 CoreImage.framework 实现的 High Pass Skin Smoothing 的实现。
适用于 OS X 和 iOS。
测试使用 Instruments 的 "OpenGL ES Analysis" 模板进行。
使用 EAGLContext
和 sRGB 工作颜色空间 (CGColorSpaceCreateDeviceRGB()
) 创建 CIContext
对象。
Image Size: 640 x 800
Input Radius: 7.0
Operating System: iOS 9
Device: iPhone 5s / FPS: 60
Device: iPhone 5 / FPS: ~24
使用以下图表可以描述 YUCIHighPassSkinSmoothing
的基本流程。
High Pass Skin Smoothing 的主要理论是 频率分离
。
频率分离将图像的色调和颜色从其更详细的纹理中分离出来。这是因为数字图像可以被解释为以正弦波为不同频率的表示。
图像中的高频将包含有关细节信息,如皮肤毛孔、头发、细纹、皮肤瑕疵。
低频是包含有关体积、色调和颜色过渡信息的图像数据。换句话说:阴影和光区,颜色和色调。
https://fstoppers.com/post-production/ultimate-guide-frequency-separation-technique-8699
通过使用 高通 滤波器,可以将图像分离为高频和低频空间频率。然后,我们可以通过对图像的某些频率应用调整(图表中的“曲线调整”)来平滑图像并保留一定级别的细节。
CoreImage 中没有高通滤波器。幸运的是,创建它并不难(图表中的“高通滤波器”部分)
highpass.rgb = image.rgb - gaussianBlurredImage.rgb + vec3(0.5,0.5,0.5)
使用高通滤波器(绿通道和蓝通道叠加强光混合 -> 高通 -> 硬光混合 X 3)生成掩模图像,用于将需要调整的图像部分与应该保持不变的部分分离。
然后,这个掩模图像用于在 Blend with Mask (CIBlendWithMask)
滤波器中混合调整后的图像与未调整的图像,以生成最终输出图像。
除了图中的步骤外,YUCIHighPassSkinSmoothing
实际上还有两个额外的步骤。
在将图像发送到 Mask Generating Routine
(在 -[YUCIHighPassSkinSmoothingMaskGenerator outputImage]
方法中)之前,输入图像的曝光量降低 1 EV,并在 Mask Generating Routine
(在 YUCIHighPassSkinSmoothingMaskBoost.cikernel
的末尾)结束时添加 RGB 曲线调整。
这些步骤可以使高亮度区域的结果更好。当然,整个过程可以在没有这两个步骤的情况下工作。
inputAmount
:一个数值,用于控制 曲线调整
步骤的强度并影响最终 锐化
步骤的锐度。您使用此值来控制整体过滤器强度。有效值为 0
到 1.0
。默认值是 0.75
。
inputControlPoints
:一个 CIVector
数组,定义了 曲线调整
步骤中的曲线控制点。此参数的默认值是 [(0,0), (120/255.0,146/255.0), (1,1)]
。
inputRadius
:一个数值,用于控制 高通
滤波器的半径(以像素为单位)。此参数的默认值是 8.0
。请根据输入图像的分辨率和您想要保留的细节级别来调整此值。
inputSharpnessFactor
:一个数值,用于控制最终 锐化
步骤的锐度因素。锐度值计算为 inputAmount * inputSharpnessFactor
。此参数的默认值为 0.6。
为了获得最佳效果,您需要使用具有 sRGB 工作色彩空间的 CIContext
对象,而不是默认的线性色彩空间。您可以通过 options
字典中的 kCIContextWorkingColorSpace
键在创建上下文时指定工作色彩空间。
您还可以尝试仅将此过滤器应用于图像的皮肤/面部区域,可以使用皮肤检测过滤器或核心图像面部检测器。
使用 YUCIHighPassSkinSmoothing
,就像使用任何其他内置的核心图像过滤器一样。
有关输入参数的文档可以在 这里 找到。
let filter = YUCIHighPassSkinSmoothing()
filter.inputImage = ...
filter.inputAmount = ...
let outputImage = filter.outputImage!
/* Or */
let filter = CIFilter(name: "YUCIHighPassSkinSmoothing")!
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(0.7, forKey: "inputAmount")
let outputImage = filter.outputImage!
打开 YUCIHighPassSkinSmoothingDemo/YUCIHighPassSkinSmoothingDemo.xcworkspace
来运行 iOS 演示应用程序。演示应用程序展示了如何使用该滤镜以及如何使用不同类型的核心图像上下文来渲染输出图像。 Metal 核心图像上下文仅在 iOS 9 的 64 位设备上可用。
请在实际设备上运行演示应用程序。 iOS 模拟器无法提供与图形硬件完全准确的像素匹配。模拟器中的 OpenGL ES 的渲染性能与实际设备上的 OpenGL ES 性能无关。
YUCIHighPassSkinSmoothing
使用了 Vivid。
克隆此仓库 和 Vivid,然后将 Sources
目录中的文件手动添加到您的项目中。
鼓励您尝试不同的输入参数或调整内部流程以提高过滤器性能或满足您的需求。
如果您有任何想法或建议,请不要犹豫,提出问题。
如果发现错误并确切知道如何修复,请发起一个pull request。请确保在OS X和iOS上测试代码。
非常感谢Yien Ma对流程提供了许多建议和微调。
YUCIHighPassSkinSmoothing遵循MIT许可。详细信息请参阅LICENSE文件。
版权 © 2016 Yu Ao