当前位置:   article > 正文

swift 人脸识别相关

swift avmetadatafaceobject 人脸是否完整

因为 基于GPUImage 的对象处理

方式一 基于系统 AVCaptureMetadataOutput  效率比较低

  1. lazy var myVideo: GPUImageVideoCamera = {
  2. //初始化相机,第一个参数表示相册的尺寸,第二个参数表示前后摄像头
  3. let myVideo:GPUImageVideoCamera = GPUImageVideoCamera.init(sessionPreset: AVCaptureSession.Preset.high.rawValue, cameraPosition: AVCaptureDevice.Position.back)
  4. //设置竖屏
  5. myVideo.outputImageOrientation = UIInterfaceOrientation.portrait
  6. // 设置前置摄像头和后置摄像头是否进行镜像
  7. myVideo.horizontallyMirrorRearFacingCamera = false
  8. myVideo.horizontallyMirrorFrontFacingCamera = true
  9. //竖屏方向
  10. myVideo.outputImageOrientation = .portrait
  11. //添加音频//该句可防止允许声音通过的情况下,避免录制第一帧黑屏闪屏(====)
  12. myVideo.addAudioInputsAndOutputs()
  13. myVideo.delegate = self
  14. //设置帧数
  15. // myVideo.frameRate = 60
  16. //人脸识别部分代码
  17. let metaDataOutput = AVCaptureMetadataOutput()
  18. if myVideo.captureSession.canAddOutput(metaDataOutput){
  19. myVideo.captureSession.addOutput(metaDataOutput)
  20. let supportTypes = metaDataOutput.availableMetadataObjectTypes
  21. if supportTypes.contains(AVMetadataObject.ObjectType.face){
  22. /*
  23. [metaDataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeFace]];
  24. [metaDataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  25. */
  26. metaDataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.face]
  27. metaDataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
  28. }
  29. }
  30. return myVideo
  31. }()

 

代理方法  GPUImageVideoCameraDelegate 计算出来的坐标基于 图片原始大小 所以需要 自己转换 我这里没有转换

  1. func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
  2. if metadataObjects.count != 0 {
  3. DDLOG(message:"数量:\(metadataObjects.count)")
  4. //AVMetadataObject 对象
  5. let faceObjc:AVMetadataFaceObject = metadataObjects.first! as! AVMetadataFaceObject
  6. let faceID = faceObjc.faceID
  7. let bounds = faceObjc.bounds
  8. let rollAngle = faceObjc.rollAngle //侧倾角 手机翻转的角度
  9. let yawAngle = faceObjc.yawAngle //偏转角 脸部偏转角度 正对着为 0
  10. DDLOG(message: faceObjc)
  11. let x = DeviceMaxWidth * bounds.origin.x
  12. let y = DeviceMaxHeight * bounds.origin.y
  13. let w = DeviceMaxWidth * bounds.size.width
  14. let h = DeviceMaxHeight * bounds.size.height
  15. }else{
  16. DDLOG(message: "没找到人脸")
  17. }
  18. }

方法二  基于 CIImage

简介 (网上copy 的 )

CoreImage framework组成

Apple 已经帮我们把image的处理分类好,来看看它的结构:

core Image.png


主要分为三个部分:

  • 定义部分:CoreImage 和CoreImageDefines。见名思义,代表了CoreImage 这个框架和它的定义。
  • 操作部分:
    • 滤镜(CIFliter):CIFilter 产生一个CIImage。典型的,接受一到多的图片作为输入,经过一些过滤操作,产生指定输出的图片。
    • 检测(CIDetector):CIDetector 检测处理图片的特性,如使用来检测图片中人脸的眼睛、嘴巴、等等。
    • 特征(CIFeature):CIFeature 代表由 detector处理后产生的特征。
  • 图像部分:
    • 画布(CIContext):画布类可被用与处理Quartz 2D 或者 OpenGL。可以用它来关联CoreImage类。如滤镜、颜色等渲染处理。
    • 颜色(CIColor): 图片的关联与画布、图片像素颜色的处理。
    • 向量(CIVector): 图片的坐标向量等几何方法处理。
    • 图片(CIImage): 代表一个图像,可代表关联后输出的图像。

在了解上述基本知识后,我们开始通过创建一个工程来带大家一步步验证Core Image的人脸识别特性。

人脸监测的步骤是:先获取图像,然后转成CIImage格式,利用CIFeature特征,使用探测器CIDetector拿到所有的人脸,然后在图中圈出,即可达到人脸识别的目的,关键代码如下:

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. let imgView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: DeviceMaxWidth, height: DeviceMaxHeight))
  4. imgView.image = image
  5. imgView.contentMode = UIViewContentMode.scaleAspectFit
  6. self.view.addSubview(imgView)
  7. let ciImage = CIImage.init(image: image)
  8. let faceDetector:CIDetector = CIDetector.init(ofType: CIDetectorTypeFace, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow,CIDetectorTracking:true])!
  9. let featureArray:[CIFeature] = faceDetector.features(in: ciImage!)
  10. DDLOG(message: "识别个数:\(featureArray.count)")
  11. /*
  12. 人脸识别是在原始图像上进行的,由于原始图像的分辨率比image view要高,因此需要设置image view的content mode为aspect fit(保持纵横比的情况下缩放图片)。为了合适的绘制矩形框,需要计算image view中人脸的实际位置与尺寸
  13. 还要注意的是,CoreImage与UIView使用两种不同的坐标系统(看下图),因此要实现一个CoreImage坐标到UIView坐标的转换。
  14. */
  15. // 转换坐标系
  16. let ciImageSize = ciImage?.extent.size
  17. var transform = CGAffineTransform(scaleX: 1, y: -1)
  18. transform = transform.translatedBy(x: 0, y: -CGFloat((ciImageSize?.height)!))
  19. for index in 0..<featureArray.count {
  20. let face:CIFaceFeature = featureArray[index] as! CIFaceFeature
  21. // 应用变换转换坐标
  22. var faceViewBounds = face.bounds.applying(transform)
  23. // //获取转换后的坐标
  24. // let faceBounds = self.transform(bgView: imgView, ciImage: ciImage, transfromRect: faceViewBounds)
  25. // 在图像视图中计算矩形的实际位置和大小
  26. let viewSize = imgView.bounds.size
  27. //计算宽高比例
  28. let scale = min(viewSize.width / (ciImageSize?.width)!, viewSize.height / (ciImageSize?.height)!)
  29. //放在imageview 之后 图片相对于背景 的 x y 坐标
  30. let offsetX = (viewSize.width - (ciImageSize?.width)! * scale) / 2
  31. let offsetY = (viewSize.height - (ciImageSize?.height)! * scale) / 2
  32. //获取缩放后的 脸部位置坐标
  33. faceViewBounds = faceViewBounds.applying(CGAffineTransform(scaleX: scale, y: scale))
  34. faceViewBounds.origin.x += offsetX
  35. faceViewBounds.origin.y += offsetY
  36. let faceVIew = UIView.init(frame: faceViewBounds)
  37. faceVIew.layer.borderWidth = 1
  38. faceVIew.layer.borderColor = UIColor.red.cgColor
  39. faceVIew.backgroundColor = UIColor.clear
  40. imgView.addSubview(faceVIew)
  41. DDLOG(message:"111\(imgView.bounds)" )
  42. DDLOG(message:"222\(String(describing: ciImage?.extent.size))" )
  43. DDLOG(message:"脸部相对于原始图片位置\(face.bounds)" )
  44. DDLOG(message:"脸部相对于 转换后图片位置\(faceViewBounds)" )
  45. if face.hasLeftEyePosition {
  46. //左眼位置
  47. print("左眼位置 \(face.leftEyePosition)")
  48. // 应用矩阵变换转换坐标
  49. let leftEyesPoint = face.leftEyePosition.applying(transform)
  50. //缩放后坐标
  51. var leftEyesScalPoint = leftEyesPoint.applying(CGAffineTransform(scaleX: scale, y: scale))
  52. leftEyesScalPoint.x += offsetX
  53. leftEyesScalPoint.y += offsetY
  54. let leftEyesVIew = UIView.init(frame: CGRect.init(origin: leftEyesScalPoint, size: CGSize(width: 20, height: 20)))
  55. leftEyesVIew.layer.cornerRadius = leftEyesVIew.width/2
  56. leftEyesVIew.layer.borderWidth = 1
  57. leftEyesVIew.layer.borderColor = UIColor.red.cgColor
  58. leftEyesVIew.backgroundColor = UIColor.clear
  59. imgView.addSubview(leftEyesVIew)
  60. }
  61. if face.hasRightEyePosition {
  62. //右眼位置
  63. print("右眼位置 \(face.rightEyePosition)")
  64. // 应用矩阵变换转换坐标
  65. let rightEyesPoint = face.rightEyePosition.applying(transform)
  66. //缩放后坐标
  67. var rightEyesScalPoint = rightEyesPoint.applying(CGAffineTransform(scaleX: scale, y: scale))
  68. rightEyesScalPoint.x += offsetX
  69. rightEyesScalPoint.y += offsetY
  70. let rightEyesVIew = UIView.init(frame: CGRect.init(origin: rightEyesScalPoint, size: CGSize(width: 20, height: 20)))
  71. rightEyesVIew.layer.cornerRadius = rightEyesVIew.width/2
  72. rightEyesVIew.layer.borderWidth = 1
  73. rightEyesVIew.layer.borderColor = UIColor.red.cgColor
  74. rightEyesVIew.backgroundColor = UIColor.clear
  75. imgView.addSubview(rightEyesVIew)
  76. }
  77. if face.leftEyeClosed {
  78. //左眼闭着
  79. print("左眼闭着")
  80. }
  81. if face.rightEyeClosed {
  82. //右眼闭着
  83. print("右眼闭着")
  84. }
  85. if face.hasMouthPosition {
  86. //嘴巴位置
  87. print("嘴巴位置e \(face.mouthPosition)")
  88. // 应用矩阵变换转换坐标
  89. let mouthPoint = face.mouthPosition.applying(transform)
  90. //缩放后坐标
  91. var mouthScalPoint = mouthPoint.applying(CGAffineTransform(scaleX: scale, y: scale))
  92. mouthScalPoint.x += offsetX
  93. mouthScalPoint.y += offsetY
  94. let mouthVIew = UIView.init(frame: CGRect.init(origin:mouthScalPoint, size: CGSize(width: 30, height: 30)))
  95. mouthVIew.layer.borderWidth = 1
  96. mouthVIew.layer.borderColor = UIColor.red.cgColor
  97. mouthVIew.backgroundColor = UIColor.clear
  98. imgView.addSubview(mouthVIew)
  99. }
  100. if face.hasSmile {
  101. //是否微笑
  102. print("在微笑")
  103. }
  104. if face.hasFaceAngle {
  105. //人脸角度
  106. print("人脸角度 \(face.faceAngle)")
  107. }
  108. if face.hasTrackingID {
  109. //获取追踪对象
  110. print("获取追踪对象ID \(face.trackingID)")
  111. }
  112. if face.hasTrackingFrameCount {
  113. //获取追踪对象个数
  114. print("获取追踪对象个数 \(face.hasTrackingFrameCount)")
  115. }
  116. }
  117. let backbtn = UIButton.init(frame: CGRect.init(x: 15, y:20, width: 30, height: 30))
  118. backbtn.setTitleColor(UIColor.red, for: .normal)
  119. backbtn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
  120. backbtn.setTitle("返回", for: .normal)
  121. backbtn.addTarget(self, action: #selector(btnEvent1), for: .touchUpInside)
  122. backbtn.tag = 0
  123. self.view.addSubview(backbtn)
  124. }

 

转载于:https://my.oschina.net/iceTear/blog/1607876

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/229397
推荐阅读
相关标签
  

闽ICP备14008679号