[ARKit]7-ARKit1.5的图片识别功能

说明

ARKit系列文章目录node

ARKit1.5新增功能

  • iOS 11.3 上的视频分辨率提高至 1080p,其他不变;
  • 新增竖直平面识别ARWorldTrackingConfiguration.PlaneDetection;
  • 新增ARPlaneAnchor中粗略平面估计,见ARPlaneAnchor;
  • 新增ARSession.setWorldOrigin方法能够从新设置世界坐标原点;
  • 新增图片识别能力,示例代码见Recognizing Images in an AR Experience
  • ARsession被打断后,可尝试恢复追踪.详见sessionShouldAttemptRelocalization代理方法;

还有一个加强功能:swift

  • 打了断点,再恢复后,session的VIO(视觉惯性里程计)也会继续工做了.原来放置在世界坐标系中的虚拟物体仍然是可见的.

图片识别

这个功能使用起来其实很是简单,AR功能启动时设置要识别的图片,而后在回调方法中处理识别到的锚点就能够了.数组

// 加载要识别的图片组
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
    fatalError("Missing expected asset catalog resources.")
}

let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = referenceImages //设置识别项
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])

复制代码
// MARK: - ARSCNViewDelegate (Image detection results)
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    // 判断识别到的锚点类型
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    let referenceImage = imageAnchor.referenceImage //获取锚点对应的图片
    updateQueue.async {
        
       // 建立一个平面来显示检测到的图片(与图片相同大小)
        let plane = SCNPlane(width: referenceImage.physicalSize.width,
                             height: referenceImage.physicalSize.height)
        let planeNode = SCNNode(geometry: plane)
        planeNode.opacity = 0.25
        
        /* `SCNPlane`在它的本地坐标系是竖直的, 但`ARImageAnchor`会假设图片在自身本地坐标系中是水平的,因此要旋转平面. */
        planeNode.eulerAngles.x = -.pi / 2
        
        /* 图片锚点在初始化后是再也不被追踪的,因此建立一个动画效果以显示平面出现了. */
        planeNode.runAction(self.imageHighlightAction)
        
        // 添加到场景中
        node.addChildNode(planeNode)
    }
   
}
// 高亮动画
var imageHighlightAction: SCNAction {
    return .sequence([
        .wait(duration: 0.25),
        .fadeOpacity(to: 0.85, duration: 0.25),
        .fadeOpacity(to: 0.15, duration: 0.25),
        .fadeOpacity(to: 0.85, duration: 0.25),
        .fadeOut(duration: 0.5),
        .removeFromParentNode()
        ])
}
复制代码

参考图片referenceImages

参考图片就是要被识别的图片,须要放置在Xcode的素材文件夹asset catalog中:session

  1. 打开项目的asset catalog,点击添加按钮(+)来添加新的AR资源组;
  2. Finder中拖拽图片到资源组中;
  3. 须要在检查器中给每张图片指定一个物理尺寸,还能够设定一个描述性的名字(可选);

注意图片识别的能力: 须要精心挑选,设计,配置图片来达到更好的可靠性和性能表现:app

  • 图片的物理尺寸设置应尽量精确.ARKit须要根据这个值来肯定真实世界中的图片到相机的距离,设置不当会致使ARImageAnchor到相机的距离出错;
  • 当向Xcode的素材文件夹asset catalog添加图片时,应注意Xcode提供的图片质量预估警告.高对比度的图片在图片识别中效果最好;
  • 使用平面图片来检测.若是要识别的图片不是平面的,好比是酒瓶上的标签,那ARKit可能不会识别或者给出错误的锚点位置;
  • 考虑你的图片在不一样光照下的表现.若是图片是打印在光滑的纸上或者显示在屏幕上,这些平面上的反光可能会妨碍识别;

应用最佳实践

使用识别出的图片做为AR场景的参照系.使用识别出的图片来锚定虚拟场景,而不是再让用户选择场景的摆放位置,或直接粗暴地摆放在用户的场景中.你甚至可使用多个识别图片.例如,一个给零售店用的app,能够经过识别贴在门两侧的海报(门左边一个海报贴图,右边一个)来算出门的位置,从而建立出一个虚拟角色并从门中走出来.async

注意:可使用ARSession setWorldOrigin(relativeTransform:)方法来重设世界坐标系,这样就能够放置全部锚点和其余相关内容到你选择的参考点上.post

设计AR流程,将识别出的图片做为虚拟内容的起始点.ARKit不会再追踪已探测到的图片的位置和朝向.若是你试图让虚拟内容一直紧贴在识别出的图片上,那么可能会显示不正确.应该作的是,使用识别出的图片做为参照系,来开始一个动态场景.例如你的app须要识别出科幻电影的海报,而后会有几个太空船从海报中飞出来,并飞到周围环境中去.性能

考虑好什么时候容许图片检测以触发(或重复)AR交互.对于配置session configuration中的detectionImages数组中的每张参考图片,ARKit都只会添加一个图片锚点.若是你的AR流程中向一个识别出的图片添加了虚拟内容,那这个动做默认状况下只会发生一次.要想再体验一次这个流程,能够调用session的remove(anchor:)方法来移除对应的ARImageAnchor.移除该锚点以后,ARKit会在下次识别出图片后,再添加一个新的锚点. 例如,仍是前面科幻电影海报的例子,当第一次的动画正在播放时,太空船正从电影海报中飞出来时,你确定不想要再出现一个一样的.要等到动画播放完成后再移除锚点,这样当用户再对准海报时,就能够再触发一次动画.动画

ARReferenceImage的建立

除了前面讲到的ARReferenceImage.referenceImages(inGroupNamed:bundle:)方法能够从素材中加载图片做为参考图片外,还有另外两个建立方法:ui

- (instancetype)initWithCGImage:(CGImageRef)image orientation:(CGImagePropertyOrientation)orientation physicalWidth:(CGFloat)physicalWidth;
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer orientation:(CGImagePropertyOrientation)orientation physicalWidth:(CGFloat)physicalWidth;
复制代码

这两种方法能够分别从CGImageRefCVPixelBufferRef中建立参考图片,这样就灵活多了.