HarmonyOS AR Engine 平面语义实战:跟踪到 8 个平面,为何标签仍全部 UNKNOWN

发布时间:2026/8/27 21:26:03
HarmonyOS AR Engine 平面语义实战:跟踪到 8 个平面,为何标签仍全部 UNKNOWN 封面是根据本次实测数据制作的视觉摘要真正承担验证的仍是下面的真机截图和 Hilog。这篇文章只写一次真实复测得到的结果。在 HUAWEI Mate 60 Pro、HarmonyOS 7.0API 26上相机画面扫过室内柜体、墙顶和附近表面后AR Engine 最终跟踪到 8 个平面几何范围、中心坐标和边界顶点都可以读取但 8 个平面的ARPlane.label始终都是UNKNOWN。本次结果不是“平面语义识别成功”。准确结论是相机权限、SLAM 和 SEMANTIC 能力门禁通过semanticModePLANE的 AR 会话初始化成功平面几何跟踪可运行最大同时跟踪数为 8本次会话没有取得任何非UNKNOWN的平面语义标签独立的二维拍照识别产生过模型原始输出但它既不能证明标签正确也不能替代ARPlane.label。下面是同一次会话的真实结果页。它显示 8 个总平面、8 个跟踪中平面、0 个已分类平面和 8 个未知平面一、实验环境与可运行案例项目本次实测值设备HUAWEI Mate 60 Pro系统HarmonyOS 7.0 / API 26应用包com.example.csdnAbilityEntryAbility案例入口实验 05识别平面语义完整页面源码entry/src/main/ets/features/arengine/PlaneSemanticPage.ets复测时间2026-08-25 16:36:11—16:45:33工程不是代码片段演示签名 HAP 已覆盖安装到真机随后完成初始化、扫描、四次二维识别、暂停、恢复和销毁。使用的安装与启动命令如下hdcinstall-rentry/build/default/outputs/default/entry-default-signed.hap hdc shell aa start-aEntryAbility-bcom.example.csdn模块声明了相机、加速度计和陀螺仪权限requestPermissions:[{name:ohos.permission.CAMERA,reason:$string:permission_reason_camera,usedScene:{abilities:[EntryAbility],when:inuse}},{name:ohos.permission.ACCELEROMETER,reason:$string:permission_reason_accelerometer,usedScene:{abilities:[EntryAbility],when:inuse}},{name:ohos.permission.GYROSCOPE,reason:$string:permission_reason_gyroscope,usedScene:{abilities:[EntryAbility],when:inuse}}]二、先分清三个概念1. 平面数量不是语义分类数量session.getAllTrackables(arEngine.ARTrackableType.PLANE)返回的是平面 Trackable。它能提供范围、姿态、方向和边界多边形但不代表语义标签一定有效。本次页面同时统计total当前返回的平面总数tracking状态为TRACKING的平面数classifiedlabel ! UNKNOWN的平面数unknownlabel UNKNOWN的平面数。所以total8 / tracking8与classified0 / unknown8可以同时成立。2.planeType不是labelplane.planeType描述几何朝向例如水平向上、水平向下或垂直plane.label才是地面、墙面、桌面等语义类别。本次代表平面显示“水平向上”只能说明其几何方向不能把它写成“地面”。因为同一条记录的label仍然是UNKNOWN。AR 平面语义面向多种室内表面。下面三张图只用于帮助理解类别与几何表面的关系不是本次真机返回的分类结果。概念示意地面与墙面。图中的高亮效果不是本次真机截图。概念示意桌面与座椅。本次复测没有取得这两类有效标签。概念示意门窗、床与天花板。本次复测对应计数仍全部为 0。3. 二维模型输出不是 AR 平面语义页面还提供“识别当前画面”按钮它读取 AR 相机帧转换成PixelMap再交给 Core Vision Kit 多目标识别。这是二维图像链路与 AR 平面的label是两份独立数据。即使二维模型返回了某个对象名称也不能据此修改或推断ARPlane.label。原理示意上方是本次 8 个平面全部UNKNOWN的 AR 链路下方是独立二维推理链路。二维输出没有正确性验证也不会回填平面标签。三、能力门禁不支持就不创建会话进入实验前依次检查相机权限、SLAM 和 SEMANTIC。任何一项不满足都直接拦截避免在不支持的设备上制造“识别失败”的假象。private startPlaneSemantic(): void { if (!this.cameraGranted) { this.latestMessage 拦截成功未获得相机权限不启动平面语义。; hilog.info(DOMAIN, TAG, SEMANTIC_GUARD camerafalse); return; } if (!this.canStartAR()) { this.latestMessage 拦截成功当前设备不支持 SLAM不启动平面语义。; hilog.info(DOMAIN, TAG, SEMANTIC_GUARD slamfalse); return; } if (!this.canStartSemantic()) { this.latestMessage 拦截成功当前设备不支持平面语义不创建 AR 会话。; hilog.info(DOMAIN, TAG, SEMANTIC_GUARD semanticfalse); return; } hilog.info(DOMAIN, TAG, SEMANTIC_GUARD cameratrue slamtrue semantictrue); this.showPlaneSemantic true; }本次真机日志为SEMANTIC_GUARD cameratrue slamtrue semantictrue它只证明设备允许进入实验不保证每个环境平面都能取得语义标签。四、创建平面语义 AR 会话配置中的关键项是planeFindingMode与semanticMode。本案例同时启用水平、垂直平面检测并请求平面语义深度模式设为自动Mesh 在本实验中关闭。private async initARView(): Promisevoid { const scene: Scene await Scene.load(); const context new arViewController.ARViewContext(); this.callback new PlaneSemanticCallback( (arContext: arViewController.ARViewContext, timestamp: number) { this.handleFrameUpdate(arContext, timestamp); }); context.scene scene; context.callback this.callback; context.config { type: arEngine.ARType.WORLD, planeFindingMode: arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL, powerMode: arEngine.ARPowerMode.NORMAL, semanticMode: arEngine.ARSemanticMode.PLANE, poseMode: arEngine.ARPoseMode.GRAVITY, depthMode: arEngine.ARDepthMode.AUTOMATIC, meshMode: arEngine.ARMeshMode.DISABLED, focusMode: arEngine.ARFocusMode.AUTO }; await context.init(); this.arContext context; }本次初始化和深度探测的真实日志如下SEMANTIC_SESSION_INIT success modePLANE depthAUTOMATIC costMs39 SEMANTIC_DEPTH_PROBE attempt13 depthSuccesstrue depth256x256 depthFormat4 depthPlanes1 confidenceSuccesstrue confidence256x256 confidenceFormat3 confidencePlanes1深度图可读取仍不能推出平面语义必然成功它只是另一项设备与帧能力证据。五、逐帧读取并严格统计UNKNOWN帧回调只在相机处于TRACKING时继续处理。取得平面 Trackable 后代码必须直接读取ARPlane.label不能根据朝向或尺寸自行猜测语义。private updateSemanticSnapshot( trackables: ArrayarEngine.ARTrackable ): void { let tracked: number 0; let classified: number 0; let unknown: number 0; trackables.forEach((trackable: arEngine.ARTrackable) { if (trackable.type ! arEngine.ARTrackableType.PLANE || trackable.state ! arEngine.ARTrackingState.TRACKING) { return; } const plane: arEngine.ARPlane trackable as arEngine.ARPlane; tracked 1; if (plane.label arEngine.ARSemanticPlaneLabel.UNKNOWN) { unknown 1; } else { classified 1; } }); this.totalPlanes trackables.length; this.trackedPlanes tracked; this.classifiedPlanes classified; this.unknownPlanes unknown; }代表平面的几何详情来自真实 APIprivate updateRepresentativePlane(plane: arEngine.ARPlane): void { let pose: arEngine.ARPose | undefined undefined; try { pose plane.getPose(); const polygon: ArrayBuffer plane.getPolygonXZ(); const vertexCount: number Math.floor(polygon.byteLength / 4 / 2); this.representativeLabel this.semanticLabelText(plane.label); this.representativeDirection this.planeTypeText(plane.planeType); this.representativeSize ${Math.abs(plane.extendX).toFixed(2)} × ${Math.abs(plane.extendZ).toFixed(2)} m; this.representativeCenter X ${pose.translation.x.toFixed(2)} Y ${pose.translation.y.toFixed(2)} Z ${pose.translation.z.toFixed(2)}; this.representativeVertices ${vertexCount} 个; } finally { if (pose) { pose.release().catch((error: BusinessError) { hilog.error(DOMAIN, TAG, SEMANTIC_POSE_RELEASE error%{public}d, error.code); }); } } }实际扫描中首次平面在初始化后5834 ms出现随后总数逐步增长到 8。稳定阶段的日志是SEMANTIC_FIRST_PLANE latencyMs5834 total1 SEMANTIC_COUNTS sample104 total8 tracking8 classified0 unknown8 floor0 wall0 table0 seat0 ceiling0 doorWindow0 bed0 other0 SEMANTIC_REPRESENTATIVE label未知 direction水平向上 extent4.71 × 2.63 m centerX 0.70 Y -1.04 Z -0.92 vertices10 SEMANTIC_COUNTS sample370 total8 tracking8 classified0 unknown8 floor0 wall0 table0 seat0 ceiling0 doorWindow0 bed0 other0从sample104到sample3708 个平面持续跟踪分类数仍为 0。这比单帧截图更能说明本次不是页面刚进入时的短暂等待而是在持续扫描后仍没有取得有效语义标签。六、二维拍照识别只记录原始输出API 26 的相机帧先检查多目标识别系统能力再读取YUV_420_888图像、转换为PixelMap并发起推理private requestPhotoRecognition(): void { if (!canIUse(SystemCapability.AI.Vision.ObjectDetection)) { this.photoRecognitionState 当前设备不支持; this.photoRecognitionResult 缺少多目标识别系统能力; hilog.error(DOMAIN, TAG, PHOTO_OBJECT_GUARD syscapfalse); return; } this.photoCaptureRequested true; this.photoRecognitionState 等待下一帧; } private async runPhotoRecognition(pixelMap: image.PixelMap): Promisevoid { try { if (!this.objectDetector) { this.objectDetector await objectDetection.ObjectDetector.create(); } const request: visionBase.Request { inputData: { pixelMap: pixelMap } }; const response await this.objectDetector.process(request); // 页面只展示 response.objects 的原始标签与分数 // 不把结果写入任何 ARPlane。 } finally { this.photoRecognitionBusy false; pixelMap.release().catch((error: BusinessError) { hilog.error(DOMAIN, TAG, PHOTO_OBJECT_PIXELMAP_RELEASE error%{public}d, error.code); }); } }用户改变镜头后四次调用依次留下PHOTO_OBJECT_COMPLETE count1 summary人物 42% PHOTO_OBJECT_COMPLETE count4 summary文本 43% · 植物 40% · 植物 36% PHOTO_OBJECT_COMPLETE count10 summary人头 83% · 人头 80% · 人脸 69% PHOTO_OBJECT_COMPLETE count0 summary画面中没有识别到目标这些是模型原始输出没有人工标注或独立正确性验证。本文不把它们称为“识别正确”也不利用它们解释 8 个 AR 平面的语义。首图显示的是最后一次调用后的页面状态所以二维区域为“画面中没有识别到目标”。七、暂停、恢复与销毁必须闭环AR 页面退出时要释放持有的平面、二维检测器和ARViewContext。暂停与恢复则直接调用上下文的生命周期接口private pauseARView(): void { if (!this.arContext || this.isDestroyed || this.isPaused) { return; } this.arContext.pause(); this.isPaused true; } private resumeARView(): void { if (!this.arContext || this.isDestroyed || !this.isPaused) { return; } this.arContext.resume(); this.isPaused false; this.lastSampleTime 0; } private async destroyARView(): Promisevoid { if (!this.arContext || this.isDestroyed) { return; } this.isDestroyed true; if (this.retainedProbePlane) { await this.retainedProbePlane.release(); this.retainedProbePlane undefined; } if (this.objectDetector) { await this.objectDetector.destroy(); this.objectDetector undefined; } await this.arContext.destroy(); this.arContext undefined; this.callback undefined; }暂停发生在sample789页面保持 8 个跟踪平面和 0 个已分类平面SEMANTIC_SESSION_PAUSE success sample789 tracking8 classified0恢复后下一次采样从790继续。恢复瞬间有 6 个平面处于跟踪状态这属于重新建立跟踪过程不能把它写成“平面数据丢失”SEMANTIC_SESSION_RESUME success sample789 tracking8 classified0 SEMANTIC_COUNTS sample790 total8 tracking6 classified0 unknown6 floor0 wall0 table0 seat0 ceiling0 doorWindow0 bed0 other0最后点击销毁应用关闭相机并返回七项实验首页SEMANTIC_SESSION_DESTROY success samples944 maxTracking8 maxClassified0 total8八、本次结果如何解释验证项2026-08-25 同一次真机会话结果能力门禁cameratrue / slamtrue / semantictrue会话初始化成功39 ms深度与置信度第 13 次探测取得256 × 256图像首个平面5834 ms最大平面总数8最大同时跟踪数8有效语义数0稳定阶段未知数8代表平面水平向上4.71 × 2.63 m10 个边界顶点二维拍照识别产生过多组原始输出最终为“画面中没有识别到目标”正确性未验证暂停与恢复789暂停恢复后从790继续采样销毁samples944 / maxTracking8 / maxClassified0 / total8从证据可以确定几何平面检测链路可运行因为平面数量、范围、位姿与边界均有真实数据。本次平面语义分类没有成功因为整个会话的最大有效分类数为 0。semanticModePLANE、能力门禁通过和深度图可用都不是“必然返回非 UNKNOWN 标签”的证明。仅凭这一次测试无法确定始终为UNKNOWN的唯一原因场景、光照、纹理、模型适配和设备实现都可能影响结果不能选一个原因当作已证实结论。如果业务必须依赖地面、墙面或桌面标签应把UNKNOWN设计为正常分支保留几何能力、提示用户继续扫描或降级为只依赖平面朝向与点击命中但不要伪造语义类别。九、排查清单遇到“检测到平面但没有语义”时可以按以下顺序检查确认相机权限、SLAM 和 SEMANTIC 能力均通过。确认会话配置确实为semanticMode: ARSemanticMode.PLANE。分开记录planeType和label不要把水平向上直接写成地面。同时记录total / tracking / classified / unknown并持续采样避免只看一帧。扫描多种真实表面保持移动缓慢、画面清晰并记录失败分支。如果接入二维模型把其结果放在独立区域不回填ARPlane.label。验证暂停、恢复和销毁确保退出页面后释放相机、Trackable、Frame、Image、Pose 与检测器资源。十、结论这次实操得到的是一个明确但未达到语义目标的结果AR Engine 在真机上跟踪到了 8 个环境平面几何数据完整生命周期闭环可复现然而整个会话没有出现任何非UNKNOWN的ARPlane.label。因此第五篇仍不能标记为“平面语义验证成功”。后续只有在真机日志和截图中取得至少一个非UNKNOWN标签并能与同一会话的页面数据对应才可以更新这一结论。参考资料华为 AR Engine Kit 开发指南平面语义介绍检测环境中的平面ArkTS管理 AR 会话ArkTSCore Vision Kit 多目标识别本文所有结果截图均来自 2026-08-25 同一次真机会话横向封面、原理图和场景图由内置 ImageGen 制作只承担视觉摘要与概念说明不作为成功证据。