iOS开发 · iOS音视频开发 - ARKit 教学:2D 图像识别功能

1,176 阅读6分钟

前提条件

本篇教学需要你对于我们先前的 ARKit 教学文章有深入了解。如果你对于 ARKit 有点陌生,请先阅读 ARKit 教学系列文章

本次教学亦需要 9.3 或是更新版本的 Xcode,以及运行 iOS 11.3 或更高版本的苹果装置。

事不宜迟,我们开始吧!

你将会制作什麽 App

我们将制作一个 ARKit 图像识别 App。这个 App 在任何时候侦测到可识别的图像,就会执行一连串动画来显示图像中物件的实际位置及大小,并以一个 UILabel 来显示图像的名称。如果你不了解我的意思,下图可以给你一些概念。

image

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:1012951431,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

开始制作

首先,从这裡下载初始专案吧。初始专案已经有预先设置好的 UI 元件和 Action 方法,这样我们就可以专注在 ARKit 图像识别的核心功能。

注意:如果你希望了解更多关于如何制作专业的 UI 元件,欢迎随时参阅 《iOS 11 App 程式设计实战心法》 及更进阶的 《iOS 11 App程式设计进阶攻略》

Xcode Demo storyboard

下载了初始专案后,在你的 iOS 装置上 Build 及 Run。App 会要求允许使用你的相机,点击 OK 来允许相机权限。

好,现在让我们为 ARKit 图像识别功能准备些图片吧。

使 ARKit 可以进行图像识别

为了让 ARKit 识别图像,你先要提供两项东西:

  1. App 需要识别的图像
  2. 图像物件的实际大小

我们就从提供图像开始吧。在初始专案中,点击 Assets.xcassets。接著,你应该能够看到 AR Resources 群组。点击群组,你会看到裡面有三张图像。

Xcode image asset

你也可以拖曳自己的图片到这个群组之中。但一定要给图像一个描述性名称。

就如早前提到的,将图像放入专案中只是准备 ARKit 图像识别的第一步。此外,你还需要提供图像物件的实际大小。

下一个段落将谈谈关于图像物件的实际大小。

图像物件的实际大小

ARKit 需要知道图像物件的实际大小,来计算相机与图像之间的距离。物件大小不正确会导致 ARImageAnchor 错误计算物件与相机之间的距离。

记得在每次为 ARKit 识别添加新的图像时,都要提供图像物件的实际大小。这个数值应该反映出图像物件被测量时的大小。例如,”Book” 图像物件有以下的实际大小:

AR Reference Image

这是在一台 15.4 吋的 MacBook Pro 的 Preview 预览时,Book 图像物件的实际大小。你可以在图像的 Attributes Inspector 栏位中设定大小。

图像属性

ARKit 的图像识别能力可能会随图像的属性而改变。看看 AR Resources 群组裡的图像,你会看到 “Book” 图像有两个警告讯息。在添加图像时,请注意一下这些警告讯息。图像有高对比区块时,侦测效果会比较好。

image

“Snow Mountain” 和 “Trees In The Dark” 图像没有黄色警告,表示 ARKit 认为这些图像容易被识别。

image

但无论有或没有黄色警告也好,你最好还是先测试一下你打算使用的图像,从而测试出哪些图像是容易被识别的。

接下来,我们要开始动手写程式码囉。

为图像识别设定组态

我们将设定场景视图的组态 (Configuration) 来侦测 AR Resources 群组裡的图像。组态将须重设追踪,并移除现有的锚点运行选项。以组态执行了场景视图 Session 之后,我们就要更新 UILabel 上的文字描述。

开启 ViewController.swift,然后插入以下的方法到 View Controller 类别:

func resetTrackingConfiguration() {
    guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { return }
    let configuration = ARWorldTrackingConfiguration()
    configuration.detectionImages = referenceImages
    let options: ARSession.RunOptions = [.resetTracking, .removeExistingAnchors]
    sceneView.session.run(configuration, options: options)
    label.text = "Move camera around to detect images"
}

接下来,分别在 viewWillAppear(_:)resetButtonDidTouch(_:) 方法中呼叫其 resetTrackingConfiguration() 方法。

以 ARImageAnchor 识别图像

现在,我们要以一个白色透明平面覆盖新侦测的图像。这个平面会反映出新侦测图像的形状、大小、和图像到相机间的距离。当一个新节点被映到给定的锚点时,这个平面覆盖 UI 就会显示出来。

注意: 锚点是 ARImageAnchor 的型态,并使用于 renderer(_:didAdd:for:) 方法中。

这样更新 renderer(_:didAdd:for:) 方法:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    let referenceImage = imageAnchor.referenceImage
        let imageName = referenceImage.name ?? "no name"
        
    let plane = SCNPlane(width: referenceImage.physicalSize.width, height: referenceImage.physicalSize.height)
    let planeNode = SCNNode(geometry: plane)
    planeNode.opacity = 0.20
    planeNode.eulerAngles.x = -.pi / 2
    
    planeNode.runAction(imageHighlightAction)
}

这个平面节点设定为执行一个 SCNAction 序列,此序列将执行一个淡入与淡出的动画效果。

现在有了这个平面节点和被侦测图像的名称,我们会将平面节点添加至节点参数,并设定 UILabel 的文字,以展示被识别图像的名称。在 planeNode.runAction(imageHighlightAction) 后面插入以下程式码:

node.addChildNode(planeNode)
DispatchQueue.main.async {
    self.label.text = "Image detected: \"\(imageName)\""
}

好了!你已经成功建立了一个全新的 ARKit 图像识别 App。

测试示范 App

为了功能示范,你可以将所有 AR Resources 群组内的图像列印出来,或是在 Preview 中开启图片。

ARKit Image Recognition Demo

下一阶段,让我们将 3D 物件覆盖在被侦测的图像上吧。

覆盖 3D 物件到被侦测的图像上

我们已经将被侦测图像物件的实际大小和位置视觉化,现在来将 3D 物件覆盖在图像之上吧。

首先,为以下的程式码加入注解,让我们可以专注把 3D 物件覆盖在图像上:

let planeNode = self.getPlaneNode(withReferenceImage: imageAnchor.referenceImage)
planeNode.opacity = 0.0
planeNode.eulerAngles.x = -.pi / 2
planeNode.runAction(self.fadeAction)

node.addChildNode(planeNode)

接著,利用下列程式码取代 TODO: Overlay 3D Object 注解:

let overlayNode = self.getNode(withImageName: imageName)
overlayNode.opacity = 0
overlayNode.position.y = 0.2
overlayNode.runAction(self.fadeAndSpinAction)

node.addChildNode(overlayNode)

现在,在图像侦测的过程中,你会看到 SceneKit 节点执行一个动画,从图像向你的方向淡入、旋转、并淡出。

image

总结

恭喜你完成这次的教学内容!我希望你享受这次的教学,并从中学习到一些有价值的东西。欢迎分享本次教学给你的朋友,这样他们也可以从中获益!

最后,你可以在 Github 上 下载完整的 Xcode 专案档

文末推荐:iOS热门文集