美文网首页
Swift人脸检测

Swift人脸检测

作者: 疯狂的面条 | 来源:发表于2021-01-12 18:09 被阅读0次
    import UIKit
    
    class FaceCaptureViewController: ViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
        
        var popClosure: (() -> Void)?
        
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            self.navigationController?.setNavigationBarHidden(true, animated: true)
        }
        var countDown: Int = 3
        let gcdTimer = DispatchSource.makeTimerSource()
        override func viewDidLoad() {
            super.viewDidLoad()
            preview.frame = self.view.bounds
            self.view.layer.addSublayer(preview)
            session.startRunning()
            view.addSubview(tipLabel)
            view.addSubview(tipTime)
            tipTime.snp.makeConstraints { (make) in
                make.centerX.equalToSuperview()
                make.top.equalTo(tipLabel.snp.bottom).offset(20)
                make.size.equalTo(CGSize(width: 50, height: 50))
            }
            
            let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity")
            opacityAnimation.values = [0.5, 0.3, 0.2]
            opacityAnimation.duration = 1
            opacityAnimation.repeatCount = self.countDown.float
            opacityAnimation.isRemovedOnCompletion = true
            opacityAnimation.fillMode = .forwards
            tipTime.layer.add(opacityAnimation, forKey: "groupAnimation")
            
            gcdTimer.schedule(wallDeadline: DispatchWallTime.now(), repeating: DispatchTimeInterval.seconds(1), leeway: DispatchTimeInterval.seconds(0))
    
            gcdTimer.setEventHandler {
                DispatchQueue.main.async {
                    self.countDown -= 1
                    self.tipTime.text = "\(self.countDown)"
                }
            }
            gcdTimer.resume()
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
                if !self.isPop {
                    self.letgo()
                }
            }
        }
        private var isPop: Bool = false
        private func letgo() {
            isPop = true
            self.session.stopRunning()
            self.gcdTimer.cancel()
            self.popClosure?()
            self.popViewController()
        }
        
        // ui
        lazy var tipLabel: UILabel = {
            let l = UILabel(frame: CGRect(x: 20, y: 50, width: ScreenWidth - 40, height: 80))
            l.backgroundColor = UIColor(white: 0.2, alpha: 0.5)
            l.textAlignment = .center
            l.textColor = .init(hex: "ddd")
            l.font = .systemFont(ofSize: 28, weight: .bold)
            l.text = "实名认证中"
            l.cornerRadius = 2
            return l
        }()
        lazy var tipTime: UILabel = {
            let b = UILabel()
            b.backgroundColor = .init(hex: "293874")
            b.cornerRadius = 25
            b.layer.opacity = 0.2
            b.textColor = .white
            b.text = "2"
            b.textAlignment = .center
            b.font = .systemFont(ofSize: 24, weight: .bold)
    //        b.setTitle("3", for: .normal)
            
            return b
        }()
        
        // AVFoundation
        
        lazy var preview: AVCaptureVideoPreviewLayer = {
            let p = AVCaptureVideoPreviewLayer(session: session)
            p.videoGravity = .resizeAspectFill
            return p
        }()
        lazy var session: AVCaptureSession = {
            let session = AVCaptureSession()
            session.canSetSessionPreset(.vga640x480)
            if let input = captureInput {
                session.addInput(input)
                session.addOutput(captureOutput)
                session.addOutput(captureImageOutput)
            }
            return session
        }()
        lazy var device: AVCaptureDevice? = {
            let dss = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .front)
            return dss.devices.first
        }()
        lazy var captureInput: AVCaptureDeviceInput? = {
            if let d = device {
                let ci = try? AVCaptureDeviceInput(device: d)
                return ci
            }
            return nil
        }()
        lazy var captureOutput: AVCaptureVideoDataOutput = {
            let output = AVCaptureVideoDataOutput()
            output.alwaysDiscardsLateVideoFrames = true
            output.setSampleBufferDelegate(self, queue: queue)
            output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
            return output
        }()
        lazy var captureImageOutput: AVCapturePhotoOutput = {
            let o = AVCapturePhotoOutput()
            o.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey:AVVideoCodecJPEG])], completionHandler: nil)
            
            return o
        }()
        
        lazy var queue: DispatchQueue = {
            let q = DispatchQueue(label: "cameraQueue")
            return q
        }()
        
        deinit {
            print("==============deinit")
    //        gcdTimer.cancel()
        }
    
    }
    
    extension FaceCaptureViewController {
        
        func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
             
            guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
            CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0))
            
            let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
            let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
            let width = CVPixelBufferGetWidth(imageBuffer)
            let height = CVPixelBufferGetHeight(imageBuffer)
            
            let colorSpace = CGColorSpaceCreateDeviceRGB()
            guard let newContext = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) else {
                return
            }
            newContext.concatenate(CGAffineTransform(rotationAngle: CGFloat.pi/2))
            guard let newImage = newContext.makeImage() else { return }
            
            let image = UIImage(cgImage: newImage, scale: 1, orientation: .leftMirrored)
            performSelector(onMainThread: #selector(detectFace(_:)), with: image, waitUntilDone: true)
            Thread.sleep(forTimeInterval: 0.2)
        }
        
        @objc func detectFace(_ image: UIImage) {
            guard let cgImage = image.cgImage else { return }
            let ciImage = CIImage(cgImage: cgImage)
            let context = CIContext()
            let detector = CIDetector(ofType: CIDetectorTypeFace, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
            
            var exifOrientation: Int = 1
            switch image.imageOrientation {
            case .up:
                exifOrientation = 1
            case .down:
                exifOrientation = 3
            case .left:
                exifOrientation = 8
            case .right:
                exifOrientation = 6
            case .upMirrored:
                exifOrientation = 2
            case .downMirrored:
                exifOrientation = 4
            case .leftMirrored:
                exifOrientation = 5
            case .rightMirrored:
                exifOrientation = 7
            default:
                break
            }
            // options要在这里设置,在detector初始化的地方设置无效
            guard let features = detector?.features(in: ciImage, options: [CIDetectorImageOrientation: exifOrientation, CIDetectorEyeBlink: true]) as? [CIFaceFeature] else { return }
            // 只取第一张人脸
            guard let faceObject = features.first else { return }
            
            if faceObject.hasMouthPosition && faceObject.hasLeftEyePosition && faceObject.hasRightEyePosition && !faceObject.leftEyeClosed && !faceObject.rightEyeClosed {
                print("------------------found face, lefteye closed=\(faceObject.leftEyeClosed) righteye closed=\(faceObject.rightEyeClosed)")
                // TODO: - 上传图片
                
                self.letgo()
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Swift人脸检测

          本文链接:https://www.haomeiwen.com/subject/buyeaktx.html