当前位置: 首页 > news >正文

使用ARCore深度API实现点云采集

一、深度API

本小节内容摘自ARCore官方文档。

ARCore 深度API

Depth API 可助力实现对象遮挡、提升沉浸感和新颖的互动体验,从而增强 AR 体验的真实感。

在下图中,右侧画面是采用深度API进行遮挡后的效果,与左侧图相比更加真实。

ARCore深度示例图

深度值

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

图

应用场景

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

ARCore文档截图

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

ARCore文档截图

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

ARCore文档截图

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

ARCore文档截图

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

在以下示例中,绿色 Andys 代表标准平面命中测试,红色 Andys 代表深度命中测试。

ARCore文档截图

ARCore文档截图

二、 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 可助力实现对象遮挡、提升沉浸感和新颖的互动体验&#xff0c;从而增强 AR 体验的真实感。 在下图中&#xff0c;右侧画面是采用深度API进行遮挡后的效果&#xff0c;与左侧图相比更加真实。 深度值 给…...

软考数据库

目录 分值分布1. 事务管理1.1 事物的基本概念1.2 数据库的并发控制1.2.1 事务调度概念1.2.2 并发操作带来的问题1.2.3 并发控制技术1.2.4 隔离级别&#xff1a; 1.3 数据库的备份和恢复1.3.1 故障种类1.3.2 备份方法1.3.3 日志文件1.3.4 恢复 2. SQL语言发权限收权限视图触发器…...

Echarts 自适应宽高,或指定宽高进行自适应

文章目录 需求分析 需求 有一个按钮实现对Echarts的指定缩放与拉长&#xff0c;形成自适应效果 拉长后效果图 该块元素缩短后效果图 分析 因为我习惯使用 ref 来获取组件的 DOM 元素&#xff0c;然后进行挂载 <div ref"echartsRef" id"myDiv" :sty…...

体验报告:为什么Claude-3是码农和学者的新宠?

在这个充斥着海量信息的新时代&#xff0c;人工智能的飞速发展带来了翻天覆地的变化。特别是在编程、学术探索以及专业文案创作等领域&#xff0c;AI的助力显得格外关键。最近&#xff0c;我有机会尝试了一种革命性的人工智能工具——Claude-3&#xff0c;其表现令我震惊&#…...

接口自动化框架搭建(九):接入钉钉消息通知

1&#xff0c;jenkins安装钉钉插件 2&#xff0c;在钉钉群聊设置机器人 3&#xff0c;jenkins配置钉钉 根据情况选择&#xff1a; 除了这些&#xff0c;其他不用配置&#xff0c;配置完成点击确认 4&#xff0c;项目配置 添加后保存 5&#xff0c;测试下效果 构建完成后&a…...

一、点击视频下载(通过视频url实现);二、点击下载视频按钮,视频以压缩包形式下载(但未实现压缩视频)

一、点击视频下载&#xff08;通过视频url实现&#xff09; <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树 特点&#xff1a;一个节点当中可以有多个值&#xff0c;节点内部key 值是有序的&#xff0c;节点内部存储的是key-value类型的数据 磁盘中文件存储用B树。 4阶B树一个节点最多三个key值 5阶B树一个节点最多四个key值 B树有很多的分支&…...

评价指标_Precision(精确率)、Recall(召回率)和Accuracy(准确率)区别和联系

Precision&#xff08;精确率&#xff09;、Recall&#xff08;召回率&#xff09;和Accuracy&#xff08;准确率&#xff09;是机器学习和信息检索领域常用的评价指标&#xff0c;它们用于评估分类器或检索系统的性能&#xff0c;但各自关注的方面略有不同。 Precision&#x…...

【React】React AJAX

在React中使用AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种常见的做法&#xff0c;用于从服务器获取数据并在组件中显示。尽管AJAX的名字中包含了XML&#xff0c;但现在更多地使用JSON&#xff08;JavaScript Object Notation&#xff09;作为数据交换格…...

vue 移动端弹窗带滚动效果 滚动到底的时候弹窗下的页面会跟着滑动

<template><div class"wrap" :style"dynamicStyle"><!--dynamicStyle主要是介个 通过computed设置postion的值 弹窗的时候设置为fixed 关闭弹窗的时候设置为unset--><div class"banner-wrap"><img src"/assets/…...

Linux-3 yum和vim

目录 本节目标&#xff1a; Linux 软件包管理器 yum 什么是软件包 1.yum是什么&#xff1f;软件包&#xff1f; 2.Linux(centos)的生态 3.yum的相关操作 我怎么知道我应该安装什么软件&#xff1f; 4.yum的本地配置 关于 rzsz 查看软件包 Linux编辑器-vim使用 1.v…...

什么是计算机视觉?计算机视觉:从基础到前沿

引言 计算机视觉&#xff0c;作为人工智能的一个重要分支&#xff0c;致力于赋予机器“看”的能力——即从图像或视频中理解和解释视觉信息的能力。这项技术的发展为自动驾驶汽车、面部识别、机器人导航等多种应用开辟了道路&#xff0c;正在逐步改变我们的工作和生活方式。本…...

Java中的可变字符串

Java中的可变字符串 一、什么是可变字符串二、可变字符串的使用场景以及使用步骤1.新建一个可变字符串2.可变字符串的一系列方法 一、什么是可变字符串 可变字符串是Java.lang包下的 在我们学习到JDBC的时候需要将原有的sql语句根据不同的差异添加一段新的关键字或者单词&…...

C++多线程:单例模式与共享数据安全(七)

1、单例设计模式 单例设计模式&#xff0c;使用的频率比较高&#xff0c;整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式&#xff0c;同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉…...

康耐视visionpro-CogAcqFifoTool工具详细说明

CogAcqFifoTool操作说明&#xff1a; ① 打开工具栏&#xff0c;双击或点击鼠标拖拽 添加CogAcqFifoTool ②.从图片采集设备/图像采集卡列表里选择对应的相机&#xff0c;视频格式选择图像格式。 Mono表示黑白图像&#xff0c;RGB表示彩色相机。点击初始化取相初始化相机。 ③…...

静态图片如何生成gif动画?一个网站在线实现

在当下这个媒体时代&#xff0c;各种各样的图片充斥着我们的生活。尤其是gif动图能够快速有效的传递信息&#xff0c;让用户更加直观的了解某个时间或是场景。非常的生动便捷&#xff0c;那么怎么弄制作gif动画图片呢&#xff1f;其实&#xff0c;只是gif动画的方法非常的简单&…...

Git 实战教程

Git 是一款强大的分布式版本控制系统&#xff0c;广泛用于团队协作与项目管理。本文将为你提供一份 Git 的实战教程&#xff0c;通过实例演示 Git 的基本用法和高级特性&#xff0c;帮助你快速上手 Git。 一、Git 基础 安装 Git 首先&#xff0c;你需要在你的计算机上安装 G…...

解决Vue中仓库持久化的问题,不借助插件用原生JS实现仓库持久化。了解仓库的插件机制、监听的时机

1、演示 前言&#xff1a;目前Vue有两种仓库&#xff0c;一种是Vuex&#xff0c;一种是Pinia&#xff0c;懂得都懂&#xff0c;这里就不详细介绍这两者的区别了 2、什么是持久化 仓库里面的数据是需要跨越页面周期的&#xff0c;当页面刷新之后数据还在&#xff0c;在默认情况下…...

ajax的优缺点有哪些?

我们先来介绍一下什么是ajax&#xff1a; 对于ajax的理解&#xff0c;ajax是一种使用现有技术集合技术内容包括: HTML或XHTML、CSS、 JavaScript、DOM、XML、 XSLT&#xff0c; 以及最重要的XMLHttpRequest。 用于浏览器与服务器之间使用异步数据传输(HTTP请求)&#xff0c;做…...

自贡市第一人民医院:超融合与 SKS 承载 HIS 等核心业务应用,加速国产化与云原生转型

自贡市第一人民医院始建于 1908 年&#xff0c;现已发展成为集医疗、科研、教学、预防、公共卫生应急处置为一体的三级甲等综合公立医院。医院建有“全国综合医院中医药工作示范单位”等 8 个国家级基地&#xff0c;建成高级卒中中心、胸痛中心等 6 个国家级中心。医院日门诊量…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...

Xcode 16 集成 cocoapods 报错

基于 Xcode 16 新建工程项目&#xff0c;集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

break 语句和 continue 语句

break语句和continue语句都具有跳转作用&#xff0c;可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...