AR测量:实现AR尺子与测距功能(198)
·
在鸿蒙(HarmonyOS)应用开发中,基于 AR Engine 实现 AR 尺子与测距功能,核心依赖于平面检测与命中检测(HitTest)能力的结合。通过获取用户在现实空间中点击的两个点的三维坐标,即可计算出两点间的实际物理距离。
一、 核心测量原理与流程
AR 测距的底层逻辑是“空间坐标获取 + 几何距离计算”:
- 初始化与会话启动:创建 AR Session,并配置启用平面检测模式(如
HORIZONTAL_AND_VERTICAL),以识别现实世界中的水平面(如桌面、地面)或垂直面(如墙面)。 - 命中检测(HitTest):当用户在屏幕上点击时,系统从屏幕坐标发射一条射线,检测其与真实平面的交点,并返回该交点的 3D 世界坐标(Pose)。
- 距离计算:获取起点与终点的三维坐标 (x1,y1,z1)(x1,y1,z1) 与 (x2,y2,z2)(x2,y2,z2) ,通过三维空间欧几里得距离公式计算实际距离。
- UI 可视化:在 3D 场景中将两个坐标点进行连线,并在连线中点或 UI 面板上实时渲染测量结果。
// ARMeasureTool.ets
import { arEngine } from '@kit.AREngine';
// 定义 3D 坐标接口
interface Point3D {
x: number;
y: number;
z: number;
}
export class ARMeasureTool {
// 1. 命中检测:获取屏幕点击对应的 3D 坐标
public static hitTestAndGetPoint(x: number, y: number, frame: arEngine.ARFrame): Point3D | null {
try {
let hitResults = frame.hitTest(x, y);
if (hitResults && hitResults.length > 0) {
let hitPose = hitResults[0].getHitPose();
return {
x: hitPose.tx(),
y: hitPose.ty(),
z: hitPose.tz()
};
}
} catch (error) {
console.error('HitTest 失败:', error);
}
return null;
}
// 2. 距离计算:三维空间欧几里得距离公式
public static calculateDistance(p1: Point3D, p2: Point3D): number {
const dx = p1.x - p2.x;
const dy = p1.y - p2.y;
const dz = p1.z - p2.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
}
二、 进阶能力:高精几何重建(HPG)
对于需要更高精度和复杂空间感知的测量场景(如测量不规则包裹体积、房间整体尺寸),AR Engine 提供了高精几何重建(HPG)能力:
- 纯软件高精度:无需依赖 LiDAR(激光雷达)等专用硬件,仅通过标准 RGB 摄像头结合 IMU(惯性测量单元)数据,即可实现厘米级的高精度测量。
- 语义感知与稠密点云:算法能够自动从复杂的家庭背景中提取出目标物体(如包裹实体),并生成高精稠密点云,误差可控制在 3% 以内,且 3D 模型重建耗时小于 5 秒。
- 工程化建议:由于 HPG 功耗较高且仅部分高端机型支持,建议将其作为“可选增强体验”,采用“能力探测 + 优雅降级”策略,仅在用户明确触发扫描时按需开启。
// HPGVolumeMeasurement.ets
import { arEngine, arViewController } from '@kit.AREngine';
class HPGCallback extends arViewController.ARViewCallback {
// 1. 在配置中开启体积测量识别能力
public initHPGConfig() {
return {
type: arEngine.ARType.WORLD,
semanticDenseMode: arEngine.ARSemanticDenseMode.CUBE_VOLUME, // 核心:开启 HPG
planeFindingMode: arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL,
focusMode: arEngine.ARFocusMode.AUTO
};
}
// 2. 帧更新回调:获取立方体体积数据
onFrameUpdate(ctx: arViewController.ARViewContext, sysBootTs: number): void {
if (!ctx.session) return;
try {
let frame = ctx.session.getFrame();
// 获取高精几何重建对象数据
let semanticDense = frame.acquireSemanticDense();
if (semanticDense) {
// 获取识别到的立方体数据列表
let cubeDataList = semanticDense.acquireCubeData();
if (cubeDataList && cubeDataList.length > 0) {
for (let cube of cubeDataList) {
// 提取长宽高及体积信息
console.info(`物体尺寸: ${cube.size.x} x ${cube.size.y} x ${cube.size.z}`);
}
}
// ⚠️ 必须调用 release 防止内存泄漏
semanticDense.release();
}
} catch (error) {
console.error('HPG 数据处理失败:', error);
}
}
}
三、 性能优化
- 按需启动与资源释放:不要在应用启动时默认开启 AR 测量。应在用户点击“开始测量”时启动 Session,获取数据后立即调用
stop()并释放资源,避免设备快速发热和耗电。 - 清晰的 UI 引导:AR 测量强依赖用户的物理操作。必须在 UI 上提供清晰的引导提示(如“请缓慢移动手机扫描平面”、“请在平面上点击两个点”),并在状态变化时给予明确反馈(如“检测到平面”、“重建完成”)。
- 轻量级替代方案:如果应用仅需简单的长度或面积测量,优先使用通用的“AR 平面检测 + 用户点击两点计算”方案,无需引入高功耗的 HPG 模块,这能兼容绝大多数支持 AR 的设备。
// ARSafeManager.ets
import { arEngine } from '@kit.AREngine';
import { common } from '@kit.AbilityKit';
export class ARSafeManager {
// 1. 能力探测与优雅降级
public static async checkAndInitAR(context: common.UIAbilityContext): Promise<string> {
// 检查设备是否支持高精几何重建 (HPG)
let supportHPG = canIUse('SystemCapability.Collaboration.AREngine.HighPrecisionGeometry');
if (supportHPG) {
return 'HPG_MODE'; // 返回高级模式标识
} else {
// 降级为普通的平面检测模式
let isSupportBasic = arEngine.isSupport(context);
return isSupportBasic ? 'BASIC_MODE' : 'NOT_SUPPORT';
}
}
// 2. 严格的资源释放与生命周期管理
public static async safeStopAR(arContext: arViewController.ARViewContext | null) {
if (arContext) {
try {
arContext.pause(); // 暂停 AR 会话
arContext.destroy(); // 彻底销毁释放资源
console.info('AR 资源已安全释放');
} catch (error) {
console.error('AR 资源释放失败:', error);
}
}
}
}
四、 AR 测量实战:HitTest 命中检测与空间坐标提取
在鸿蒙的 ArkTS 开发中,实现 AR 尺子的核心在于精准捕获用户在屏幕上的点击,并将其映射为 3D 空间中的物理坐标。
- 射线检测与坐标获取
当用户点击屏幕时,获取屏幕的二维坐标(x, y),并调用arFrame.hitTest(x, y)。系统会从相机位置向屏幕点击点发射一条射线,返回射线与真实世界平面的交点列表(ARHitResult)。 - 提取 3D 世界坐标
从命中结果中提取交点的位姿(Pose),通过调用hitResult.getHitPose()获取位姿对象,进而通过tx()、ty()、tz()方法提取该点在真实世界中的三维坐标 (x,y,z)(x,y,z) 。 - 状态机与交互反馈
在应用层维护一个状态机,记录用户当前是处于“寻找平面”、“等待点击起点”还是“等待点击终点”的状态。当成功获取第一个点时,在 3D 场景中渲染一个指示球体;获取第二个点时,计算距离并渲染连线。
// ARMeasureInteraction.ets
import { arEngine } from '@kit.AREngine';
// 定义 3D 坐标接口
interface Point3D { x: number; y: number; z: number; }
export class ARMeasureInteraction {
private points: Point3D[] = [];
// 1. 射线检测与 3D 坐标提取
public handleScreenTap(x: number, y: number, frame: arEngine.ARFrame): Point3D | null {
try {
// 从屏幕坐标发射射线检测交点
let hitResults = frame.hitTest(x, y);
if (hitResults && hitResults.length > 0) {
let hitPose = hitResults[0].getHitPose();
// 提取真实世界中的三维坐标 (单位: 米)
const point: Point3D = {
x: hitPose.tx(),
y: hitPose.ty(),
z: hitPose.tz()
};
// 状态机:记录点击的点
this.points.push(point);
return point;
}
} catch (error) {
console.error('HitTest 命中检测失败:', error);
}
return null;
}
// 2. 获取当前状态机中的点集(用于 UI 渲染连线或指示球)
public getPoints(): Point3D[] {
return this.points;
}
// 重置测量状态
public reset() {
this.points = [];
}
}
五、 进阶场景:高精几何重建(HPG)与体积测量
对于复杂的测量需求(如顺丰速运的“拍照识别体积”),基础的平面两点测距已无法满足,需要引入高精几何重建(HPG)能力。
- 启用语义稠密重建
在 AR 配置中开启semanticDense模式,通过frame.acquireSemanticDense()获取当前帧的 HPG 数据,并调用semanticDense.acquireCubeData()返回ARSemanticDenseCube[]数组。 - 提取物体包围盒
每个 Cube 包含目标物体在世界坐标系中的center(中心点)、size(长宽高)和orientation(旋转四元数)。通过遍历这些立方体抽象,算法能自动从背景中提取出包裹实体,直接计算出物体的体积。 - 严格的资源释放
HPG 数据极其消耗内存。在获取并处理完semanticDense数据后,必须调用semanticDense.release()释放底层资源,以防止严重的内存泄漏。
// HPGVolumeMeasure.ets
import { arEngine, arViewController } from '@kit.AREngine';
class HPGViewCallback extends arViewController.ARViewCallback {
// 1. 在 onFrameUpdate 中获取 HPG 数据
async onFrameUpdate(ctx: arViewController.ARViewContext, sysBootTs: number): Promise<void> {
let arSession: arEngine.ARSession = ctx.session;
try {
let frame: arEngine.ARFrame = arSession.getFrame();
if (frame) {
// 获取高精几何重建对象数据
let semanticData: arEngine.ARSemanticDenseData = frame.acquireSemanticDense();
if (semanticData && semanticData.cubeDataSize > 0) {
// 提取识别到的立方体(包裹实体)数据
let cubeDataList = semanticData.acquireCubeData();
for (let cube of cubeDataList) {
// 提取长宽高及置信度
let vertexData = cube.vertexData;
let confidence = cube.confidence;
console.info(`识别到物体,置信度: ${confidence}`);
}
}
// ⚠️ 核心:必须严格释放底层资源,防止内存泄漏
if (semanticData) await semanticData.release();
}
} catch (error) {
console.error('HPG 帧数据更新失败:', error);
}
}
}
六、 性能优化与工程避坑指南
AR 测量对设备的传感器和算力要求极高,工程化落地时必须遵循以下规范:
- 能力探测与优雅降级
HPG 仅支持搭载麒麟 9000S/9010 + ToF/深度传感器的部分高端机型。在初始化前,必须通过canIUse('SystemCapability.Collaboration.AREngine.HighPrecisionGeometry')进行能力探测。若不支持,应优雅降级为普通的“平面两点测距”模式。 - 最佳测量环境与引导
测量精度受环境影响极大。应用应引导用户在距离被测物 0.3m - 1.5m 的范围内操作,并提示“缓慢移动手机”。必须明确告知用户避开透明、反光、纯白墙面或光线过暗的场景,否则会导致平面检测失败或坐标漂移。 - 按需启用与防发热
AR 测量(尤其是 HPG)会导致设备快速发热和耗电。严禁在 App 启动时默认开启 AR,仅在用户明确点击“开始测量”时启动 Session。获取到最终测量结果后,应立即调用stop()并释放资源。
// ARMeasurementConfig.ets
import { arEngine, arViewController } from '@kit.AREngine';
import { Scene } from '@kit.ArkGraphics3D';
export class ARMeasurementConfig {
private viewContext: arViewController.ARViewContext | null = null;
// 1. 能力探测与优雅降级配置
public async initARScene(isHPGSupported: boolean): Promise<void> {
let scene = await Scene.load();
this.viewContext = new arViewController.ARViewContext();
this.viewContext.scene = scene;
this.viewContext.callback = new HPGViewCallback();
// 根据设备能力动态配置 AR 参数
this.viewContext.config = {
type: arEngine.ARType.WORLD,
planeFindingMode: arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL,
// 核心:支持 HPG 则开启体积测量,否则降级为普通模式
semanticDenseMode: isHPGSupported
? arEngine.ARSemanticDenseMode.CUBE_VOLUME
: arEngine.ARSemanticDenseMode.NONE,
poseMode: arEngine.ARPoseMode.GRAVITY,
focusMode: arEngine.ARFocusMode.AUTO
};
await this.viewContext.init();
}
// 2. 按需启用与防发热:严格的资源释放
public async safeStopAndRelease() {
if (this.viewContext) {
this.viewContext.pause();
this.viewContext.destroy();
this.viewContext = null;
console.info('AR 测量会话已安全销毁,释放资源');
}
}
}
更多推荐




所有评论(0)