大雷神头像
关注
HarmonyOS AR Engine 物体形状实战:把实体书识别为 RECTANGLE,再放进地面 AR 盒子封面图

HarmonyOS AR Engine 物体形状实战:把实体书识别为 RECTANGLE,再放进地面 AR 盒子

AR 书籍放入开口盒子效果图

上图根据本次真机实验的书籍、开口盒子和地面锚定关系制作,用于展示最终效果。后文保留未经生成式处理的真机截图和原生日志作为验证证据。

这次实操在 Mate 60 Pro 上完成了两项可以直接看到结果的 AR 操作:

  • AR Engine 的 ARTarget 把一本平放的实体书自动分类为 RECTANGLE
  • 在真实水平平面上创建锚点,显示一个顶部敞开的半透明立体盒子,把实体书放进盒子后确认匹配完成。

真机在第 766、780 和 810 帧三次取得有效矩形结果。第一次成功时,书本的包围盒尺寸为 0.2219 × 0 × 0.2976 m,包围球半径为 0.1856 m

OBJECT_SNAPSHOT sample=766 camera=0 total=3 tracking=1 paused=2 stopped=0 acquireErrors=0 stateErrors=0 classified=1 unknown=0 cube=0 circle=0 rectangle=1 shape=3 radius=0.1856 size=0.2219,0.0000,0.2976 center=-0.0727,-0.8548,-0.4059 shapeStatus=0 geometryStatus=0

本机 SDK 中 shape=3 对应 ARENGINE_TARGET_SHAPE_RECTANGLEshapeStatus=0geometryStatus=0 表示形状、包围盒、半径及中心位姿均读取成功。

最初版本使用扁平书籍模型,地面命中距离为 0.6598 m。为了让放入动作更直观,后续把锚点上的几何体改为 28 × 21 × 6 cm 开口盒子,内部保留 24 × 17 cm 的书籍框。开口盒子复测的命中距离为 0.7255 m,锚点状态为 TRACKING

BOOK_GUIDE_PLACE model=OPEN_BOX_GUIDE placed=1 hitStatus=0 hitCount=2 anchorTracking=0 distance=0.7255 center=-0.3791,-0.8131,0.0138

实体书放入开口盒子后,本轮确认记录写在第 6946 帧:

BOOK_MATCH_CONFIRM confirmed=1 manual=true sample=6946 camera=0 anchor=0 status=0

这里有两个独立结果:RECTANGLE 是单独扫描实体书时由 AR Engine 自动返回的形状分类;“书籍摆放匹配成功”是锚点稳定时,由操作者确认实体书已经放入盒子。人工确认不会修改 ARTarget 的 shape、计数或几何数据。

本次实验的完整过程

整个过程分为四步:扫描水平平面、创建盒子锚点、放入实体书、读取官方形状结果。

从地面锚点到矩形分类

应用中同时保留两条数据链路:

地面扫描 → HitTest → ARAnchor → OpenGL 开口盒子 → 人工确认

相机帧 → ARTarget → TrackingState → ShapeType → AABB / Radius / CenterPose

第一条链路负责可见的 AR 摆放效果;第二条链路负责官方物体形状分类。把它们放在同一个实验页里,既能看到 AR 模型,也能判断 ARTarget 到底有没有返回有效形状。

实操环境与准备

项目本次实操环境
开发工具DevEco Studio
开发语言ArkTS + C++
SDKHarmonyOS API 26
测试设备HUAWEI Mate 60 Pro
设备系统HarmonyOS 7.0
AR 会话类型ARENGINE_TYPE_WORLD
平面模式水平与垂直平面
语义模式ARENGINE_SEMANTIC_MODE_TARGET
深度模式ARENGINE_DEPTH_MODE_AUTOMATIC
对焦模式ARENGINE_FOCUS_MODE_AUTO
必需权限CAMERA、ACCELEROMETER、GYROSCOPE
必需能力SLAM、SEMANTIC

测试物体选择了一本封面颜色鲜明、边缘完整的平装书。书本平放后轮廓接近矩形,封面有足够纹理,移动手机时也容易保持完整取景。

入口页先完成相机权限和设备能力检测。CAMERA、SLAM 或 SEMANTIC 条件不满足时,不进入原生 AR 会话。

权限声明如下:

"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"
    }
  }
]

AR Engine 物体形状使用 C API。本次通过 Native XComponent 显示真实相机画面和 OpenGL 模型,再通过 NAPI 把形状、几何与锚点状态传给 ArkTS 页面。

CMake 配置如下:

cmake_minimum_required(VERSION 3.5.0)
project(ObjectSemanticLab)

set(CMAKE_CXX_STANDARD 17)
find_library(ARENGINE_LIB libarengine_ndk.z.so)

add_library(objectsemantic SHARED object_semantic.cpp)

target_link_libraries(objectsemantic PUBLIC
    EGL
    GLESv3
    hilog_ndk.z
    ace_ndk.z
    ace_napi.z
    ${ARENGINE_LIB}
)

创建 TARGET 语义会话

会话使用 WORLD 类型,同时开启平面检测、TARGET 语义、自动深度和自动对焦。

AREngine_ARConfig *config = nullptr;
HMS_AREngine_ARConfig_Create(session, &config);

HMS_AREngine_ARConfig_SetPreviewSize(
    session, config, 1440, 1080);
HMS_AREngine_ARConfig_SetUpdateMode(
    session, config, ARENGINE_UPDATE_MODE_LATEST);
HMS_AREngine_ARConfig_SetFocusMode(
    session, config, ARENGINE_FOCUS_MODE_AUTO);
HMS_AREngine_ARConfig_SetARType(
    session, config, ARENGINE_TYPE_WORLD);
HMS_AREngine_ARConfig_SetPlaneFindingMode(
    session,
    config,
    ARENGINE_PLANE_FINDING_MODE_HORIZONTAL_AND_VERTICAL);
HMS_AREngine_ARConfig_SetSemanticMode(
    session, config, ARENGINE_SEMANTIC_MODE_TARGET);
HMS_AREngine_ARConfig_SetDepthMode(
    session, config, ARENGINE_DEPTH_MODE_AUTOMATIC);

AREngine_ARStatus configureStatus =
    HMS_AREngine_ARSession_Configure(session, config);
HMS_AREngine_ARConfig_Destroy(config);

配置完成后回读语义和对焦模式,并把每个调用的状态写入日志。本次所有状态均为 0:

OBJECT_CONFIG preview=0 update=0 focusSet=0 focusGet=0 focusMode=1 type=0 plane=0 semanticSet=0 semanticGet=0 semanticMode=2 depth=0 configure=0 frame=0 texture=0 geometry=0 resume=0

本机 SDK 中 semanticMode=2 为 TARGET,focusMode=1 为 AUTO。

查询 ARTarget,先看跟踪状态

每一帧先查询 ARENGINE_TRACKABLE_TARGET,再读取每个目标的跟踪状态。

AREngine_ARTrackableList *targetList = nullptr;
HMS_AREngine_ARTrackableList_Create(session, &targetList);
HMS_AREngine_ARSession_GetAllTrackables(
    session,
    ARENGINE_TRACKABLE_TARGET,
    targetList);

int32_t targetSize = 0;
HMS_AREngine_ARTrackableList_GetSize(
    session, targetList, &targetSize);

for (int32_t index = 0; index < targetSize; ++index) {
    AREngine_ARTrackable *trackable = nullptr;
    AREngine_ARStatus acquireStatus =
        HMS_AREngine_ARTrackableList_AcquireItem(
            session, targetList, index, &trackable);
    if (acquireStatus != ARENGINE_SUCCESS || trackable == nullptr) {
        acquireErrors += 1;
        continue;
    }

    AREngine_ARTrackingState state =
        ARENGINE_TRACKING_STATE_STOPPED;
    AREngine_ARStatus stateStatus =
        HMS_AREngine_ARTrackable_GetTrackingState(
            session, trackable, &state);

    if (stateStatus != ARENGINE_SUCCESS) {
        stateErrors += 1;
        HMS_AREngine_ARTrackable_Release(trackable);
        continue;
    }
    if (state == ARENGINE_TRACKING_STATE_PAUSED) {
        paused += 1;
        HMS_AREngine_ARTrackable_Release(trackable);
        continue;
    }
    if (state == ARENGINE_TRACKING_STATE_STOPPED) {
        stopped += 1;
        HMS_AREngine_ARTrackable_Release(trackable);
        continue;
    }

    // 只有 TRACKING 目标才进入形状与几何读取。
}

首轮扫描时已经发现两个候选目标,但两者一直处于 PAUSED

OBJECT_SNAPSHOT sample=82 camera=0 total=2 tracking=0 paused=2 stopped=0 acquireErrors=0 stateErrors=0 classified=0 unknown=0 cube=0 circle=0 rectangle=0 shape=0

这时相机已经是 TRACKING,目标列表也能取得数据,但还不能读取有效形状。页面因此显示“候选目标未进入跟踪”,没有把 total=2 写成识别成功。

读取形状、包围盒、半径和中心位姿

目标进入 TRACKING 后,将通用 Trackable 转为 AREngine_ARTarget,读取形状类型。

auto *target = reinterpret_cast<AREngine_ARTarget *>(trackable);
AREngine_ARTargetShapeLabel shape =
    ARENGINE_TARGET_SHAPE_UNKNOWN;

AREngine_ARStatus shapeStatus =
    HMS_AREngine_ARTarget_GetShapeType(
        session, target, &shape);

if (shapeStatus == ARENGINE_SUCCESS &&
    shape != ARENGINE_TARGET_SHAPE_UNKNOWN) {
    classified += 1;
} else {
    unknown += 1;
}

if (shape == ARENGINE_TARGET_SHAPE_CUBE) {
    cube += 1;
} else if (shape == ARENGINE_TARGET_SHAPE_CIRCLE) {
    circle += 1;
} else if (shape == ARENGINE_TARGET_SHAPE_RECTANGLE) {
    rectangle += 1;
}

几何数据使用三个接口分别读取:

float aabb[6] = {};
float radius = 0.0f;
float poseRaw[7] = {};
AREngine_ARPose *pose = nullptr;

AREngine_ARStatus aabbStatus =
    HMS_AREngine_ARTarget_GetAxisAlignedBoundingBox(
        session, target, aabb, 6);
AREngine_ARStatus radiusStatus =
    HMS_AREngine_ARTarget_GetRadius(
        session, target, &radius);

HMS_AREngine_ARPose_Create(session, nullptr, 0, &pose);
AREngine_ARStatus centerStatus =
    HMS_AREngine_ARTarget_GetCenterPose(
        session, target, pose);
AREngine_ARStatus rawStatus =
    HMS_AREngine_ARPose_GetPoseRaw(
        session, pose, poseRaw, 7);
HMS_AREngine_ARPose_Destroy(pose);

float sizeX = std::abs(aabb[3] - aabb[0]);
float sizeY = std::abs(aabb[4] - aabb[1]);
float sizeZ = std::abs(aabb[5] - aabb[2]);

书本平放在水平面上,因此本次 AABB 的一个轴接近 0,另外两个轴约为 22 cm 和 30 cm,与画面中的实体书尺寸吻合。

在地面创建盒子锚点

页面中央显示十字准星。点击“在这里放置开口盒子”时,原生层在准星附近执行 HitTest。

AREngine_ARHitResultList *hitList = nullptr;
HMS_AREngine_ARHitResultList_Create(session, &hitList);

float pixelX = static_cast<float>(width) * 0.5f;
float pixelY = static_cast<float>(height) * 0.48f;

AREngine_ARStatus hitStatus =
    HMS_AREngine_ARFrame_HitTest(
        session, frame, pixelX, pixelY, hitList);

命中结果不会直接使用。候选对象还要同时满足四个条件:

  1. Trackable 类型为 ARENGINE_TRACKABLE_PLANE
  2. Trackable 状态为 ARENGINE_TRACKING_STATE_TRACKING
  3. 平面方向为 ARENGINE_PLANE_FACING_HORIZONTAL_UPWARD
  4. 命中 Pose 位于平面多边形内部。
bool validPlane =
    trackableType == ARENGINE_TRACKABLE_PLANE &&
    trackableState == ARENGINE_TRACKING_STATE_TRACKING &&
    planeType == ARENGINE_PLANE_FACING_HORIZONTAL_UPWARD &&
    poseStatus == ARENGINE_SUCCESS &&
    polygonStatus == ARENGINE_SUCCESS &&
    inPolygon != 0;

if (validPlane) {
    AREngine_ARAnchor *anchor = nullptr;
    AREngine_ARStatus anchorStatus =
        HMS_AREngine_ARHitResult_AcquireNewAnchor(
            session, hit, &anchor);

    AREngine_ARTrackingState anchorState =
        ARENGINE_TRACKING_STATE_STOPPED;
    HMS_AREngine_ARAnchor_GetTrackingState(
        session, anchor, &anchorState);
}

正式放置前,对着有纹理的地面缓慢移动手机,让十字落在无遮挡区域。

扫描地面准备放置盒子

成功会话返回两个命中候选,最终使用的锚点处于 TRACKING,距离相机 0.6598 m

用 OpenGL 绘制顶部敞开的盒子

盒子不是图片覆盖,而是原生 OpenGL 几何体。外框尺寸为 0.28 × 0.21 × 0.06 m,内部书籍框为 0.24 × 0.17 m。顶部不绘制面,因此可以清楚看到实体书位于盒子内部。

constexpr float BOX_OUTER_WIDTH_METERS = 0.28f;
constexpr float BOX_OUTER_LENGTH_METERS = 0.21f;
constexpr float BOX_WALL_HEIGHT_METERS = 0.06f;
constexpr float BOOK_SLOT_WIDTH_METERS = 0.24f;
constexpr float BOOK_SLOT_LENGTH_METERS = 0.17f;

每帧从锚点取得模型矩阵,再读取相机 View 和 Projection 矩阵:

float model[16] = {};
float view[16] = {};
float projection[16] = {};

HMS_AREngine_ARAnchor_GetPose(session, guideAnchor, pose);
HMS_AREngine_ARPose_GetMatrix(session, pose, model, 16);
HMS_AREngine_ARCamera_GetViewMatrix(
    session, camera, view, 16);

AREngine_ClipPlaneDistance clip {0.05f, 20.0f};
HMS_AREngine_ARCamera_GetProjectionMatrix(
    session, camera, clip, projection, 16);

auto viewModel = MultiplyMatrix(view, model);
auto mvp = MultiplyMatrix(projection, viewModel.data());

盒子使用一块半透明底板和四面竖直侧壁,共 30 个三角形顶点;顶部边框、底部边框、四条竖边、内部书籍框和中心十字使用不透明线段。等待放书时为青色,确认完成后改成绿色:

glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(guideProgram);
glUniformMatrix4fv(mvpUniform, 1, GL_FALSE, mvp.data());

if (matched) {
    glUniform4f(colorUniform, 0.20f, 0.94f, 0.65f, 0.32f);
} else {
    glUniform4f(colorUniform, 0.16f, 0.74f, 1.0f, 0.24f);
}
glDrawArrays(GL_TRIANGLES, 0, 30);

glVertexAttribPointer(positionAttribute, 3,
    GL_FLOAT, GL_FALSE, 0, lineVertices);
glDrawArrays(GL_LINES, 0, 36);

盒子出现后,移动手机观察它是否仍留在原地。锚点继续 TRACKING 时,盒子不会跟着屏幕移动。

在 ArkTS 页面完成三步交互

Native 模块向 ArkTS 暴露启动、快照、放置、确认、重置和生命周期动作:

declare const objectSemantic: {
  start: (id: string, rotation: number) => void;
  getSnapshot: (id: string) => ObjectSemanticSnapshot;
  placeGuide: (id: string) => void;
  confirmGuide: (id: string) => void;
  resetGuide: (id: string) => void;
  pause: (id: string) => void;
  resume: (id: string) => void;
  stop: (id: string) => void;
};

页面根据 guideState 只保留一个主动作:

private runPrimaryAction(): void {
  if (this.snapshot.guideState === 2) {
    objectSemantic.confirmGuide(this.componentId);
    hilog.info(DOMAIN, TAG,
      'BOOK_UI_CONFIRM sample=%{public}d manual=true',
      this.snapshot.sample);
    return;
  }
  if (this.snapshot.guideState === 3) {
    objectSemantic.resetGuide(this.componentId);
    return;
  }
  objectSemantic.placeGuide(this.componentId);
}

三个阶段对应的按钮文字为:

未放置:在这里放置开口盒子
已锚定:确认实体书已放入盒子
已完成:重新开始匹配

确认动作不调用图像分类,也不写入官方 TARGET 结果。它只在相机和书籍锚点都处于 TRACKING 时记录人工完成状态:

bool confirmed =
    anchorStatus == ARENGINE_SUCCESS &&
    anchorState == ARENGINE_TRACKING_STATE_TRACKING &&
    cameraState == ARENGINE_TRACKING_STATE_TRACKING;

if (confirmed) {
    snapshot.guideState = GUIDE_MATCHED;
    snapshot.guideManualConfirmed = 1;
    snapshot.guideConfirmedSample = sample;
}

真机怎么操作

1. 先让书完整进入画面

把书平放在有纹理的地面上,手机距离书大约 60~90 cm。取景时保留书本四周的一圈地面,不要让封面边缘贴住画面边界。

首轮近距离扫描时,两个候选目标持续 PAUSED,没有有效形状。

书籍扫描仍未激活

2. 缓慢移动手机,不在屏幕上滑动

保持书本完整入镜,手机向左、右和斜上方缓慢移动,让 AR Engine 取得不同视角。屏幕滑动不会改变相机位姿,对物体跟踪没有帮助。

本次移动到第 766 帧时,第 3 个候选目标进入 TRACKING,形状变为 RECTANGLE;第 780 帧仍然保持相同尺寸,第 810 帧再次取得矩形结果。

sample=766 tracking=1 paused=2 classified=1 rectangle=1 shape=3 radius=0.1856 size=0.2219,0.0000,0.2976
sample=780 tracking=1 paused=2 classified=1 rectangle=1 shape=3 radius=0.1856 size=0.2219,0.0000,0.2976
sample=810 tracking=1 paused=2 classified=1 rectangle=1 shape=3 radius=0.1841 size=0.2240,0.0000,0.2921

3. 扫描地面并放置盒子

让中心十字对准书本旁边的空地,点击“在这里放置开口盒子”。成功时页面显示盒子已锚定,原生日志同时给出命中候选数、距离、锚点状态和世界坐标。

4. 把实体书放进盒子

把书移入半透明盒子,调整位置和方向,让书位于内部 24 × 17 cm 落位框附近。确认实体书已经进入盒子后,点击“确认实体书已放入盒子”。

放入时页面显示锚点 TRACKING · 稳定跟踪、命中距离 0.73 m 和盒子世界坐标:

实体书已经放进开口盒子

点击确认后,页面显示“书籍摆放匹配成功”,盒子描边变为绿色,并保留“人工确认”标记:

实体书放入盒子确认成功

BOOK_GUIDE_PLACE model=OPEN_BOX_GUIDE placed=1 hitStatus=0 hitCount=2 anchorTracking=0 distance=0.7255 center=-0.3791,-0.8131,0.0138
BOOK_MATCH_CONFIRM confirmed=1 manual=true sample=6946 camera=0 anchor=0 status=0

这一轮书和盒子组合进入 TARGET 视野后,官方结果稳定返回 CUBE,AABB 为 0.2081 × 0.0281 × 0.2726 m。它没有覆盖前面单独扫描书籍取得的 RECTANGLE,而是作为本轮组合外形的独立记录:

下面的图只用来区分两轮扫描对象:左侧是单独扫描书籍,右侧是书籍放入盒子后的组合目标。分类结论仍以真机截图和紧随其后的原生日志为准。

单独书籍RECTANGLE与盒内组合CUBE关系示意

OBJECT_SNAPSHOT sample=5940 camera=0 total=4 tracking=1 paused=3 stopped=0 classified=1 cube=1 rectangle=0 shape=1 radius=0.1720 size=0.2081,0.0281,0.2726 shapeStatus=0 geometryStatus=0
OBJECT_SNAPSHOT sample=6960 camera=0 total=4 tracking=1 paused=3 stopped=0 classified=1 cube=1 rectangle=0 shape=1 radius=0.1720 size=0.2081,0.0281,0.2726 shapeStatus=0 geometryStatus=0

遇到的情况与处理

情况一:目标数量增加,但一直没有形状

最初页面能看到两个 TARGET,却一直是 PAUSED 2 / TRACKING 0。这说明目标候选已经产生,形状读取接口也没有报错,但目标尚未进入可读取形状的跟踪状态。

处理时依次核对了三项配置:

  • 平面检测不能关闭,改为 HORIZONTAL_AND_VERTICAL
  • 相机对焦从默认固定模式改为 AUTO
  • 书本四条边不能贴住相机画面边缘,扫描时保留周围地面。

系统日志曾反复出现:

Invalid 2D box. (2D box lies along the image border)

把整本书完整放进画面并缓慢移动后,目标进入 TRACKING,随后取得 RECTANGLE

情况二:模型已经出现,证据卡仍显示初始值

第一版页面顶部已经显示“模型已锚定”,相机画面也能看到立体模型,但底部锚点卡仍显示“尚未创建”。原生日志中的锚点状态和距离是正确的,问题出在 ArkUI 自定义 Builder。

首版模型已锚定但底部状态未刷新

错误写法把动态值作为 Builder 参数传入:

this.evidenceRow('锚点状态', this.guideTrackingText())

修改后只传固定标签,在 Builder 内直接读取 @State

this.evidenceRow('锚点状态')

@Builder
private evidenceRow(label: string): void {
  Row() {
    Text(label)
    Text(this.evidenceValue(label))
  }
}

修复后的待放置、命中失败和按钮状态均能随快照变化。

情况三:点击放置后命中结果为 0

地面看起来平整,不代表 AR Engine 已经建立可命中的平面。重新进入会话后立即点击,原生返回:

BOOK_GUIDE_PLACE placed=0 hitStatus=-2001 hitCount=0 anchorTracking=-1 distance=0.0000 center=0.0000,0.0000,0.0000

页面按失败分支显示“这次没有命中地面”,不创建锚点,也不显示模型。

中心未命中地面

处理动作只有两个:继续缓慢移动手机,让画面看到更多地面纹理;再让十字落在无遮挡区域重新放置。不能在 hitCount=0 时直接生成一个假锚点。

构建与验证结果

静态回归脚本检查以下内容:

  • TARGET 会话保留水平与垂直平面检测;
  • 自动对焦已经设置并回读;
  • PAUSED、STOPPED、Acquire 错误和状态错误均有统计;
  • HitTest、水平向上平面、锚点、盒子渲染和释放接口均存在;
  • 开口盒子的外框、墙高、内部书籍框和 OPEN_BOX_GUIDE 日志标识均存在;
  • 人工确认日志固定包含 manual=true
  • ArkTS 页面不会用人工确认覆盖官方 TARGET 结果。

回归结果:

物体语义状态观测回归检查通过。

最终执行 clean 签名构建:

hvigorw clean assembleHap --no-daemon

构建结果:

BuildNativeWithCmake  SUCCESS
BuildNativeWithNinja SUCCESS
CompileArkTS         SUCCESS
PackageHap           SUCCESS
SignHap              SUCCESS
BUILD SUCCESSFUL

本次结果

这次真机实验得到的结果如下:

验证项真机结果
TARGET 配置成功,semanticMode=2
官方形状分类:单独扫描实体书成功,返回 RECTANGLE
目标几何成功,约 0.222 × 0.298 m,半径约 0.186 m
地面开口盒子成功,28 × 21 × 6 cm,命中距离 0.7255 m,锚点 TRACKING
实体书放入盒子成功,真机画面可见书位于四面侧壁内部
摆放确认成功,第 6946 帧记录,manual=true
官方形状分类:书与盒子组合返回 CUBE,AABB 0.2081 × 0.0281 × 0.2726 m

自动分类与人工摆放确认是两条独立证据。单独扫描书籍得到 RECTANGLE,放入盒子后的组合外形得到 CUBE;人工确认不会决定或修改这两个枚举结果。目标在部分帧会从 TRACKING 回到 PAUSED,因此页面保留最后一次有效自动分类结果,实时 TARGET 计数仍继续更新。

退出页面时先 detach 并 release 书籍锚点,再停止 Session,销毁 Frame、两个 OpenGL Program、相机纹理、EGL Surface、EGL Context 和 Native XComponent 实例,避免相机与原生资源留在后台。

官方资料

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/ldc121xy716/article/details/164069093

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--