摘要

本文介绍模糊脸部的功能逻辑和实现方式,实现方式会尽可能的使用苹果提供的 API,保证功能高效率和简洁。

逻辑

模糊脸部的逻辑主要有两个流程,就是先找到脸部,然后模糊脸部,那么就引申出这两个实现问题:

  • 如何正确找到脸部区域?
  • 如何只模糊脸部区域?

依次解决这两个问题,那么这个功能就已经轻松实现了。

实现

实现功能方式有很多,这里只是分享一下自己的实现方式。主要借鉴 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? = nil for 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.5 let 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 图

通过效果看这三张图是这样处理,inputBackgroundImage 和 inputMaskImage 组合获得到脸部区域被扣去的图片,然后在这张图下面放置 inputImage 图,就能得到脸部被高斯模糊的图片了。

// 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
}

题外话

时间仓促,说的东西可能不全面,在你实现过程中遇到什么问题,评论区给我留言,我会尽快回复

最新文章

  1. 各种android应用模仿源码
  2. CSS关于子元素设置了float属性后父元素高度为0的解释和解决方法
  3. 面试题五 数组中出现次数超过一半的数字 时间为O(n)
  4. 在VS2010下编译和使用tesseract_ocr识别验证码
  5. Django基础——Model篇(二)
  6. [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select
  7. 【CSS3】Advanced3:Universal, Child, and Adjacent Selectors
  8. windwos server 2008下iis7各种操作
  9. T-SQL表联接查询
  10. Python重写C语言程序100例--Part6
  11. 使用python+django+twistd 开发自己的操作和维护系统的一个
  12. C++学习笔记1(标准的输入输出)
  13. ecshop屏蔽wap功能
  14. [原创]MinHook测试与分析(x64下 E9,EB,CALL指令测试,且逆推测试微软热补丁)
  15. CSS设计中的错误大整理!
  16. Sum of Even Numbers After Queries LT985
  17. C++变量的默认初始化规则
  18. Alpha 冲刺一
  19. node模拟socket
  20. 使用依赖关系注入在 ASP.NET Core 中编写干净代码

热门文章

  1. PHP中PDO关闭连接的问题
  2. MSSQL数据库安全实验
  3. whistle手机抓包(以安卓手机为例)
  4. LR进行内外网附件上传并发——实践心得
  5. css Table 表格宽度失效解决方案
  6. 定要过python二级 第二套
  7. 2017第二届广东省强网杯线上赛:WEB phone number (SQL注入)
  8. 浅析 Java 内存模型
  9. HttpClient遭遇Connection Reset异常,如何正确配置?
  10. storm卡顿修改