2017-04-20 52 views
12

如何剪切我作爲faceViewBounds收到的框架以在臉部周圍形成一個大圓圈?這就像一個人臉上的徽章。用CIDetector和CIFaceFeature的臉部剪切圓形圖像

也許我應該得到faceViewBounds的中心,然後我必須在ImageView.image中找到這個中心,然後繪製一個大直徑的圓,然後用邏輯將其餘的圓剪除,但是我不知道如何做到這一點..任何建議?

func detectFaceFrom(ImageView theImageView: UIImageView) { 

    guard let personImage = CIImage(image: theImageView.image!) else { 
     return 
    } 

    let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyLow] 
    let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy) 
    let faces = faceDetector?.features(in: personImage) 

    let ciImageSize = personImage.extent.size 
    var transform = CGAffineTransform(scaleX: 1, y: -1) 
    transform = transform.translatedBy(x: 0, y: -ciImageSize.height) 
    if(faces?.count==1){ 
     for face in faces as! [CIFaceFeature] { 
      var faceViewBounds = face.bounds.applying(transform) 

      let viewSize = theImageView.bounds.size 
      let scale = min(viewSize.width/ciImageSize.width, 
          viewSize.height/ciImageSize.height) 
      let offsetX = (viewSize.width - ciImageSize.width * scale)/2 
      let offsetY = (viewSize.height - ciImageSize.height * scale)/2 

      faceViewBounds = faceViewBounds.applying(CGAffineTransform(scaleX: scale, y: scale)) 
      faceViewBounds.origin.x += offsetX 
      faceViewBounds.origin.y += offsetY 

      let faceBox = UIView(frame: faceViewBounds) 
      faceBox.layer.borderWidth = 3 
      faceBox.layer.borderColor = UIColor.green.cgColor 
      faceBox.backgroundColor = UIColor.clear 

      drawCircleFromCenter(faceViewBounds.center ??? 

     } 
     return cuttedCircleWithFace 
    }else{ 
     return theImageView.image 
    } 
} 

我剛纔看到了Facebook的廣告與我要實現這個目標完全一樣的東西:

badges

回答

8

問題是您應該使用您的image.size而不是使用theImageView.bounds.size。您還應該處理CIDetectorImageOrientation的功能選項。

func detectFaces(from image: UIImage) -> [UIImage] { 
    guard let ciimage = CIImage(image: image) else { return [] } 
    var orientation: NSNumber { 
     switch image.imageOrientation { 
     case .up:   return 1 
     case .upMirrored: return 2 
     case .down:   return 3 
     case .downMirrored: return 4 
     case .leftMirrored: return 5 
     case .right:   return 6 
     case .rightMirrored: return 7 
     case .left:   return 8 
     } 
    } 
    return CIDetector(ofType: CIDetectorTypeFace, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])? 
     .features(in: ciimage, options: [CIDetectorImageOrientation: orientation]) 
     .flatMap { 
      let rect = $0.bounds.insetBy(dx: -10, dy: -10) 
      let ciimage = ciimage.cropping(to: rect) 
      UIGraphicsBeginImageContextWithOptions(rect.size, false, image.scale) 
      defer { UIGraphicsEndImageContext() } 
      UIImage(ciImage: ciimage).draw(in: CGRect(origin: .zero, size: rect.size)) 
      guard let face = UIGraphicsGetImageFromCurrentImageContext() else { return nil } 
      // now that you have your face image you need to properly apply a circle mask to it 
      let size = face.size 
      let breadth = min(size.width, size.height) 
      let breadthSize = CGSize(width: breadth, height: breadth) 
      UIGraphicsBeginImageContextWithOptions(breadthSize, false, image.scale) 
      defer { UIGraphicsEndImageContext() } 
      guard let cgImage = face.cgImage?.cropping(to: CGRect(origin: 
       CGPoint(x: size.width > size.height ? (size.width-size.height).rounded(.down).divided(by: 2) : 0, 
         y: size.height > size.width ? (size.height-size.width).rounded(.down).divided(by: 2) : 0), 
        size: breadthSize)) else { return nil } 
      let faceRect = CGRect(origin: .zero, size: CGSize(width: min(size.width, size.height), height: min(size.width, size.height))) 
      UIBezierPath(ovalIn: faceRect).addClip() 
      UIImage(cgImage: cgImage).draw(in: faceRect) 
      return UIGraphicsGetImageFromCurrentImageContext() 
     } ?? [] 
} 

let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))! 
let faces = detectFaces(from: profilePicture) 

enter image description here

2

如果你只是想專注於圖像的內面。你應該首先建立的形象圖,它掩蓋成一個圓圈:

let image = UIImage(named: "face.jpg") 
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50.0, height: 50.0)) 
imageView.image = image 
imageView.contentMode = .scaleAspectFill 
imageView.layer.cornerRadius = imageView.bounds.height * 0.5 
imageView.layer.masksToBounds = true 

下次運行CIDetector

func focusOnFace(in imageView: UIImageView) 
{ 

    guard let image = imageView.image, 
      var personImage = CIImage(image: image) else { return } 

    let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyLow] 
    let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy) 
    // This will just take the first detected face but you can do something more sophisticated 
    guard let face = faceDetector?.features(in: personImage).first as? CIFaceFeature else { return } 

    // Make the facial rect a square so it will mask nicely to a circle (may not be strictly necessary as `CIFaceFeature` bounds is typically a square) 
    var rect = face.bounds 
    rect.size.height = max(face.bounds.height, face.bounds.width) 
    rect.size.width = max(face.bounds.height, face.bounds.width) 
    rect = rect.insetBy(dx: -30, dy: -30) // Adds padding around the face so it's not so tightly cropped 

    // Crop to the face detected 
    personImage = personImage.cropping(to: rect) 

    // Set the new cropped image as the image view image 
    imageView.image = UIImage(ciImage: personImage) 
} 

運行focusOnFace之前:

enter image description here

After運行focusOnFace

enter image description here

更新了例

運行focusOnFace之前:

enter image description here

運行focusOnFace後:

enter image description here

+1

是的,我想這一點,但我不希望它被放大等之後。我希望它像您展示的第一張照片一樣被縮小 - 「之前」。 –

+0

'CIDetector'會給你的臉和眼睛和嘴巴緊密裁剪的界限。如果你想要更多的周圍圖像,你可以添加像'rect = rect.insetBy(dx:-30,dy:-30)',其中30是你想要包括的寬度和高度的點數,在'rect.size.width = max(face.bounds.height,face.bounds.width)'之後,儘管你會需要做一些比這更復雜的事情,因爲你的矩形可能會超出原始圖像範圍的範圍。 – beyowulf

+1

在我的iPhone上,屏幕被切割並且位置有誤http://imgur.com/a/Fiu9G有什麼建議嗎? –