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
 }

題外話

時間倉促,說的東西可能不全面,在你實現過程中遇到什么問題,評論區給我留言,我會盡快回復


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM