人脸识别之CoreImage

2018-07-06  本文已影响20人  melody5

前段时间研究人脸识别,正好也在学习swift,所以真好都总结一下。

步骤;

  1. 创建特征检测器CIDetector,检测类型人脸,高精度。
  2. 调用检测器的featuresInImage方法,传入图片,会得到一个人脸的数组。
  3. 遍历人脸数组,转为CIFaceFeature类型,并根据其各个特征点进行操作,比如人脸,眼睛等位置。

下面是我的demo,就一个imageView和一个按钮,点击按钮开始检测,检测到人脸后,在脸上加一个红色的框。

检测前:

image.png

检测后

image.png

看一下,点击检测按钮做了什么:

    @IBAction func detect(_ sender: Any) {
        // 取出照片并将其转换为CIImage,使用Core Image时需要用CIImage
        guard let picture = CIImage(image: pictureView.image!) else {
            return
        }
        // 选择高精度
        let accuracy = [CIDetectorAccuracy:CIDetectorAccuracyHigh]
        // 这里定义了一个属于CIDetector类的faceDetector变量,并输入之前创建的accuracy变量
        let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy)
        // 调用faceDetector的featuresInImage方法,识别器会找到所给图像中的人脸,最后返回一个人脸数组
        let faces = faceDetector?.features(in: picture)
        
        // 计算转换坐标系的transform(这里取出来的size是图片的原始尺寸)
        let ciImageSize = picture.extent.size
        var transform = CGAffineTransform(scaleX: 1, y: -1)
        transform = transform.translatedBy(x: 0, y: -ciImageSize.height)
        
        // 遍历faces数组,把人脸数据转换为CIFaceFeature类型
        for face in faces as! [CIFaceFeature] {
            print("发现人脸坐标= \(face.bounds)")
            // 通过上边transform转换face的坐标
            var faceViewBounds = face.bounds.applying(transform)
            
            // 由于图片的宽高比例可能会随着容器pictureView的zize而被压缩或者拉伸,这里计算框框在pictureView中的实际大小和位置
            let viewSize = pictureView.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 faceCase = UIView(frame: faceViewBounds)
            faceCase.layer.borderWidth = 3
            faceCase.layer.borderColor = UIColor.red.cgColor
            faceCase.backgroundColor   = UIColor.clear
            pictureView.addSubview(faceCase)
            
            print("转换后人脸坐标= \(faceCase.frame)")
            
            if face.hasLeftEyePosition {
                print("左眼位置=\(face.leftEyePosition)")
            }
            if face.hasRightEyePosition {
                print("右眼位置=\(face.rightEyePosition)")
            }
            if face.hasMouthPosition {
                print("检测到嘴巴=\(face.mouthPosition)")
            }
            if face.hasFaceAngle {
                print("人脸旋转角度=\(face.faceAngle)")
            }
        }

    }
image.png

坐标转换

其中涉及到一个UIKit和CoreImage的坐标转换,UIKit的坐标是左上角为顶点(0,0)向右下方展开,而CoreImage是以左下角为顶点(0,0)向右上方展开的,如图所示:


image.png

由于取出来的CIImage图片是原始尺寸,但是图片真实显示出来的size受到容器的限制,可能拉伸或者压缩,所以坐标转换后还需要根据比例来计算出人脸实际显示的大小,然后再加框框。

总结

还有些特征点可以检测,但是我试了一下,不是特别好使,总是检测不到,比如微笑和闭眼的状态,如果你发现了问题所在,请告诉我,谢谢。
参考文章

上一篇下一篇

猜你喜欢

热点阅读