内容简介:本文是Ray Wenderlich上《ARKit by Tutorials》的读书笔记,主要讲内容概要和读后感ARKit by Tutorials中讲到了图像识别触发AR场景交互的一种特殊方法:利用
本文是Ray Wenderlich上《ARKit by Tutorials》的读书笔记,主要讲内容概要和读后感
ARKit by Tutorials中讲到了图像识别触发AR场景交互的一种特殊方法:利用 Vision Framework 来识别一些物体,然后在上面展示一些图片或动画.
还有利用地理定位和iBeacon触发AR交互的方法.
为什么用Vision
可能你会觉得奇怪:为什么不用ARKit自带的图片检测功能? 只要把参考图片的素材放好,设置好物理尺寸,ARKit就可以检测到图片,在WWDC2018上ARKit 2更是增加了图片追踪功能,效果非常好,识别率高,追踪稳定.
那是因为,ARKit目前自带的图片检测和追踪功能,有几点要求不太好满足:
- 图片不能过于相似;
- 图片的色彩直方图分布要均匀(不能是黑白的);
- 图片不能有大片相同颜色的区域;
- 图片的物理尺寸必须是已知且准确的.
比如下面的图片就不满足要求,虽然也能检测到,但追踪效果会差很多.
更麻烦的是:二维码.
- 虽然不同内容的二维码图片本身并不相同,但是仍然太相似了,尤其是文本很长的时候;
- 二维码一般是黑白的;
- 二维码中有大片相同颜色的区域;
- 二维码的尺寸往往是不同的;
而 Vision 框架可以识别的内容就很多,可以识别矩形,二维码等等.我们可以把它们两个结合起来使用,达到神奇的效果.
识别任意矩形
Vision框架的使用本身并不难,在AR项目中,写个 touchesBegan()
方法,在其中写上:
// 1 guard let currentFrame = sceneView.session.currentFrame else { return } // 2 DispatchQueue.global(qos: .background).async { // 3 do { // 4 let request = VNDetectRectanglesRequest {(request, error) in // Access the first result in the array, // after converting to an array // of VNRectangleObservation // 5 guard let results = request.results?.compactMap({ $0 as? VNRectangleObservation }), // 6 let result = results.first else { print ("[Vision] VNRequest produced no result") return } // 得到识别结果,稍后在这里添加处理代码. } let handler = VNImageRequestHandler(cvPixelBuffer: currentFrame.capturedImage) try handler.perform([request]) } catch(let error) { print("An error occurred during rectangle detection: \(error)") } } 复制代码
可以看到,在上面第6步之后,已经得到了识别出的矩形的结果,继续通过hitTest方法,根据二维的屏幕坐标上矩形的四个角的位置(二维坐标),找到三维空间里矩形的四个角的位置(三维坐标).
// 1 let coordinates: [matrix_float4x4] = [ result.topLeft, result.topRight, result.bottomRight, result.bottomLeft ].compactMap { // 2 guard let hitFeature = currentFrame.hitTest($0, types: .featurePoint).first else { return nil } // 3 return hitFeature.worldTransform } // 4 guard coordinates.count == 4 else { return } // 5 DispatchQueue.main.async { // 6 self.removeBillboard() let (topLeft, topRight, bottomRight, bottomLeft) = (coordinates[0], coordinates[1], coordinates[2], coordinates[3]) // 7 self.createBillboard(topLeft: topLeft, topRight: topRight, bottomRight: bottomRight, bottomLeft: bottomLeft) } 复制代码
利用hitTest方法得到了四个featurePoint,后创建一个三维的平面Billboard.
三维平面的位置由锚点决定,锚点位置则由4个点的中心点确定:
let anchor = ARAnchor(transform: plane.center) sceneView.session.add(anchor: anchor) 复制代码
同时还可以创建四个SCNBox来标识矩形的四个角,效果如下
坐标系的处理
但这样创建出的平面有个问题,朝向不正确
这是因为,我们是根据4个点来创建的平面,这4个点是在世界坐标下的点,本身只有位置坐标,没有旋转和缩放信息,打印print(coordinates[0])
结果如下:
simd_float4x4([ [1.0, 0.0, 0.0, 0.0)], [0.0, 1.0, 0.0, 0.0)], [0.0, 0.0, 1.0, 0.0)], [-0.0293431, -0.238044, -0.290515, 1.0)] ]) 复制代码
用这样的4个点去创建平面,过程如下:
func addBillboardNode() -> SCNNode? { guard let billboard = billboard else { return nil } // 1 宽和高是从4个点的位置计算出来的 let rectangle = SCNPlane(width: billboard.plane.width, height: billboard.plane.height) // 2 无法得到transform信息,不能正确显示方向,而SCNPlane的默认方向是在x-y平面上,也就是垂直于地面(沿y轴方向),与手机的初始化方向平行(x-y平面方向平行) let rectangleNode = SCNNode(geometry: rectangle) self.billboard?.billboardNode = rectangleNode return rectangleNode } 复制代码
这里就能看出问题:创建平面只利用了4个点的宽高信息,朝向信息没有设置使用了默认方向.
书中给出了一种处理方式:更改ARKit配置项 ARConfiguration 中的 worldAlignment
属性.这个属性有三个值:
- gravity :坐标系的y轴是与重力方向平行的,坐标原点及x-z轴则是设备初始化时的位置和朝向.也就是默认设置项
- gravityAndHeading :y轴与重力方向平行,而x轴指向东,z轴指向南.和现实世界保持一致.
- camera :坐标系始终跟随摄像机(也就是手机)的位置和朝向,伴随移动.
如果我们采用第三种配置,那么创建出的平面是平行于x-y平面的,即平行于手机屏幕的.但是由于正常情况下,识别过程中手机是正对着要识别对象的,所以得到的结果就是几乎是正确的.
configuration.worldAlignment = .camera 复制代码
个人认为:这种做法很扯蛋,根本没有解决问题,只是当用户垂直于矩形进行识别时,效果较好(远远算不上完美)而已.
我认为可以这样解决,欢迎大家讨论:
- 利用4个点,计算所在平面的法线A,法线A的方向就取指向摄像机(手机)方向为正.考虑到4个点可能不共面(毕竟立体几何中3点确定一个平面),可以用排列组合的方式轮流取3个点求法向量,总共求出4个法向量再求平均值做为法线A;(求平面的法向量可以用两条边向量的叉乘)
- 将创建出的平面的法线B对准刚才计算出的法线A.如何对准呢?变换矩阵是什么? 这就是一个数学问题:已知初始法线B,和目标法线A,求变换矩阵;可以借助四元数进行求解,或者直接设置四元数来处理旋转;
- 将创建出的平面SCNNode的矩阵属性设置为求出的变换矩阵就可以了;
// 可以先求出从法线B到法线A的四元数 extension simd_quatf { /// A quaternion whose action rotates the vector `from` onto the vector `to`. public init(from: float3, to: float3) } // 从四元数中得到变换矩阵或直接使用四元数 extension simd_float4x4 { /// Construct a 4x4 matrix from `quaternion`. public init(_ quaternion: simd_quatf) } 复制代码
Vision能实现的其它功能
除了矩形之外,Vision还能识别出其它物体:
- Horizon :
VNDetectHorizonRequest
类可以得到画面的水平角度. - Faces :
VNDetectFaceRectanglesRequest
类可以实现人脸识别; - Text :
VNDetectTextRectanglesRequest
类可以识别文本和区域; - Rectangle 和 object 追踪:
VNTrackRectangleRequest
和VNTrackObjectRequest
类可以追踪识别出的物体.
例如,上面的例子想改成识别二维码,并在二维码上显示图片或视频,只需要更改Vision部分的代码就行了:
let request = VNDetectBarcodesRequest { (request, error) in // Access the first result in the array, // after converting to an array // of VNBarcodeObservation guard let results = request.results?.compactMap({ $0 as? VNBarcodeObservation }), let result = results.first else { print ("[Vision] VNRequest produced no result") return } ... } 复制代码
效果如下:
后续还可以在识别出二维码的内容后,在上面展示图片,打开网页或播放视频等
地理定位相关
除了Vision识别来触发场景外,还讲到了利用地理定位和iBeacon来触发AR场景,其实核心代码非常简单,如果你做过地图开发或iBeacon开发的话,就知道其实就是下面几个代理方法:
// MARK: - LocationManagerDelegate extension AdViewController: LocationManagerDelegate { // MARK: Location func locationManager(_ locationManager: LocationManager, didEnterRegionId regionId: String) { } func locationManager(_ locationManager: LocationManager, didExitRegionId regionId: String) { } // MARK: Beacons func locationManager(_ locationManager: LocationManager, didRangeBeacon beacon: CLBeacon) { } func locationManager(_ locationManager: LocationManager, didLeaveBeacon beacon: CLBeacon) { } } 复制代码
具体业务逻辑没有什么太大的难点,不再赘述了.
需要注意的是,提到了地理定位的测试方法:
- 用 .gpx 文件来做虚拟定位测试;
- 用lightblue等蓝牙软件来模拟iBeacon定位;
第三部分读书笔记结束!
以上所述就是小编给大家介绍的《16-《ARKit by Tutorials》读书笔记3:交互操作》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- MongoDB的聚合操作以及与Python的交互
- RedisPlus 3.1.0 优化操作体验 新增命令交互
- gitsh 0.13 发布,Git 交互操作环境
- 隔空操作有哪些应用场景?(mixlab 人机交互技术)
- C++操作Kafka使用Protobuf进行跨语言数据交互
- 统信桌面 v20 个人版 1030 发布,优化交互操作
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++ Primer 中文版(第 4 版)
Stanley B.Lippman、Josée LaJoie、Barbara E.Moo / 李师贤、蒋爱军、梅晓勇、林瑛 / 人民邮电出版社 / 2006 / 99.00元
本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本版对前一版进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当......一起来看看 《C++ Primer 中文版(第 4 版)》 这本书的介绍吧!