zoukankan      html  css  js  c++  java
  • Swift-技巧(二)模糊脸部功能

    摘要

    本文介绍模糊脸部的功能逻辑和实现方式,实现方式会尽可能的使用苹果提供的 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
     }
    

    题外话

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

  • 相关阅读:
    Cassandra内部架构
    Cassandra数据模型
    windows10 docker安装使用
    vue用async、await实现同步请求
    navicat mysql 书写存储过程并导出成sql
    idea svn 文件还原到指定版本
    vscode vue 去掉语法提示
    elasticsearch regexp查询特殊字符处理
    redis中获取不同自增数的方法
    java Elasticsearch 进行嵌套子聚合
  • 原文地址:https://www.cnblogs.com/shsuper/p/15502695.html
Copyright © 2011-2022 走看看