2017-04-20 42 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有什么建议吗? –