专栏名称: 唤之
目录
相关文章推荐
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  2 天前  
待字闺中  ·  DeepSeek 爆火带来的大变化 ·  1 周前  
程序员的那些事  ·  李彦宏自曝开源真相:从骂“智商税”到送出“史 ... ·  3 天前  
51好读  ›  专栏  ›  唤之

Find me - 用 ARKit 找人

唤之  · 掘金  · 程序员  · 2017-12-09 03:04

正文

引言

从 Apple 发布 ARKit 框架起,我就一直想学习并做点好玩的东西,后来就勾搭了 滑滑鸡 大佬来 上海 Code 沙龙第八次活动 讲他做的 ARGitHubCommits ,学习了一些 ARKit 的基础知识,后来持续跟进了一波,看了很多 张嘉夫 大佬的 ARKit 文章,也看了一些 ARKit 开源的项目。那会微博上有一个 ARKit 不停的弹 Windows 告警对话框的动态图特别火,看到的时候我就想,弹出来的这一堆对话框好像一条路径啊,这也是 Find me 这个 App 最初的灵感来源。

探索

后来就想利用这个特性做一些寻路的方面的探索,最开始是想做在家里找东西,脑洞如下:

  • 在家里找一个位置固定不变的物品(比如电视机)做为参考点。
  • 为每件物品录制一条路径到这个参考点。
  • 想找某件物品的时候先找到这个参考点,然后就可以通过之前录制的路径找到这件物品了。

但是发现有两个特别大的痛点:

  • 东西位置经常会变,路径也要跟着变。
  • 找不到的东西往往是乱放的东西,所以当然也没有路径记录一说。

所以这个脑洞就被我 Pass 了,项目也搁置了一段时间。

然后有一天,我约了朋友去商场吃饭。他先到了店里,但是我确始终找不到这个店,问了半天才在一个很隐蔽的角落找到了这个店。约完回家之后灵感突发,这个场景完全可以用之前找东西的思路来做啊:

  • 先到商场的人找一个好找的位置,比如商场北门。
  • 从这个位置开始记录一条到门店的路径,并分享给后来的朋友。
  • 后来的朋友找到这条路径的起点,也就是之前说的商场北门,打开先到的人分享的路径即可沿着路径找到约好见面的门店。

关键问题:从使用场景来说,没有痛点。

这也是我今天文章内容的主角 - Find me 实现的功能。

目前这个 App 已经发布上架: Find me ,而且代码已经开源了,地址在: mmoaay/Findme (喜欢的话记得点个 Star),为什么选择开源呢?因为只是一个创意,并没有太多的技术壁垒,而且目前在技术上确实存在两个问题:

  • 路径记录和寻找过程中 ARKit 的 Session 不能被打断,因为恢复之后的虚拟坐标会产生极大偏差,导致虚拟路径进入不可控状态。
  • ARKit 目前不稳定,虚拟坐标系会抖动,这样就会导致虚拟路径有偏移,而且距离越远,偏差越大。

产生这两个问题的原因主要都在虚拟世界坐标上,我们都知道, ARKit 初始化的时候,会基于你当前位置为世界原点,建立了一个虚拟世界坐标系:

所以,Find me 记录并分享出来的路径,对 ARKit 虚拟世界的坐标系有两个基本要求:

  • 记录路径和根据路径找人时虚拟世界的原点一定要映射到现实世界中的同一个点,也就是分享和寻找的起点位置要是同一个。
  • 虚拟世界的水平垂直方向要和现实世界一样。

优化

对于这两个问题,我也做了一些优化。

目前失败的两个优化

基于定位优化

思路很简单:根据定位将路径分段记录,并修正虚拟路径。相当于给虚拟路径加一个现实世界的坐标修正。

实践之后发现:定位比 ARKit 还不准,尤其在商场内,基于 WiFi 的定位基本上能让你的位置到处跳。Pass!

基于距离优化

这个方案的思路是:根据你在虚拟世界移动的距离分段记录路径。

实践之后问题也来了: ARKit 的初始化太慢了,在我的 iPhone 7 上需要的时间 足足有 3 秒 …而且 ARKit 的 Seesion 还不能并发,因为摄像头只有一个,只有上一个结束了,下一个才能开始,最后发现路径根本没法记录…

成功优化

ARKit 使用优化

设置 ARWorldTrackingConfiguration worldAlignment .gravityAndHeading

首先我们来看一下 WorldAlignment 类型:

/**
Enum constants for indicating the world alignment.
*/
@available(iOS 11.0, *)
public enum WorldAlignment : Int {

        
    /** Aligns the world with gravity that is defined by vector (0, -1, 0). */
    case gravity

        
    /** Aligns the world with gravity that is defined by the vector (0, -1, 0)
     and heading (w.r.t. True North) that is given by the vector (0, 0, -1). */
    case gravityAndHeading

        
    /** Aligns the world with the camera’s orientation. */
    case camera
}
  • .gravity :只有重力,也就是坐标系的垂直方向和真实世界一致,但是水平方向不定。
  • .gravityAndHeading :重力和指北,垂直和水平方向都和真实世界一致。
  • .camera :摄像头方向,也就是坐标系和手机保持一致。

所以这就是我们选择 .gravityAndHeading 的原因。这样一来,根据路径找人的那个人就只需要找到路径起始点的真实位置即可,手机的方向就不重要了,极大降低的使用门槛。

提供路径起始点图片

这个优化的内容是: 分享路径的时候提供一张起始点的照片 。这样拿到路径的人就拿图片和自己所在的场景做一个大致的比对来确定分享路径的人当时的位置,看一下使用效果:

这张照片我们直接用 ARKit sceneView.session.currentFrame 属性获取,如下:

if let currentFrame = sceneView.session.currentFrame, let image = UIImage(pixelBuffer: currentFrame.capturedImage, context:CIContext()) {
}

使用建议

基于上面说的情况,如果你在日常生活中确实想使用 Find me,下面是一些非常 重要的使用建议

  • 如果在记录或者寻路过程中,有新消息, 千万不要切出去看 ,毕竟商场内导航也就是 10 分钟左右的事情,正常晚 10 分钟回复消息也没事。
  • 寻路的人一定要 找准路径初始点 !非常重要!这个直接决定了路径终点位置的准确度。

其他一些比较有趣的技术点

路径中的箭头实现

先看一下效果:

这个技术点包含两个部分:

  • 怎么绘制箭头?
  • 如果让箭头指向下一个点的位置?

怎么绘制箭头?

首先,我们生成一个如下图形状的 UIBezierPath

代码如下:

private static func vertexCoordinates() -> [CGPoint] {
    return [CGPoint(x: 0, y: 0),
            CGPoint(x: 20, y: 0),
            CGPoint(x: 20, y: 10),
            CGPoint(x: 10, y: 10),
            CGPoint(x: 10, y: 20),
            CGPoint(x: 0, y: 20)
    ]
}
    
private static func arrowPath() -> UIBezierPath {
    let






请到「今天看啥」查看全文