专栏首页相约机器人使用CoreML和ARKit进行人脸检测和识别

使用CoreML和ARKit进行人脸检测和识别

作者 | Omar M'Haimdat

来源 | Medium

编辑 | 代码医生团队

创建单视图应用程序

首先,需要使用单个视图应用创建一个iOS项目:

创建一个视图应用程序

现在已经拥有了自己的项目,并且因为不喜欢使用故事板,所以应用程序以编程方式完成,这意味着没有按钮或开关切换,只需要纯粹的代码。

必须删除main.storyboard并设置您的AppDelegate.swift文件,如下所示:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.makeKeyAndVisible()
        let controller = ViewController()
        window?.rootViewController = controller
        
        return true
    }

确保从部署信息中删除故事板“Main”。

创建场景并将其添加到子视图

只有一个ViewController,它将是应用程序的主要入口点。

在这个阶段,需要导入ARKit并实例化一个ARSCNView自动渲染来自设备相机的实时视频作为场景背景。它还会自动移动其SceneKit摄像头以匹配设备的真实世界移动,这意味着不需要锚点来跟踪我们添加到场景中的对象的位置。

需要给它屏幕边界,以便摄像机会话占据整个屏幕:

let sceneView = ARSCNView(frame: UIScreen.main.bounds)

在该ViewDidLoad方法中,将设置一些内容,例如委托,还需要查看帧统计信息以监视帧丢弃:

self.view.addSubview(sceneView) // add the scene to the subview
sceneView.delegate = self // Setting the delegate for our view controller
sceneView.showsStatistics = true // Show statistics

开始一个ARFaceTrackingConfiguration会话

现在需要开始一个会话ARFaceTrackingConfiguration,这个配置让可以访问仅适用于iPhone X,Xs和Xr的前置TrueDepth摄像头。以下是Apple文档中的更详细说明:

面部跟踪配置会根据设备的前置摄像头检测用户的脸部。运行此配置时,AR会话将检测用户的面部(如果在前置摄像头图像中可见),并在其锚点列表中添加表示面部的ARFaceAnchor对象。每个面部锚点提供有关面部位置和方向,其拓扑以及描述面部表情的特征的信息。

ViewDidLoad方法应如下所示:

override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(sceneView)
        sceneView.delegate = self
        sceneView.showsStatistics = true
        guard ARFaceTrackingConfiguration.isSupported else { return }
        let configuration = ARFaceTrackingConfiguration()
        configuration.isLightEstimationEnabled = true
        sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }

训练人脸识别模型

有多种方法可以创建与CoreML兼容的.mlmodel文件,这些是常见的:

  1. Turicreate:它是python库,简化了自定义机器学习模型的开发,更重要的是,可以将模型导出到可由Xcode解析的.mlmodel文件中。
  2. MLImageClassifierBuilder():它是一个内置的解决方案,提供Xcode开箱即用,可以访问几乎一个拖放界面来训练一个相对简单的模型。

https://pypi.org/project/turicreate/?source=post_page---------------------------

MLImageClassifierBuilder

已经创建了多个模型来测试这两个解决方案,因为没有大数据集,决定使用MLImageClassifierBuilder()和一组67个图像,这些图像是'Omar MHAIMDAT '和一组261 在unsplash上找到的'未知'的面孔。

https://unsplash.com/

打开游乐场并编写此代码:

import CreateMLUI
 
let builder = MLImageClassifierBuilder()
builder.showInLiveView()

建议将最大迭代次数设置为20并添加裁剪增强,这将为每个图像添加4个裁剪图像实例。

捕获相机帧并将其注入模型

需要使用场景委托来扩展ViewController ARSCNViewDelegate。需要两个委托方法,一个用于设置面部检测,另一个用于在检测到面部时更新场景:

人脸检测:

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        
        guard let device = sceneView.device else {
            return nil
        }
        
        let faceGeometry = ARSCNFaceGeometry(device: device)
        
        let node = SCNNode(geometry: faceGeometry)
        
        node.geometry?.firstMaterial?.fillMode = .lines
        
        return node
    }

不幸的是,当睁开眼睛或嘴巴时,场景不会更新。在这种情况下,需要相应地更新场景。

更新场景:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        
        guard let faceAnchor = anchor as? ARFaceAnchor,
            let faceGeometry = node.geometry as? ARSCNFaceGeometry else {
                return
        }
        
        faceGeometry.update(from: faceAnchor.geometry)
}

采用整个面几何和映射,并更新节点。

获取相机框架:

这很有趣,因为ARSCNView继承自AVCaptureSession,意味着可以得到一个cvPixelFuffer可以提供模型。

这是从sceneView属性中获取它的简单方法:

guard let pixelBuffer = self.sceneView.session.currentFrame?.capturedImage else { return }

将相机框架注入模型:

现在可以检测到面部并拥有每个相机框架,已准备好为模型提供一些内容:

guard let model = try? VNCoreMLModel(for: FaceRecognition3().model) else {
            fatalError("Unable to load model")
        }
        
        let coreMlRequest = VNCoreMLRequest(model: model) {[weak self] request, error in
            guard let results = request.results as? [VNClassificationObservation],
                let topResult = results.first
                else {
                    fatalError("Unexpected results")
            }
 
            DispatchQueue.main.async {[weak self] in
                print(topResult.identifier)
            }
        }
        
        guard let pixelBuffer = self.sceneView.session.currentFrame?.capturedImage else { return }
        
        
        let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
        DispatchQueue.global().async {
            do {
                try handler.perform([coreMlRequest])
            } catch {
                print(error)
            }
        }

在识别的脸部上方显示名称

最后也可能是最令人沮丧的部分是在识别出的脸部上方投射3D文本。如果考虑一下,配置就不如ARWorldTrackingConfiguration能够访问众多方法和类的功能那样强大。使用的是前置摄像头,可以实现的功能很少。

尽管如此,仍然可以在屏幕上投影3D文本,但它不会跟踪面部运动并相应地进行更改。

let text = SCNText(string: "", extrusionDepth: 2)
let font = UIFont(name: "Avenir-Heavy", size: 18)
text.font = font
let material = SCNMaterial()
material.diffuse.contents = UIColor.black
text.materials = [material]
text.firstMaterial?.isDoubleSided = true
        
let textNode = SCNNode(geometry: faceGeometry)
textNode.position = SCNVector3(-0.1, -0.01, -0.5)
textNode.scale = SCNVector3(0.002, 0.002, 0.002)
textNode.geometry = text

现在有了SCNText对象,需要使用相应的face更新它并将其添加到rootNode:

      let coreMlRequest = VNCoreMLRequest(model: model) {[weak self] request, error in
            guard let results = request.results as? [VNClassificationObservation],
                let topResult = results.first
                else {
                    fatalError("Unexpected results")
            }
 
            DispatchQueue.main.async {[weak self] in
                print(topResult.identifier)
                if topResult.identifier != "Unknown" {
                    text.string = topResult.identifier
                    self!.sceneView.scene.rootNode.addChildNode(textNode)
                    self!.sceneView.autoenablesDefaultLighting = true
                }
            }
        }

最后结果:

这是面部检测和识别的最终结果。

该项目可从Github帐户下载

https://github.com/omarmhaimdat/WhoAreYou

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为你的IDE集成AI,解放双手,我推荐这款神器!

    我们平时写代码的时候,多少都会依赖编辑器的代码补全功能,敲几个字母就能补全一个词。可是这么多年过去了,语言升级了很多次,而代码提示却没有升级,还是只能限定在一个...

    用户5224393
  • 深入理解iOS Crash Log

    USB连接设备,接着在XCode菜单栏依次选择:Window -> Devices And Simulators,接着选择View Device Logs

    用户2932962
  • React-Native踩坑记

    最近使用react-native参与开发了个应用,记录下其中踩的一些坑。本人使用的是mac电脑进行开发,本文仅对此平台进行记录?

    嘉明
  • react-native修改APP的名字与图标

    进入:android/app/src/main/AndroidManifest.xml,

    踏浪
  • IOS 学习笔记 快速解决is running iOS 12.3 (16F156), which may not be supported by this version of Xcode.

    is running iOS 12.3 (16F156), which may not be supported by this version of Xcod...

    Python疯子
  • 用过了那么多开发者工具,这个才真正好用,AI辅助编程,释放你的双手!

    我们平时写代码的时候,多少都会依赖编辑器的代码补全功能,敲几个字母就能补全一个词。可是这么多年过去了,语言升级了很多次,而代码提示却没有升级,还是只能限定在一个...

    江南一点雨
  • iOS xib控件变成框框 An internal error occurred

    an internal error occured.Editing functionality may be limited

    赵哥窟
  • 为你的IDE集成AI,解放双手,我推荐这款神器!

    我们平时写代码的时候,多少都会依赖编辑器的代码补全功能,敲几个字母就能补全一个词。可是这么多年过去了,语言升级了很多次,而代码提示却没有升级,还是只能限定在一个...

    JAVA葵花宝典
  • 为你的IDE集成AI,解放双手,我推荐这款神器!

    我们平时写代码的时候,多少都会依赖编辑器的代码补全功能,敲几个字母就能补全一个词。可是这么多年过去了,语言升级了很多次,而代码提示却没有升级,还是只能限定在一个...

    kirito-moe

扫码关注云+社区

领取腾讯云代金券