Swift-技巧(二)模糊脸部功能
摘要逻辑 模糊脸部的逻辑主要有两个流程,就是先找到脸部,然后模糊脸部,那么就引申出这两个实现问题:
本文介绍模糊脸部的功能逻辑和实现方式,实现方式会尽可能的使用苹果提供的 API,保证功能高效率和简洁。
- 如何正确找到脸部区域?
- 如何只模糊脸部区域?
实现 【Swift-技巧(二)模糊脸部功能】实现功能方式有很多,这里只是分享一下自己的实现方式。主要借鉴 Core Image 中的方法。
找脸部区域
使用 CIDetector 类来查找图片中的脸部,虽然文档中说明可以找到比如鼻子更具体的部位,但是一直没有找到实现方式,它的识别成功率相对比较高,不是百分之百。
代码逻辑归纳为:
- 通过
CIDetector
类获取图片中的所有脸部区域 - 通过
CIFilter.sourceOverCompositing
函数绘制出存在所有脸部区域的 mask 图
// MARK: - 获取图像中面部区域数据
func getFaceData(from image: UIImage?) -> CIImage? {
guard image != nil, let image = CIImage(image: image!) else { return nil }
// CIDetectorTypeFace
let detector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: nil)guard let faceArray = detector?.features(in: image, options: nil) else { return nil}
var maskImage: CIImage? = nilfor face in faceArray {
let bounds = face.bounds
let centerX = bounds.origin.x + bounds.size.width * 0.4
let centerY = bounds.origin.y + bounds.size.height * 0.5let radius = min(bounds.size.width, bounds.size.height) * 0.5
let gaussion = CIFilter.radialGradient(inputCenter: CIVector(x: centerX, y: centerY),
inputRadius0: NSNumber(value: Int(radius)),
inputRadius1: NSNumber(value: Int(radius+1)),
inputColor0: CIColor(red: 0, green: 1, blue: 0, alpha: 1),
inputColor1: CIColor(red: 0, green: 0, blue: 0, alpha: 0))
guard let gaussianImage = gaussion?.outputImage else { continue }
if maskImage == nil {
maskImage = gaussianImage
} else {
maskImage = CIFilter.sourceOverCompositing(inputImage: gaussianImage, inputBackgroundImage: maskImage!)?.outputImage
}
}
return maskImage
}
模糊脸部区域
上面步骤获取到有脸部区域的 mask 图,下面就对脸部进行模糊。这里使用 使用
CISourceOverCompositing
处理脸部模糊。使用
blendWithMask
函数时,会发现要传入 3 张 image 对象,但是到目前只有一张原图和一张脸部的 mask 图,那么第三张图是什么呢?这里使用的第三张图是一张将原图通过
gaussianBlur
之后的图片。然后在使用 blendWithMask
合成后获得,那么这三张图放置有什么讲究呢?下面简单总结一下:inputImage
: 放置整体被高斯模糊后的图inputBackgroundImage
: 放置原图inputMaskImage
: 放置获取到脸部的 mask 图
// MARK: - 模糊人脸
func blurVariable(inputImage: UIImage?, maskInputImage: CIImage) -> UIImage? {guard let image = inputImage, let ciImg = CIImage(image: image) else { return nil }let blur = CIFilter.gaussianBlur(inputImage: ciImg, inputRadius: 8)
guard let blurImage = blur?.outputImage else { return nil}let maskedVariableFilter = CIFilter.blendWithMask(inputImage: blurImage, inputBackgroundImage: ciImg, inputMaskImage: maskInputImage)if let outputImg = maskedVariableFilter?.outputImage {
return UIImage(ciImage: outputImg.oriented(image.imageOrientation))
}
return nil
}
题外话 时间仓促,说的东西可能不全面,在你实现过程中遇到什么问题,评论区给我留言,我会尽快回复
推荐阅读
- EffectiveObjective-C2.0|EffectiveObjective-C2.0 笔记 - 第二部分
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 赢在人生六项精进二阶Day3复盘
- 2019年12月24日
- 陇上秋二|陇上秋二 罗敷媚
- 一百二十三夜,请嫁给我
- 【译】20个更有效地使用谷歌搜索的技巧
- 迷失的世界(二十七)
- 我要我们在一起(二)
- 基于|基于 antd 风格的 element-table + pagination 的二次封装