使用ARCore深度API实现点云采集
一、深度API
本小节内容摘自ARCore官方文档。
ARCore 深度API
Depth API 可助力实现对象遮挡、提升沉浸感和新颖的互动体验,从而增强 AR 体验的真实感。
在下图中,右侧画面是采用深度API进行遮挡后的效果,与左侧图相比更加真实。

深度值
给定实测几何图形上的点 A 和代表深度图像中同一点的 2D 点 a,Depth API 在 a 处给出的值等于投影到主轴上的 CA 的长度。这也可称为 A 相对于相机原点 C 的 z 坐标。使用 Depth API 时,请务必注意,深度值不是光线 CA 本身的长度,而是光线的投影。

应用场景
启用遮挡
遮挡(即准确渲染虚拟物体在现实物体后面)对于沉浸式 AR 体验至关重要。假设有一个虚拟 Andy,用户可能需要放置在包含门边有后备箱的场景中。渲染时没有遮挡,Andy 会不切实际地与树干边缘重叠。如果您使用场景的深度来了解虚拟 Andy 相对于木箱等周围环境的距离,就可以准确地渲染 Andy 的遮挡效果,使其在周围环境中看起来更逼真。

改变场景
您可以渲染虚拟雪花,让其坐在沙发的扶手和枕头上,或者在雾气弥漫的客厅中飘散,让用户进入身临其境的新世界。您可以使用“深度”创建虚拟光线互动、隐藏后方以及重新照亮真实物体的场景。

距离和景深
需要显示距离较远的物体?您可以通过 Depth API 使用距离测量并添加景深效果,例如对场景的背景或前景进行模糊处理。

支持用户与 AR 对象互动
让虚拟内容通过碰撞和物理与现实世界互动,让用户能够通过您的应用“触摸”世界。让虚拟物体绕过现实世界的障碍物,或让虚拟彩弹击中并泼洒到真实的树上。将基于深度的碰撞与游戏物理学相结合,可以打造栩栩如生的体验。

改进点击测试
深度可用于改进点击测试结果。平面点击测试仅适用于具有纹理的平面表面,而深度点击测试则更加详细,甚至适用于非平面和低纹理区域。这是因为深度命中测试使用来自场景的深度信息来确定点的正确深度和方向。
在以下示例中,绿色 Andys 代表标准平面命中测试,红色 Andys 代表深度命中测试。


二、 AR Foundation
本小节记录如何在Unity中开发,通过 AR Foundation 使用“深度”功能。
配置安卓权限
这里需要配置安卓清单,以下方式二选一。
自定义AndroidManifest
在清单中添加<users-feature>其值设为“com.google.ar.core.depth>
配置Unity 项目
导航到 Edit > Project Settings > XR Plug-in Management > ARCore。
Depth 默认设置为 Required。修改为optional
启用深度
为节省资源,ARCore 默认情况下不会启用 Depth API。如需在支持的设备上充分利用深度,您必须通过 Camera 和 ARCameraBackground 组件手动将 AROcclusionManager 组件添加到 AR 相机游戏对象。如需了解详情,请参阅 Unity 文档中的自动遮盖。
在新的AR Session中,检查用户的设备是否支持深度,示例如下:
// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …// Check whether the user's device supports the Depth API.
if (occlusionManager.descriptor?.supportsEnvironmentDepthImage)
{// If depth mode is available on the user's device, perform// the steps you want here.
}
获取深度图像
从AROcclusionManager中获取环境的深度图
// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …if (occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
{using (image){// Use the texture.}
}
提取深度图的距离
如需将 Depth API 用于遮蔽虚拟对象或直观呈现深度数据之外的用途,请从深度图像中提取信息。
Texture2D _depthTexture;
short[] _depthArray;void UpdateEnvironmentDepthImage()
{if (_occlusionManager &&_occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image)){using (image){UpdateRawImage(ref _depthTexture, image, TextureFormat.R16);_depthWidth = image.width;_depthHeight = image.height;}}var byteBuffer = _depthTexture.GetRawTextureData();Buffer.BlockCopy(byteBuffer, 0, _depthArray, 0, byteBuffer.Length);
}// Obtain the depth value in meters at a normalized screen point.
public static float GetDepthFromUV(Vector2 uv, short[] depthArray)
{int depthX = (int)(uv.x * (DepthWidth - 1));int depthY = (int)(uv.y * (DepthHeight - 1));return GetDepthFromXY(depthX, depthY, depthArray);
}// Obtain the depth value in meters at the specified x, y location.
public static float GetDepthFromXY(int x, int y, short[] depthArray)
{if (!Initialized){return InvalidDepthValue;}if (x >= DepthWidth || x < 0 || y >= DepthHeight || y < 0){return InvalidDepthValue;}var depthIndex = (y * DepthWidth) + x;var depthInShort = depthArray[depthIndex];var depthInMeters = depthInShort * MillimeterToMeter;return depthInMeters;
}
三、示例Demo
这里记录当前ARFoundation关于深度API使用点云的示例Demo。不同的是,这里新增的“点云采集”和“点云导入”功能。
官方示例:arcore-depth-lab
版本信息
"com.unity.xr.arfoundation": "4.1.5","com.unity.xr.arcore": "4.1.5","com.unity.xr.arkit": "4.1.5"
相机配置
在“AR Session Origin”->“AR Camera"中添加"AROcclusion Manager组件”

此外在示例demo中,这里挂载了"DepthSource"脚本。(这个脚本一个场景只可有且仅有一个激活)
这个脚本主要作用是处理深度图纹理。
点云采集
示例场景
Demo场景路径:Assests/ARRealismDemos/PointCloud/Scenes/RawPointClouds.unity
点云渲染
场景中找到“RawPointCloudBlender”游戏对象,其挂载的组件如下图:

"PointCloudMaterial"是ARCore示例提供的渲染点云的材质(这个后续会用到)。
“RawPointCloudBlender”是渲染点云的核心脚本,它会在MeshFilter上生成Mesh。
点云保存
在运行时,点云实时渲染的Mesh在“RawPointCloudBlender”->MeshFilter上。
因此这里可直接获取Mesh的顶点数据进行保存。
保存为PTS
public void SaveMeshToFile(string filePath){if (meshFilter == null || meshFilter.sharedMesh == null){Debug.LogWarning("MeshFilter or Mesh not assigned.");return;}Mesh mesh = meshFilter.sharedMesh;// 获取网格数据Vector3[] vertices = mesh.vertices;//int[] triangles = mesh.triangles;//点云无需三角顶点索引,Color[] colors = mesh.colors;int minCount = Math.Min(vertices.Length, colors.Length);// 创建保存网格数据的文件using (StreamWriter writer = new StreamWriter(filePath)){// 写入顶点数据for (int i = 0; i < minCount; i++){//PTS格式前三个是 (x,y,z) 坐标 其中,第四个是“强度”值,最后三个是“颜色值”(R,G,B) Vector3 vertex = vertices[i];Color c = colors[i];//这里暂用ALPHA表示强度值writer.WriteLine(vertex.x + " " + vertex.y + " " + vertex.z+ " " + (int)(c.a * 255) + " " + (int)(c.r * 255) + " " + (int)(c.g * 255) + " " + (int)(c.b * 255));}}}
保存为OBJ
将上述循环中替换为如下内容:
// 创建保存网格数据的文件using (StreamWriter writer = new StreamWriter(filePath)){// 写入顶点数据foreach (Vector3 vertex in vertices){writer.WriteLine("v " + vertex.x + " " + vertex.y + " " + vertex.z);}//...}
点云加载
扩展编辑器
编写脚本,新增点云数据导入功能
public class PTSLoaderEditor : EditorWindow
{private string ptsFilePath;private Material material;[MenuItem("EQ/点云数据/\"加载 *.pts\"")]public static void ShowWindow(){EditorWindow.GetWindow(typeof(PTSLoaderEditor));}private void OnGUI(){//...LoadPointCloud(string filePath);//...}private void LoadPointCloud(string filePath){//...// 创建点云 MeshMesh pointCloudMesh = new Mesh();for (int i = 0; i < count; i++){string[] parts = lines[i].Split(' ');if (parts.Length >= 7){float x = float.Parse(parts[0]);float y = float.Parse(parts[1]);float z = float.Parse(parts[2]);_vertices[i] = new Vector3(x, y, z);byte a = byte.Parse(parts[3]);byte r = byte.Parse(parts[4]);byte g = byte.Parse(parts[5]);byte b = byte.Parse(parts[6]);_colors[i] = new Color32(r, g, b, a);_indices[i] = i;}}#if UNITY_2019_3_OR_NEWERpointCloudMesh.SetVertices(_vertices, 0, count);pointCloudMesh.SetIndices(_indices, 0, count, MeshTopology.Points, 0);pointCloudMesh.SetColors(_colors, 0, count);
#else// Note that we recommend using Unity 2019.3 or above to compile this scene.List<Vector3> vertexList = new List<Vector3>();List<Color32> colorList = new List<Color32>();List<int> indexList = new List<int>();for (int i = 0; i < count; ++i){vertexList.Add(_vertices[i]);indexList.Add(_indices[i]);colorList.Add(_colors[i]);}pointCloudMesh.SetVertices(vertexList);pointCloudMesh.SetIndices(indexList.ToArray(), MeshTopology.Points, 0);pointCloudMesh.SetColors(colorList);
#endif // UNITY_2019_3_OR_NEWER//...}
}

导入点云
在编辑器中操作如下:
“EQ/点云数据/“加载 *.pts””

查看点云
注:这里使用点云材质,可以给点赋予之前传入的颜色值

相关文章:
使用ARCore深度API实现点云采集
一、深度API 本小节内容摘自ARCore官方文档。 ARCore 深度API Depth API 可助力实现对象遮挡、提升沉浸感和新颖的互动体验,从而增强 AR 体验的真实感。 在下图中,右侧画面是采用深度API进行遮挡后的效果,与左侧图相比更加真实。 深度值 给…...
软考数据库
目录 分值分布1. 事务管理1.1 事物的基本概念1.2 数据库的并发控制1.2.1 事务调度概念1.2.2 并发操作带来的问题1.2.3 并发控制技术1.2.4 隔离级别: 1.3 数据库的备份和恢复1.3.1 故障种类1.3.2 备份方法1.3.3 日志文件1.3.4 恢复 2. SQL语言发权限收权限视图触发器…...
Echarts 自适应宽高,或指定宽高进行自适应
文章目录 需求分析 需求 有一个按钮实现对Echarts的指定缩放与拉长,形成自适应效果 拉长后效果图 该块元素缩短后效果图 分析 因为我习惯使用 ref 来获取组件的 DOM 元素,然后进行挂载 <div ref"echartsRef" id"myDiv" :sty…...
体验报告:为什么Claude-3是码农和学者的新宠?
在这个充斥着海量信息的新时代,人工智能的飞速发展带来了翻天覆地的变化。特别是在编程、学术探索以及专业文案创作等领域,AI的助力显得格外关键。最近,我有机会尝试了一种革命性的人工智能工具——Claude-3,其表现令我震惊&#…...
接口自动化框架搭建(九):接入钉钉消息通知
1,jenkins安装钉钉插件 2,在钉钉群聊设置机器人 3,jenkins配置钉钉 根据情况选择: 除了这些,其他不用配置,配置完成点击确认 4,项目配置 添加后保存 5,测试下效果 构建完成后&a…...
一、点击视频下载(通过视频url实现);二、点击下载视频按钮,视频以压缩包形式下载(但未实现压缩视频)
一、点击视频下载(通过视频url实现) <div class"video-list" v-for"(item,index) in videoList" :key"index"><span class"video-title" >{{item.title}}</span><span class"video-…...
B树、B+树、哈夫曼树
目录 1. B树2. B树3. 哈夫曼树 1. B树 特点:一个节点当中可以有多个值,节点内部key 值是有序的,节点内部存储的是key-value类型的数据 磁盘中文件存储用B树。 4阶B树一个节点最多三个key值 5阶B树一个节点最多四个key值 B树有很多的分支&…...
评价指标_Precision(精确率)、Recall(召回率)和Accuracy(准确率)区别和联系
Precision(精确率)、Recall(召回率)和Accuracy(准确率)是机器学习和信息检索领域常用的评价指标,它们用于评估分类器或检索系统的性能,但各自关注的方面略有不同。 Precision&#x…...
【React】React AJAX
在React中使用AJAX(Asynchronous JavaScript and XML)是一种常见的做法,用于从服务器获取数据并在组件中显示。尽管AJAX的名字中包含了XML,但现在更多地使用JSON(JavaScript Object Notation)作为数据交换格…...
vue 移动端弹窗带滚动效果 滚动到底的时候弹窗下的页面会跟着滑动
<template><div class"wrap" :style"dynamicStyle"><!--dynamicStyle主要是介个 通过computed设置postion的值 弹窗的时候设置为fixed 关闭弹窗的时候设置为unset--><div class"banner-wrap"><img src"/assets/…...
Linux-3 yum和vim
目录 本节目标: Linux 软件包管理器 yum 什么是软件包 1.yum是什么?软件包? 2.Linux(centos)的生态 3.yum的相关操作 我怎么知道我应该安装什么软件? 4.yum的本地配置 关于 rzsz 查看软件包 Linux编辑器-vim使用 1.v…...
什么是计算机视觉?计算机视觉:从基础到前沿
引言 计算机视觉,作为人工智能的一个重要分支,致力于赋予机器“看”的能力——即从图像或视频中理解和解释视觉信息的能力。这项技术的发展为自动驾驶汽车、面部识别、机器人导航等多种应用开辟了道路,正在逐步改变我们的工作和生活方式。本…...
Java中的可变字符串
Java中的可变字符串 一、什么是可变字符串二、可变字符串的使用场景以及使用步骤1.新建一个可变字符串2.可变字符串的一系列方法 一、什么是可变字符串 可变字符串是Java.lang包下的 在我们学习到JDBC的时候需要将原有的sql语句根据不同的差异添加一段新的关键字或者单词&…...
C++多线程:单例模式与共享数据安全(七)
1、单例设计模式 单例设计模式,使用的频率比较高,整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式,同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉…...
康耐视visionpro-CogAcqFifoTool工具详细说明
CogAcqFifoTool操作说明: ① 打开工具栏,双击或点击鼠标拖拽 添加CogAcqFifoTool ②.从图片采集设备/图像采集卡列表里选择对应的相机,视频格式选择图像格式。 Mono表示黑白图像,RGB表示彩色相机。点击初始化取相初始化相机。 ③…...
静态图片如何生成gif动画?一个网站在线实现
在当下这个媒体时代,各种各样的图片充斥着我们的生活。尤其是gif动图能够快速有效的传递信息,让用户更加直观的了解某个时间或是场景。非常的生动便捷,那么怎么弄制作gif动画图片呢?其实,只是gif动画的方法非常的简单&…...
Git 实战教程
Git 是一款强大的分布式版本控制系统,广泛用于团队协作与项目管理。本文将为你提供一份 Git 的实战教程,通过实例演示 Git 的基本用法和高级特性,帮助你快速上手 Git。 一、Git 基础 安装 Git 首先,你需要在你的计算机上安装 G…...
解决Vue中仓库持久化的问题,不借助插件用原生JS实现仓库持久化。了解仓库的插件机制、监听的时机
1、演示 前言:目前Vue有两种仓库,一种是Vuex,一种是Pinia,懂得都懂,这里就不详细介绍这两者的区别了 2、什么是持久化 仓库里面的数据是需要跨越页面周期的,当页面刷新之后数据还在,在默认情况下…...
ajax的优缺点有哪些?
我们先来介绍一下什么是ajax: 对于ajax的理解,ajax是一种使用现有技术集合技术内容包括: HTML或XHTML、CSS、 JavaScript、DOM、XML、 XSLT, 以及最重要的XMLHttpRequest。 用于浏览器与服务器之间使用异步数据传输(HTTP请求),做…...
自贡市第一人民医院:超融合与 SKS 承载 HIS 等核心业务应用,加速国产化与云原生转型
自贡市第一人民医院始建于 1908 年,现已发展成为集医疗、科研、教学、预防、公共卫生应急处置为一体的三级甲等综合公立医院。医院建有“全国综合医院中医药工作示范单位”等 8 个国家级基地,建成高级卒中中心、胸痛中心等 6 个国家级中心。医院日门诊量…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
