前段时间研究人脸识别,正好也在学习swift,所以真好都总结一下。
步骤;
- 创建特征检测器CIDetector,检测类型人脸,高精度。
- 调用检测器的featuresInImage方法,传入图片,会得到一个人脸的数组。
- 遍历人脸数组,转为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受到容器的限制,可能拉伸或者压缩,所以坐标转换后还需要根据比例来计算出人脸实际显示的大小,然后再加框框。
总结
还有些特征点可以检测,但是我试了一下,不是特别好使,总是检测不到,比如微笑和闭眼的状态,如果你发现了问题所在,请告诉我,谢谢。
参考文章
网友评论